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