• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/ui/app_modal_dialogs/js_modal_dialog.h"
6 
7 #include "base/string_util.h"
8 #include "base/utf_string_conversions.h"
9 #include "chrome/browser/browser_shutdown.h"
10 #include "chrome/browser/extensions/extension_host.h"
11 #include "chrome/browser/ui/app_modal_dialogs/native_app_modal_dialog.h"
12 #include "content/browser/tab_contents/tab_contents.h"
13 #include "content/common/notification_service.h"
14 #include "content/common/notification_type.h"
15 #include "ui/base/text/text_elider.h"
16 
17 namespace {
18 
19 // Control maximum sizes of various texts passed to us from javascript.
20 #ifdef OS_LINUX
21 // Two-dimensional eliding.  Reformat the text of the message dialog
22 // inserting line breaks because otherwise a single long line can overflow
23 // the message dialog (and crash/hang the GTK, depending on the version).
24 const int kMessageTextMaxRows = 32;
25 const int kMessageTextMaxCols = 132;
26 const int kDefaultPromptMaxRows = 24;
27 const int kDefaultPromptMaxCols = 132;
EnforceMaxTextSize(const string16 & in_string,string16 * out_string)28 void EnforceMaxTextSize(const string16& in_string, string16* out_string) {
29   ui::ElideRectangleString(in_string, kMessageTextMaxRows,
30                            kMessageTextMaxCols, false, out_string);
31 }
EnforceMaxPromptSize(const string16 & in_string,string16 * out_string)32 void EnforceMaxPromptSize(const string16& in_string, string16* out_string) {
33   ui::ElideRectangleString(in_string, kDefaultPromptMaxRows,
34                            kDefaultPromptMaxCols, false, out_string);
35 }
36 #else
37 // One-dimensional eliding.  Trust the window system to break the string
38 // appropriately, but limit its overall length to something reasonable.
39 const int kMessageTextMaxSize = 3000;
40 const int kDefaultPromptMaxSize = 2000;
41 void EnforceMaxTextSize(const string16& in_string, string16* out_string) {
42   ui::ElideString(in_string, kMessageTextMaxSize, out_string);
43 }
44 void EnforceMaxPromptSize(const string16& in_string, string16* out_string) {
45   ui::ElideString(in_string, kDefaultPromptMaxSize, out_string);
46 }
47 #endif
48 
49 }  // namespace
50 
JavaScriptAppModalDialog(JavaScriptAppModalDialogDelegate * delegate,const std::wstring & title,int dialog_flags,const std::wstring & message_text,const std::wstring & default_prompt_text,bool display_suppress_checkbox,bool is_before_unload_dialog,IPC::Message * reply_msg)51 JavaScriptAppModalDialog::JavaScriptAppModalDialog(
52     JavaScriptAppModalDialogDelegate* delegate,
53     const std::wstring& title,
54     int dialog_flags,
55     const std::wstring& message_text,
56     const std::wstring& default_prompt_text,
57     bool display_suppress_checkbox,
58     bool is_before_unload_dialog,
59     IPC::Message* reply_msg)
60     : AppModalDialog(delegate->AsTabContents(), title),
61       delegate_(delegate),
62       extension_host_(delegate->AsExtensionHost()),
63       dialog_flags_(dialog_flags),
64       display_suppress_checkbox_(display_suppress_checkbox),
65       is_before_unload_dialog_(is_before_unload_dialog),
66       reply_msg_(reply_msg) {
67   string16 elided_text;
68   EnforceMaxTextSize(WideToUTF16(message_text), &elided_text);
69   message_text_ = UTF16ToWide(elided_text);
70   EnforceMaxPromptSize(WideToUTF16Hack(default_prompt_text),
71                        &default_prompt_text_);
72 
73   DCHECK((tab_contents_ != NULL) != (extension_host_ != NULL));
74   InitNotifications();
75 }
76 
~JavaScriptAppModalDialog()77 JavaScriptAppModalDialog::~JavaScriptAppModalDialog() {
78 }
79 
CreateNativeDialog()80 NativeAppModalDialog* JavaScriptAppModalDialog::CreateNativeDialog() {
81   gfx::NativeWindow parent_window = tab_contents_ ?
82       tab_contents_->GetMessageBoxRootWindow() :
83       extension_host_->GetMessageBoxRootWindow();
84   return NativeAppModalDialog::CreateNativeJavaScriptPrompt(this,
85                                                             parent_window);
86 }
87 
Observe(NotificationType type,const NotificationSource & source,const NotificationDetails & details)88 void JavaScriptAppModalDialog::Observe(NotificationType type,
89                                        const NotificationSource& source,
90                                        const NotificationDetails& details) {
91   if (skip_this_dialog_)
92     return;
93 
94   if (NotificationType::EXTENSION_HOST_DESTROYED == type &&
95       Details<ExtensionHost>(extension_host_) != details)
96     return;
97 
98   // If we reach here, we know the notification is relevant to us, either
99   // because we're only observing applicable sources or because we passed the
100   // check above. Both of those indicate that we should ignore this dialog.
101   // Also clear the delegate, since it's now invalid.
102   skip_this_dialog_ = true;
103   delegate_ = NULL;
104   if (native_dialog_)
105     CloseModalDialog();
106 }
107 
InitNotifications()108 void JavaScriptAppModalDialog::InitNotifications() {
109   // Make sure we get relevant navigation notifications so we know when our
110   // parent contents will disappear or navigate to a different page.
111   if (tab_contents_) {
112     registrar_.Add(this, NotificationType::NAV_ENTRY_COMMITTED,
113                    Source<NavigationController>(&tab_contents_->controller()));
114     registrar_.Add(this, NotificationType::TAB_CONTENTS_DESTROYED,
115                    Source<TabContents>(tab_contents_));
116   } else if (extension_host_) {
117     // EXTENSION_HOST_DESTROYED uses the Profile as its source, but we care
118     // about the ExtensionHost (which is passed in the details).
119     registrar_.Add(this, NotificationType::EXTENSION_HOST_DESTROYED,
120                    NotificationService::AllSources());
121   } else {
122     NOTREACHED();
123   }
124 }
125 
OnCancel(bool suppress_js_messages)126 void JavaScriptAppModalDialog::OnCancel(bool suppress_js_messages) {
127   // If we are shutting down and this is an onbeforeunload dialog, cancel the
128   // shutdown.
129   if (is_before_unload_dialog_)
130     browser_shutdown::SetTryingToQuit(false);
131 
132   // We need to do this before WM_DESTROY (WindowClosing()) as any parent frame
133   // will receive its activation messages before this dialog receives
134   // WM_DESTROY. The parent frame would then try to activate any modal dialogs
135   // that were still open in the ModalDialogQueue, which would send activation
136   // back to this one. The framework should be improved to handle this, so this
137   // is a temporary workaround.
138   CompleteDialog();
139 
140   NotifyDelegate(false, L"", suppress_js_messages);
141 }
142 
OnAccept(const std::wstring & prompt_text,bool suppress_js_messages)143 void JavaScriptAppModalDialog::OnAccept(const std::wstring& prompt_text,
144                                         bool suppress_js_messages) {
145   CompleteDialog();
146   NotifyDelegate(true, prompt_text, suppress_js_messages);
147 }
148 
OnClose()149 void JavaScriptAppModalDialog::OnClose() {
150   NotifyDelegate(false, L"", false);
151 }
152 
NotifyDelegate(bool success,const std::wstring & prompt_text,bool suppress_js_messages)153 void JavaScriptAppModalDialog::NotifyDelegate(bool success,
154                                               const std::wstring& prompt_text,
155                                               bool suppress_js_messages) {
156   if (skip_this_dialog_)
157     return;
158 
159   delegate_->OnMessageBoxClosed(reply_msg_, success, prompt_text);
160   if (suppress_js_messages)
161     delegate_->SetSuppressMessageBoxes(true);
162 
163   // On Views, we can end up coming through this code path twice :(.
164   // See crbug.com/63732.
165   skip_this_dialog_ = true;
166 }
167