Home | History | Annotate | Download | only in app_modal_dialogs
      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/ui/app_modal_dialogs/javascript_app_modal_dialog.h"
      6 
      7 #include "chrome/browser/browser_shutdown.h"
      8 #include "chrome/browser/ui/app_modal_dialogs/native_app_modal_dialog.h"
      9 #include "content/public/browser/web_contents.h"
     10 #include "content/public/browser/web_contents_view.h"
     11 #include "ui/base/text/text_elider.h"
     12 
     13 #if defined(USE_AURA)
     14 #include "ui/aura/root_window.h"
     15 #endif
     16 
     17 using content::JavaScriptDialogManager;
     18 using content::WebContents;
     19 
     20 namespace {
     21 
     22 // Control maximum sizes of various texts passed to us from javascript.
     23 #if defined(OS_POSIX) && !defined(OS_MACOSX)
     24 // Two-dimensional eliding.  Reformat the text of the message dialog
     25 // inserting line breaks because otherwise a single long line can overflow
     26 // the message dialog (and crash/hang the GTK, depending on the version).
     27 const int kMessageTextMaxRows = 32;
     28 const int kMessageTextMaxCols = 132;
     29 const int kDefaultPromptMaxRows = 24;
     30 const int kDefaultPromptMaxCols = 132;
     31 void EnforceMaxTextSize(const string16& in_string, string16* out_string) {
     32   ui::ElideRectangleString(in_string, kMessageTextMaxRows,
     33                            kMessageTextMaxCols, false, out_string);
     34 }
     35 void EnforceMaxPromptSize(const string16& in_string, string16* out_string) {
     36   ui::ElideRectangleString(in_string, kDefaultPromptMaxRows,
     37                            kDefaultPromptMaxCols, false, out_string);
     38 }
     39 #else
     40 // One-dimensional eliding.  Trust the window system to break the string
     41 // appropriately, but limit its overall length to something reasonable.
     42 const int kMessageTextMaxSize = 3000;
     43 const int kDefaultPromptMaxSize = 2000;
     44 void EnforceMaxTextSize(const string16& in_string, string16* out_string) {
     45   ui::ElideString(in_string, kMessageTextMaxSize, out_string);
     46 }
     47 void EnforceMaxPromptSize(const string16& in_string, string16* out_string) {
     48   ui::ElideString(in_string, kDefaultPromptMaxSize, out_string);
     49 }
     50 #endif
     51 
     52 }  // namespace
     53 
     54 ChromeJavaScriptDialogExtraData::ChromeJavaScriptDialogExtraData()
     55     : suppress_javascript_messages_(false) {
     56 }
     57 
     58 JavaScriptAppModalDialog::JavaScriptAppModalDialog(
     59     WebContents* web_contents,
     60     ExtraDataMap* extra_data_map,
     61     const string16& title,
     62     content::JavaScriptMessageType javascript_message_type,
     63     const string16& message_text,
     64     const string16& default_prompt_text,
     65     bool display_suppress_checkbox,
     66     bool is_before_unload_dialog,
     67     bool is_reload,
     68     const JavaScriptDialogManager::DialogClosedCallback& callback)
     69     : AppModalDialog(web_contents, title),
     70       extra_data_map_(extra_data_map),
     71       javascript_message_type_(javascript_message_type),
     72       display_suppress_checkbox_(display_suppress_checkbox),
     73       is_before_unload_dialog_(is_before_unload_dialog),
     74       is_reload_(is_reload),
     75       callback_(callback),
     76       use_override_prompt_text_(false) {
     77   EnforceMaxTextSize(message_text, &message_text_);
     78   EnforceMaxPromptSize(default_prompt_text, &default_prompt_text_);
     79 }
     80 
     81 JavaScriptAppModalDialog::~JavaScriptAppModalDialog() {
     82 }
     83 
     84 NativeAppModalDialog* JavaScriptAppModalDialog::CreateNativeDialog() {
     85   gfx::NativeWindow parent_window =
     86       web_contents()->GetView()->GetTopLevelNativeWindow();
     87 
     88 #if defined(USE_AURA)
     89   if (!parent_window->GetRootWindow()) {
     90     // When we are part of a WebContents that isn't actually being displayed on
     91     // the screen, we can't actually attach to it.
     92     parent_window = NULL;
     93   }
     94 #endif  // defined(USE_AURA)
     95 
     96   return NativeAppModalDialog::CreateNativeJavaScriptPrompt(this,
     97                                                             parent_window);
     98 }
     99 
    100 bool JavaScriptAppModalDialog::IsJavaScriptModalDialog() {
    101   return true;
    102 }
    103 
    104 void JavaScriptAppModalDialog::Invalidate() {
    105   if (!IsValid())
    106     return;
    107 
    108   AppModalDialog::Invalidate();
    109   callback_.Reset();
    110   if (native_dialog())
    111     CloseModalDialog();
    112 }
    113 
    114 void JavaScriptAppModalDialog::OnCancel(bool suppress_js_messages) {
    115   // If we are shutting down and this is an onbeforeunload dialog, cancel the
    116   // shutdown.
    117   if (is_before_unload_dialog_)
    118     browser_shutdown::SetTryingToQuit(false);
    119 
    120   // We need to do this before WM_DESTROY (WindowClosing()) as any parent frame
    121   // will receive its activation messages before this dialog receives
    122   // WM_DESTROY. The parent frame would then try to activate any modal dialogs
    123   // that were still open in the ModalDialogQueue, which would send activation
    124   // back to this one. The framework should be improved to handle this, so this
    125   // is a temporary workaround.
    126   CompleteDialog();
    127 
    128   NotifyDelegate(false, string16(), suppress_js_messages);
    129 }
    130 
    131 void JavaScriptAppModalDialog::OnAccept(const string16& prompt_text,
    132                                         bool suppress_js_messages) {
    133   string16 prompt_text_to_use = prompt_text;
    134   // This is only for testing.
    135   if (use_override_prompt_text_)
    136     prompt_text_to_use = override_prompt_text_;
    137 
    138   CompleteDialog();
    139   NotifyDelegate(true, prompt_text_to_use, suppress_js_messages);
    140 }
    141 
    142 void JavaScriptAppModalDialog::OnClose() {
    143   NotifyDelegate(false, string16(), false);
    144 }
    145 
    146 void JavaScriptAppModalDialog::SetOverridePromptText(
    147     const string16& override_prompt_text) {
    148   override_prompt_text_ = override_prompt_text;
    149   use_override_prompt_text_ = true;
    150 }
    151 
    152 void JavaScriptAppModalDialog::NotifyDelegate(bool success,
    153                                               const string16& user_input,
    154                                               bool suppress_js_messages) {
    155   if (!IsValid())
    156     return;
    157 
    158   callback_.Run(success, user_input);
    159 
    160   // The callback_ above may delete web_contents_, thus removing the extra
    161   // data from the map owned by ChromeJavaScriptDialogManager. Make sure
    162   // to only use the data if still present. http://crbug.com/236476
    163   ExtraDataMap::iterator extra_data = extra_data_map_->find(web_contents());
    164   if (extra_data != extra_data_map_->end()) {
    165     extra_data->second.last_javascript_message_dismissal_ =
    166         base::TimeTicks::Now();
    167     extra_data->second.suppress_javascript_messages_ = suppress_js_messages;
    168   }
    169 
    170   // On Views, we can end up coming through this code path twice :(.
    171   // See crbug.com/63732.
    172   AppModalDialog::Invalidate();
    173 }
    174