Avi Drissman | 8ba1bad | 2022-09-13 19:22:36 | [diff] [blame] | 1 | // Copyright 2012 The Chromium Authors |
[email protected] | 12f74a9 | 2010-02-05 22:32:14 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
Evan Stade | 7220e47 | 2020-01-31 17:06:57 | [diff] [blame] | 5 | #include "components/javascript_dialogs/app_modal_dialog_controller.h" |
[email protected] | 12f74a9 | 2010-02-05 22:32:14 | [diff] [blame] | 6 | |
Avi Drissman | e04d399 | 2017-10-05 15:11:36 | [diff] [blame] | 7 | #include <utility> |
| 8 | |
avi | bc5337b | 2015-12-25 23:16:33 | [diff] [blame] | 9 | #include "build/build_config.h" |
Evan Stade | 7220e47 | 2020-01-31 17:06:57 | [diff] [blame] | 10 | #include "components/javascript_dialogs/app_modal_dialog_manager.h" |
| 11 | #include "components/javascript_dialogs/app_modal_dialog_queue.h" |
| 12 | #include "components/javascript_dialogs/app_modal_dialog_view.h" |
[email protected] | dbb97ba | 2013-09-09 22:15:25 | [diff] [blame] | 13 | #include "ui/gfx/text_elider.h" |
[email protected] | 51da7e3 | 2012-01-30 19:24:52 | [diff] [blame] | 14 | |
Evan Stade | 7220e47 | 2020-01-31 17:06:57 | [diff] [blame] | 15 | namespace javascript_dialogs { |
[email protected] | 999adfd6 | 2010-06-02 19:42:42 | [diff] [blame] | 16 | namespace { |
| 17 | |
avi | 373e72a | 2017-05-26 20:33:52 | [diff] [blame] | 18 | AppModalDialogObserver* app_modal_dialog_observer = nullptr; |
| 19 | |
[email protected] | 416126c5 | 2011-03-29 16:28:57 | [diff] [blame] | 20 | // Control maximum sizes of various texts passed to us from javascript. |
Xiaohan Wang | bca91f9 | 2022-01-15 19:56:21 | [diff] [blame] | 21 | #if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_APPLE) |
[email protected] | 416126c5 | 2011-03-29 16:28:57 | [diff] [blame] | 22 | // Two-dimensional eliding. Reformat the text of the message dialog |
| 23 | // inserting line breaks because otherwise a single long line can overflow |
| 24 | // the message dialog (and crash/hang the GTK, depending on the version). |
[email protected] | af4b9df | 2010-12-22 21:19:02 | [diff] [blame] | 25 | const int kMessageTextMaxRows = 32; |
| 26 | const int kMessageTextMaxCols = 132; |
[email protected] | 416126c5 | 2011-03-29 16:28:57 | [diff] [blame] | 27 | const int kDefaultPromptMaxRows = 24; |
| 28 | const int kDefaultPromptMaxCols = 132; |
Elly Fong-Jones | 7337f0cf | 2019-12-05 21:51:42 | [diff] [blame] | 29 | |
Jan Wilken Dörrie | fa241ba | 2021-03-11 17:57:01 | [diff] [blame] | 30 | std::u16string EnforceMaxTextSize(const std::u16string& in_string) { |
| 31 | std::u16string out_string; |
Elly Fong-Jones | 7337f0cf | 2019-12-05 21:51:42 | [diff] [blame] | 32 | gfx::ElideRectangleString(in_string, kMessageTextMaxRows, kMessageTextMaxCols, |
| 33 | false, &out_string); |
| 34 | return out_string; |
[email protected] | 416126c5 | 2011-03-29 16:28:57 | [diff] [blame] | 35 | } |
Elly Fong-Jones | 7337f0cf | 2019-12-05 21:51:42 | [diff] [blame] | 36 | |
Jan Wilken Dörrie | fa241ba | 2021-03-11 17:57:01 | [diff] [blame] | 37 | std::u16string EnforceMaxPromptSize(const std::u16string& in_string) { |
| 38 | std::u16string out_string; |
[email protected] | dbb97ba | 2013-09-09 22:15:25 | [diff] [blame] | 39 | gfx::ElideRectangleString(in_string, kDefaultPromptMaxRows, |
Elly Fong-Jones | 7337f0cf | 2019-12-05 21:51:42 | [diff] [blame] | 40 | kDefaultPromptMaxCols, false, &out_string); |
| 41 | return out_string; |
[email protected] | 416126c5 | 2011-03-29 16:28:57 | [diff] [blame] | 42 | } |
Elly Fong-Jones | 7337f0cf | 2019-12-05 21:51:42 | [diff] [blame] | 43 | |
[email protected] | 416126c5 | 2011-03-29 16:28:57 | [diff] [blame] | 44 | #else |
| 45 | // One-dimensional eliding. Trust the window system to break the string |
| 46 | // appropriately, but limit its overall length to something reasonable. |
thestig | bbf93ac | 2016-02-02 00:24:49 | [diff] [blame] | 47 | const size_t kMessageTextMaxSize = 2000; |
| 48 | const size_t kDefaultPromptMaxSize = 2000; |
Elly Fong-Jones | 7337f0cf | 2019-12-05 21:51:42 | [diff] [blame] | 49 | |
Jan Wilken Dörrie | fa241ba | 2021-03-11 17:57:01 | [diff] [blame] | 50 | std::u16string EnforceMaxTextSize(const std::u16string& in_string) { |
| 51 | std::u16string out_string; |
Elly Fong-Jones | 7337f0cf | 2019-12-05 21:51:42 | [diff] [blame] | 52 | gfx::ElideString(in_string, kMessageTextMaxSize, &out_string); |
| 53 | return out_string; |
[email protected] | 416126c5 | 2011-03-29 16:28:57 | [diff] [blame] | 54 | } |
Elly Fong-Jones | 7337f0cf | 2019-12-05 21:51:42 | [diff] [blame] | 55 | |
Jan Wilken Dörrie | fa241ba | 2021-03-11 17:57:01 | [diff] [blame] | 56 | std::u16string EnforceMaxPromptSize(const std::u16string& in_string) { |
| 57 | std::u16string out_string; |
Elly Fong-Jones | 7337f0cf | 2019-12-05 21:51:42 | [diff] [blame] | 58 | gfx::ElideString(in_string, kDefaultPromptMaxSize, &out_string); |
| 59 | return out_string; |
[email protected] | 416126c5 | 2011-03-29 16:28:57 | [diff] [blame] | 60 | } |
| 61 | #endif |
[email protected] | 999adfd6 | 2010-06-02 19:42:42 | [diff] [blame] | 62 | |
| 63 | } // namespace |
| 64 | |
[email protected] | 3ab9cb8 | 2011-06-03 18:02:07 | [diff] [blame] | 65 | ChromeJavaScriptDialogExtraData::ChromeJavaScriptDialogExtraData() |
palmer | d8b2ff0 | 2015-08-18 00:24:59 | [diff] [blame] | 66 | : has_already_shown_a_dialog_(false), |
Joe Mason | db32d7f0 | 2019-07-19 00:14:22 | [diff] [blame] | 67 | suppress_javascript_messages_(false) {} |
[email protected] | 3ab9cb8 | 2011-06-03 18:02:07 | [diff] [blame] | 68 | |
Evan Stade | 7220e47 | 2020-01-31 17:06:57 | [diff] [blame] | 69 | AppModalDialogController::AppModalDialogController( |
jochen | a2afdec | 2015-01-23 13:09:22 | [diff] [blame] | 70 | content::WebContents* web_contents, |
[email protected] | 1f422a7c | 2013-05-15 17:06:41 | [diff] [blame] | 71 | ExtraDataMap* extra_data_map, |
Jan Wilken Dörrie | fa241ba | 2021-03-11 17:57:01 | [diff] [blame] | 72 | const std::u16string& title, |
avi | 777ff45 | 2017-02-09 19:04:48 | [diff] [blame] | 73 | content::JavaScriptDialogType javascript_dialog_type, |
Jan Wilken Dörrie | fa241ba | 2021-03-11 17:57:01 | [diff] [blame] | 74 | const std::u16string& message_text, |
| 75 | const std::u16string& default_prompt_text, |
[email protected] | 12f74a9 | 2010-02-05 22:32:14 | [diff] [blame] | 76 | bool display_suppress_checkbox, |
Morten Stenshorne | 29ee805 | 2021-08-12 11:06:34 | [diff] [blame] | 77 | bool is_before_unload_dialog, |
| 78 | bool is_reload, |
Avi Drissman | e04d399 | 2017-10-05 15:11:36 | [diff] [blame] | 79 | content::JavaScriptDialogManager::DialogClosedCallback callback) |
Dave Tapuska | 3b48e9d | 2024-12-03 19:12:57 | [diff] [blame] | 80 | : content::WebContentsObserver(web_contents), |
| 81 | title_(title), |
[email protected] | 1f422a7c | 2013-05-15 17:06:41 | [diff] [blame] | 82 | extra_data_map_(extra_data_map), |
avi | 777ff45 | 2017-02-09 19:04:48 | [diff] [blame] | 83 | javascript_dialog_type_(javascript_dialog_type), |
Elly Fong-Jones | 7337f0cf | 2019-12-05 21:51:42 | [diff] [blame] | 84 | message_text_(EnforceMaxTextSize(message_text)), |
| 85 | default_prompt_text_(EnforceMaxPromptSize(default_prompt_text)), |
[email protected] | 12f74a9 | 2010-02-05 22:32:14 | [diff] [blame] | 86 | display_suppress_checkbox_(display_suppress_checkbox), |
Morten Stenshorne | 29ee805 | 2021-08-12 11:06:34 | [diff] [blame] | 87 | is_before_unload_dialog_(is_before_unload_dialog), |
| 88 | is_reload_(is_reload), |
Avi Drissman | e04d399 | 2017-10-05 15:11:36 | [diff] [blame] | 89 | callback_(std::move(callback)), |
Elly Fong-Jones | 7337f0cf | 2019-12-05 21:51:42 | [diff] [blame] | 90 | use_override_prompt_text_(false) {} |
[email protected] | 12f74a9 | 2010-02-05 22:32:14 | [diff] [blame] | 91 | |
Evan Stade | 7220e47 | 2020-01-31 17:06:57 | [diff] [blame] | 92 | AppModalDialogController::~AppModalDialogController() { |
avi | 373e72a | 2017-05-26 20:33:52 | [diff] [blame] | 93 | CompleteDialog(); |
[email protected] | 12f74a9 | 2010-02-05 22:32:14 | [diff] [blame] | 94 | } |
| 95 | |
Evan Stade | 7220e47 | 2020-01-31 17:06:57 | [diff] [blame] | 96 | void AppModalDialogController::ShowModalDialog() { |
| 97 | view_ = AppModalDialogManager::GetInstance()->view_factory()->Run(this); |
| 98 | view_->ShowAppModalDialog(); |
avi | 373e72a | 2017-05-26 20:33:52 | [diff] [blame] | 99 | if (app_modal_dialog_observer) |
| 100 | app_modal_dialog_observer->Notify(this); |
[email protected] | 160ad3d | 2010-09-28 15:40:20 | [diff] [blame] | 101 | } |
| 102 | |
Evan Stade | 7220e47 | 2020-01-31 17:06:57 | [diff] [blame] | 103 | void AppModalDialogController::ActivateModalDialog() { |
| 104 | DCHECK(view_); |
| 105 | view_->ActivateAppModalDialog(); |
avi | 373e72a | 2017-05-26 20:33:52 | [diff] [blame] | 106 | } |
| 107 | |
Evan Stade | 7220e47 | 2020-01-31 17:06:57 | [diff] [blame] | 108 | void AppModalDialogController::CloseModalDialog() { |
| 109 | DCHECK(view_); |
| 110 | view_->CloseAppModalDialog(); |
avi | 373e72a | 2017-05-26 20:33:52 | [diff] [blame] | 111 | } |
| 112 | |
Evan Stade | 7220e47 | 2020-01-31 17:06:57 | [diff] [blame] | 113 | void AppModalDialogController::CompleteDialog() { |
Evan Stade | 44d6317 | 2020-07-16 23:01:44 | [diff] [blame] | 114 | // If |view_| is non-null, then |this| is the active dialog and the next one |
| 115 | // should be shown. Otherwise, |this| was never shown. |
| 116 | if (view_) { |
| 117 | view_ = nullptr; |
avi | 373e72a | 2017-05-26 20:33:52 | [diff] [blame] | 118 | AppModalDialogQueue::GetInstance()->ShowNextDialog(); |
Evan Stade | 44d6317 | 2020-07-16 23:01:44 | [diff] [blame] | 119 | } else { |
| 120 | DCHECK(!valid_); |
avi | 373e72a | 2017-05-26 20:33:52 | [diff] [blame] | 121 | } |
| 122 | } |
| 123 | |
Evan Stade | 7220e47 | 2020-01-31 17:06:57 | [diff] [blame] | 124 | bool AppModalDialogController::IsValid() { |
avi | 373e72a | 2017-05-26 20:33:52 | [diff] [blame] | 125 | return valid_; |
[email protected] | 1662374 | 2011-05-16 20:04:26 | [diff] [blame] | 126 | } |
| 127 | |
Evan Stade | 7220e47 | 2020-01-31 17:06:57 | [diff] [blame] | 128 | void AppModalDialogController::Invalidate() { |
avi | 373e72a | 2017-05-26 20:33:52 | [diff] [blame] | 129 | if (!valid_) |
[email protected] | 12f74a9 | 2010-02-05 22:32:14 | [diff] [blame] | 130 | return; |
| 131 | |
avi | 373e72a | 2017-05-26 20:33:52 | [diff] [blame] | 132 | valid_ = false; |
Jan Wilken Dörrie | fa241ba | 2021-03-11 17:57:01 | [diff] [blame] | 133 | CallDialogClosedCallback(false, std::u16string()); |
Evan Stade | 7220e47 | 2020-01-31 17:06:57 | [diff] [blame] | 134 | if (view_) |
[email protected] | 66711f6f | 2010-06-23 01:17:35 | [diff] [blame] | 135 | CloseModalDialog(); |
[email protected] | 12f74a9 | 2010-02-05 22:32:14 | [diff] [blame] | 136 | } |
| 137 | |
Evan Stade | 7220e47 | 2020-01-31 17:06:57 | [diff] [blame] | 138 | void AppModalDialogController::OnCancel(bool suppress_js_messages) { |
[email protected] | 12f74a9 | 2010-02-05 22:32:14 | [diff] [blame] | 139 | // We need to do this before WM_DESTROY (WindowClosing()) as any parent frame |
| 140 | // will receive its activation messages before this dialog receives |
| 141 | // WM_DESTROY. The parent frame would then try to activate any modal dialogs |
| 142 | // that were still open in the ModalDialogQueue, which would send activation |
| 143 | // back to this one. The framework should be improved to handle this, so this |
| 144 | // is a temporary workaround. |
| 145 | CompleteDialog(); |
| 146 | |
Jan Wilken Dörrie | fa241ba | 2021-03-11 17:57:01 | [diff] [blame] | 147 | NotifyDelegate(false, std::u16string(), suppress_js_messages); |
[email protected] | 12f74a9 | 2010-02-05 22:32:14 | [diff] [blame] | 148 | } |
| 149 | |
Jan Wilken Dörrie | fa241ba | 2021-03-11 17:57:01 | [diff] [blame] | 150 | void AppModalDialogController::OnAccept(const std::u16string& prompt_text, |
[email protected] | 12f74a9 | 2010-02-05 22:32:14 | [diff] [blame] | 151 | bool suppress_js_messages) { |
Jan Wilken Dörrie | fa241ba | 2021-03-11 17:57:01 | [diff] [blame] | 152 | std::u16string prompt_text_to_use = prompt_text; |
[email protected] | 1662374 | 2011-05-16 20:04:26 | [diff] [blame] | 153 | // This is only for testing. |
| 154 | if (use_override_prompt_text_) |
[email protected] | 3ab9cb8 | 2011-06-03 18:02:07 | [diff] [blame] | 155 | prompt_text_to_use = override_prompt_text_; |
[email protected] | 1662374 | 2011-05-16 20:04:26 | [diff] [blame] | 156 | |
[email protected] | 12f74a9 | 2010-02-05 22:32:14 | [diff] [blame] | 157 | CompleteDialog(); |
[email protected] | 1662374 | 2011-05-16 20:04:26 | [diff] [blame] | 158 | NotifyDelegate(true, prompt_text_to_use, suppress_js_messages); |
[email protected] | 12f74a9 | 2010-02-05 22:32:14 | [diff] [blame] | 159 | } |
[email protected] | 7d78430 | 2010-04-09 21:41:05 | [diff] [blame] | 160 | |
Evan Stade | 7220e47 | 2020-01-31 17:06:57 | [diff] [blame] | 161 | void AppModalDialogController::OnClose() { |
Jan Wilken Dörrie | fa241ba | 2021-03-11 17:57:01 | [diff] [blame] | 162 | NotifyDelegate(false, std::u16string(), false); |
[email protected] | 7d78430 | 2010-04-09 21:41:05 | [diff] [blame] | 163 | } |
| 164 | |
Evan Stade | 7220e47 | 2020-01-31 17:06:57 | [diff] [blame] | 165 | void AppModalDialogController::SetOverridePromptText( |
Jan Wilken Dörrie | fa241ba | 2021-03-11 17:57:01 | [diff] [blame] | 166 | const std::u16string& override_prompt_text) { |
[email protected] | 1662374 | 2011-05-16 20:04:26 | [diff] [blame] | 167 | override_prompt_text_ = override_prompt_text; |
| 168 | use_override_prompt_text_ = true; |
| 169 | } |
| 170 | |
Dave Tapuska | 3b48e9d | 2024-12-03 19:12:57 | [diff] [blame] | 171 | void AppModalDialogController::WebContentsDestroyed() { |
| 172 | Invalidate(); |
| 173 | } |
| 174 | |
Evan Stade | 7220e47 | 2020-01-31 17:06:57 | [diff] [blame] | 175 | void AppModalDialogController::NotifyDelegate(bool success, |
Jan Wilken Dörrie | fa241ba | 2021-03-11 17:57:01 | [diff] [blame] | 176 | const std::u16string& user_input, |
[email protected] | 594d062 | 2010-12-07 05:33:07 | [diff] [blame] | 177 | bool suppress_js_messages) { |
avi | 373e72a | 2017-05-26 20:33:52 | [diff] [blame] | 178 | if (!valid_) |
[email protected] | 594d062 | 2010-12-07 05:33:07 | [diff] [blame] | 179 | return; |
| 180 | |
joenotcharles | 850904a | 2016-02-09 01:50:44 | [diff] [blame] | 181 | CallDialogClosedCallback(success, user_input); |
[email protected] | 3ab9cb8 | 2011-06-03 18:02:07 | [diff] [blame] | 182 | |
joenotcharles | 850904a | 2016-02-09 01:50:44 | [diff] [blame] | 183 | // The close callback above may delete web_contents_, thus removing the extra |
Evan Stade | 7220e47 | 2020-01-31 17:06:57 | [diff] [blame] | 184 | // data from the map owned by ::AppModalDialogManager. Make sure |
[email protected] | 1f422a7c | 2013-05-15 17:06:41 | [diff] [blame] | 185 | // to only use the data if still present. http://crbug.com/236476 |
Dave Tapuska | 3b48e9d | 2024-12-03 19:12:57 | [diff] [blame] | 186 | if (auto* contents = web_contents()) { |
| 187 | auto extra_data = extra_data_map_->find(contents); |
| 188 | if (extra_data != extra_data_map_->end()) { |
| 189 | extra_data->second.has_already_shown_a_dialog_ = true; |
| 190 | extra_data->second.suppress_javascript_messages_ = suppress_js_messages; |
| 191 | } |
[email protected] | 1f422a7c | 2013-05-15 17:06:41 | [diff] [blame] | 192 | } |
[email protected] | 594d062 | 2010-12-07 05:33:07 | [diff] [blame] | 193 | |
| 194 | // On Views, we can end up coming through this code path twice :(. |
| 195 | // See crbug.com/63732. |
avi | 373e72a | 2017-05-26 20:33:52 | [diff] [blame] | 196 | valid_ = false; |
[email protected] | 7d78430 | 2010-04-09 21:41:05 | [diff] [blame] | 197 | } |
oshima | 0929be2a | 2014-11-19 22:21:03 | [diff] [blame] | 198 | |
Evan Stade | 7220e47 | 2020-01-31 17:06:57 | [diff] [blame] | 199 | void AppModalDialogController::CallDialogClosedCallback( |
| 200 | bool success, |
Jan Wilken Dörrie | fa241ba | 2021-03-11 17:57:01 | [diff] [blame] | 201 | const std::u16string& user_input) { |
Avi Drissman | e04d399 | 2017-10-05 15:11:36 | [diff] [blame] | 202 | if (!callback_.is_null()) |
| 203 | std::move(callback_).Run(success, user_input); |
joenotcharles | 850904a | 2016-02-09 01:50:44 | [diff] [blame] | 204 | } |
| 205 | |
avi | 373e72a | 2017-05-26 20:33:52 | [diff] [blame] | 206 | AppModalDialogObserver::AppModalDialogObserver() { |
| 207 | DCHECK(!app_modal_dialog_observer); |
| 208 | app_modal_dialog_observer = this; |
| 209 | } |
| 210 | |
| 211 | AppModalDialogObserver::~AppModalDialogObserver() { |
| 212 | DCHECK(app_modal_dialog_observer); |
| 213 | app_modal_dialog_observer = nullptr; |
| 214 | } |
| 215 | |
Evan Stade | 7220e47 | 2020-01-31 17:06:57 | [diff] [blame] | 216 | } // namespace javascript_dialogs |