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