1 // Copyright 2014 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/chromeos/login/ui/simple_web_view_dialog.h"
6
7 #include "base/macros.h"
8 #include "base/strings/utf_string_conversions.h"
9 #include "chrome/app/chrome_command_ids.h"
10 #include "chrome/browser/chromeos/login/helper.h"
11 #include "chrome/browser/chromeos/login/ui/captive_portal_window_proxy.h"
12 #include "chrome/browser/command_updater_impl.h"
13 #include "chrome/browser/password_manager/chrome_password_manager_client.h"
14 #include "chrome/browser/profiles/profile.h"
15 #include "chrome/browser/ssl/security_state_tab_helper.h"
16 #include "chrome/browser/themes/theme_properties.h"
17 #include "chrome/browser/ui/autofill/chrome_autofill_client.h"
18 #include "chrome/browser/ui/browser.h"
19 #include "chrome/browser/ui/content_settings/content_setting_bubble_model_delegate.h"
20 #include "chrome/browser/ui/view_ids.h"
21 #include "chrome/browser/ui/views/chrome_layout_provider.h"
22 #include "chrome/browser/ui/views/toolbar/reload_button.h"
23 #include "chrome/grit/generated_resources.h"
24 #include "chrome/grit/theme_resources.h"
25 #include "components/omnibox/browser/location_bar_model_impl.h"
26 #include "components/password_manager/core/browser/password_manager.h"
27 #include "components/strings/grit/components_strings.h"
28 #include "content/public/browser/navigation_controller.h"
29 #include "content/public/browser/navigation_entry.h"
30 #include "content/public/browser/web_contents.h"
31 #include "content/public/common/content_constants.h"
32 #include "ipc/ipc_message.h"
33 #include "ui/base/l10n/l10n_util.h"
34 #include "ui/base/theme_provider.h"
35 #include "ui/views/background.h"
36 #include "ui/views/controls/webview/webview.h"
37 #include "ui/views/layout/grid_layout.h"
38 #include "ui/views/view.h"
39 #include "ui/views/widget/widget.h"
40 #include "ui/views/widget/widget_delegate.h"
41
42 using content::WebContents;
43 using views::GridLayout;
44
45 namespace {
46
47 const int kLocationBarHeight = 35;
48
49 // Margin between screen edge and SimpleWebViewDialog border.
50 const int kExternalMargin = 60;
51
52 // Margin between WebView and SimpleWebViewDialog border.
53 const int kInnerMargin = 2;
54
55 const SkColor kDialogColor = SK_ColorWHITE;
56
57 class ToolbarRowView : public views::View {
58 public:
ToolbarRowView()59 ToolbarRowView() {
60 SetBackground(views::CreateSolidBackground(kDialogColor));
61 }
62
~ToolbarRowView()63 ~ToolbarRowView() override {}
64
Init(std::unique_ptr<views::View> back,std::unique_ptr<views::View> forward,std::unique_ptr<views::View> reload,std::unique_ptr<views::View> location_bar)65 void Init(std::unique_ptr<views::View> back,
66 std::unique_ptr<views::View> forward,
67 std::unique_ptr<views::View> reload,
68 std::unique_ptr<views::View> location_bar) {
69 GridLayout* layout = SetLayoutManager(std::make_unique<GridLayout>());
70
71 const int related_horizontal_spacing =
72 ChromeLayoutProvider::Get()->GetDistanceMetric(
73 views::DISTANCE_RELATED_CONTROL_HORIZONTAL);
74 // Back button.
75 views::ColumnSet* column_set = layout->AddColumnSet(0);
76 column_set->AddColumn(GridLayout::CENTER, GridLayout::CENTER, 0,
77 GridLayout::ColumnSize::kUsePreferred, 0, 0);
78 column_set->AddPaddingColumn(0, related_horizontal_spacing);
79 // Forward button.
80 column_set->AddColumn(GridLayout::CENTER, GridLayout::CENTER, 0,
81 GridLayout::ColumnSize::kUsePreferred, 0, 0);
82 column_set->AddPaddingColumn(0, related_horizontal_spacing);
83 // Reload button.
84 column_set->AddColumn(GridLayout::CENTER, GridLayout::CENTER, 0,
85 GridLayout::ColumnSize::kUsePreferred, 0, 0);
86 column_set->AddPaddingColumn(0, related_horizontal_spacing);
87 // Location bar.
88 column_set->AddColumn(GridLayout::FILL, GridLayout::CENTER, 1,
89 GridLayout::ColumnSize::kFixed, kLocationBarHeight,
90 0);
91 column_set->AddPaddingColumn(0, related_horizontal_spacing);
92
93 layout->StartRow(0, 0);
94 layout->AddView(std::move(back));
95 layout->AddView(std::move(forward));
96 layout->AddView(std::move(reload));
97 layout->AddView(std::move(location_bar));
98 }
99
100 private:
101 DISALLOW_COPY_AND_ASSIGN(ToolbarRowView);
102 };
103
104 } // namespace
105
106 namespace chromeos {
107
108 // Stub implementation of ContentSettingBubbleModelDelegate.
109 class StubBubbleModelDelegate : public ContentSettingBubbleModelDelegate {
110 public:
StubBubbleModelDelegate()111 StubBubbleModelDelegate() {}
~StubBubbleModelDelegate()112 ~StubBubbleModelDelegate() override {}
113
114 private:
115 // ContentSettingBubbleModelDelegate implementation:
ShowCollectedCookiesDialog(content::WebContents * web_contents)116 void ShowCollectedCookiesDialog(content::WebContents* web_contents) override {
117 }
ShowContentSettingsPage(ContentSettingsType type)118 void ShowContentSettingsPage(ContentSettingsType type) override {}
ShowMediaSettingsPage()119 void ShowMediaSettingsPage() override {}
ShowLearnMorePage(ContentSettingsType type)120 void ShowLearnMorePage(ContentSettingsType type) override {}
121
122 DISALLOW_COPY_AND_ASSIGN(StubBubbleModelDelegate);
123 };
124
125 // SimpleWebViewDialog class ---------------------------------------------------
126
SimpleWebViewDialog(Profile * profile)127 SimpleWebViewDialog::SimpleWebViewDialog(Profile* profile)
128 : profile_(profile),
129 bubble_model_delegate_(new StubBubbleModelDelegate) {
130 command_updater_.reset(new CommandUpdaterImpl(this));
131 command_updater_->UpdateCommandEnabled(IDC_BACK, true);
132 command_updater_->UpdateCommandEnabled(IDC_FORWARD, true);
133 command_updater_->UpdateCommandEnabled(IDC_STOP, true);
134 command_updater_->UpdateCommandEnabled(IDC_RELOAD, true);
135 command_updater_->UpdateCommandEnabled(IDC_RELOAD_BYPASSING_CACHE, true);
136 command_updater_->UpdateCommandEnabled(IDC_RELOAD_CLEARING_CACHE, true);
137 }
138
~SimpleWebViewDialog()139 SimpleWebViewDialog::~SimpleWebViewDialog() {
140 if (web_view_ && web_view_->web_contents())
141 web_view_->web_contents()->SetDelegate(nullptr);
142 }
143
StartLoad(const GURL & url)144 void SimpleWebViewDialog::StartLoad(const GURL& url) {
145 if (!web_view_container_)
146 web_view_container_ = std::make_unique<views::WebView>(profile_);
147 web_view_ = web_view_container_.get();
148 web_view_->GetWebContents()->SetDelegate(this);
149 web_view_->LoadInitialURL(url);
150
151 WebContents* web_contents = web_view_->GetWebContents();
152 DCHECK(web_contents);
153
154 // Create the password manager that is needed for the proxy.
155 ChromePasswordManagerClient::CreateForWebContentsWithAutofillClient(
156 web_contents,
157 autofill::ChromeAutofillClient::FromWebContents(web_contents));
158 }
159
Init()160 void SimpleWebViewDialog::Init() {
161 // Create the security state model that the location bar model needs.
162 if (web_view_->GetWebContents())
163 SecurityStateTabHelper::CreateForWebContents(web_view_->GetWebContents());
164 location_bar_model_.reset(
165 new LocationBarModelImpl(this, content::kMaxURLDisplayChars));
166
167 SetBackground(views::CreateSolidBackground(kDialogColor));
168
169 // Back/Forward buttons.
170 auto back = std::make_unique<views::ImageButton>(base::BindRepeating(
171 [](CommandUpdater* updater) { updater->ExecuteCommand(IDC_BACK); },
172 command_updater_.get()));
173 back->SetTriggerableEventFlags(ui::EF_LEFT_MOUSE_BUTTON |
174 ui::EF_MIDDLE_MOUSE_BUTTON);
175 back->SetImageHorizontalAlignment(views::ImageButton::ALIGN_RIGHT);
176 back->SetTooltipText(l10n_util::GetStringUTF16(IDS_TOOLTIP_BACK));
177 back->SetFocusBehavior(views::View::FocusBehavior::ACCESSIBLE_ONLY);
178 back->SetAccessibleName(l10n_util::GetStringUTF16(IDS_ACCNAME_BACK));
179 back->SetID(VIEW_ID_BACK_BUTTON);
180 back_ = back.get();
181
182 auto forward = std::make_unique<views::ImageButton>(base::BindRepeating(
183 [](CommandUpdater* updater) { updater->ExecuteCommand(IDC_FORWARD); },
184 command_updater_.get()));
185 forward->SetTriggerableEventFlags(ui::EF_LEFT_MOUSE_BUTTON |
186 ui::EF_MIDDLE_MOUSE_BUTTON);
187 forward->SetTooltipText(l10n_util::GetStringUTF16(IDS_TOOLTIP_FORWARD));
188 forward->SetFocusBehavior(views::View::FocusBehavior::ACCESSIBLE_ONLY);
189 forward->SetAccessibleName(l10n_util::GetStringUTF16(IDS_ACCNAME_FORWARD));
190 forward->SetID(VIEW_ID_FORWARD_BUTTON);
191 forward_ = forward.get();
192
193 // Location bar.
194 auto location_bar = std::make_unique<LocationBarView>(
195 nullptr, profile_, command_updater_.get(), this, true);
196 location_bar_ = location_bar.get();
197
198 // Reload button.
199 auto reload = std::make_unique<ReloadButton>(command_updater_.get());
200 reload->SetTriggerableEventFlags(ui::EF_LEFT_MOUSE_BUTTON |
201 ui::EF_MIDDLE_MOUSE_BUTTON);
202 reload->SetTooltipText(l10n_util::GetStringUTF16(IDS_TOOLTIP_RELOAD));
203 reload->SetAccessibleName(l10n_util::GetStringUTF16(IDS_ACCNAME_RELOAD));
204 reload->SetID(VIEW_ID_RELOAD_BUTTON);
205 reload_ = reload.get();
206
207 // Use separate view to setup custom background.
208 auto toolbar_row = std::make_unique<ToolbarRowView>();
209 toolbar_row->Init(std::move(back), std::move(forward), std::move(reload),
210 std::move(location_bar));
211 // Add the views as child views before the grid layout is installed. This
212 // ensures ownership is more clear.
213 ToolbarRowView* toolbar_row_ptr = AddChildView(std::move(toolbar_row));
214 // Transfer ownership of the `web_view_` from the `web_view_container_`
215 // created in StartLoad() to `this`.
216 AddChildView(std::move(web_view_container_));
217
218 // Layout.
219 GridLayout* layout = SetLayoutManager(std::make_unique<GridLayout>());
220
221 views::ColumnSet* column_set = layout->AddColumnSet(0);
222 column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 1,
223 GridLayout::ColumnSize::kFixed, 0, 0);
224
225 column_set = layout->AddColumnSet(1);
226 column_set->AddPaddingColumn(0, kInnerMargin);
227 column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 1,
228 GridLayout::ColumnSize::kFixed, 0, 0);
229 column_set->AddPaddingColumn(0, kInnerMargin);
230
231 // Setup layout rows.
232 layout->StartRow(0, 0);
233 layout->AddExistingView(toolbar_row_ptr);
234
235 layout->AddPaddingRow(0, kInnerMargin);
236
237 layout->StartRow(1, 1);
238 layout->AddExistingView(web_view_);
239 layout->AddPaddingRow(0, kInnerMargin);
240
241 LoadImages();
242
243 location_bar_->Init();
244 UpdateReload(web_view_->web_contents()->IsLoading(), true);
245
246 gfx::Rect bounds(CalculateScreenBounds(gfx::Size()));
247 bounds.Inset(kExternalMargin, kExternalMargin);
248 layout->set_minimum_size(bounds.size());
249
250 Layout();
251 }
252
OpenURL(const content::OpenURLParams & params)253 content::WebContents* SimpleWebViewDialog::OpenURL(
254 const content::OpenURLParams& params) {
255 // As there are no Browsers right now, this could not actually ever work.
256 NOTIMPLEMENTED();
257 return nullptr;
258 }
259
NavigationStateChanged(WebContents * source,content::InvalidateTypes changed_flags)260 void SimpleWebViewDialog::NavigationStateChanged(
261 WebContents* source,
262 content::InvalidateTypes changed_flags) {
263 if (location_bar_) {
264 location_bar_->Update(nullptr);
265 UpdateButtons();
266 }
267 }
268
LoadingStateChanged(WebContents * source,bool to_different_document)269 void SimpleWebViewDialog::LoadingStateChanged(WebContents* source,
270 bool to_different_document) {
271 bool is_loading = source->IsLoading();
272 UpdateReload(is_loading && to_different_document, false);
273 command_updater_->UpdateCommandEnabled(IDC_STOP, is_loading);
274 }
275
GetWebContents()276 WebContents* SimpleWebViewDialog::GetWebContents() {
277 return nullptr;
278 }
279
GetLocationBarModel()280 LocationBarModel* SimpleWebViewDialog::GetLocationBarModel() {
281 return location_bar_model_.get();
282 }
283
GetLocationBarModel() const284 const LocationBarModel* SimpleWebViewDialog::GetLocationBarModel() const {
285 return location_bar_model_.get();
286 }
287
288 ContentSettingBubbleModelDelegate*
GetContentSettingBubbleModelDelegate()289 SimpleWebViewDialog::GetContentSettingBubbleModelDelegate() {
290 return bubble_model_delegate_.get();
291 }
292
GetActiveWebContents() const293 content::WebContents* SimpleWebViewDialog::GetActiveWebContents() const {
294 return web_view_->web_contents();
295 }
296
ExecuteCommandWithDisposition(int id,WindowOpenDisposition)297 void SimpleWebViewDialog::ExecuteCommandWithDisposition(int id,
298 WindowOpenDisposition) {
299 WebContents* web_contents = web_view_->web_contents();
300 switch (id) {
301 case IDC_BACK:
302 if (web_contents->GetController().CanGoBack()) {
303 location_bar_->Revert();
304 web_contents->GetController().GoBack();
305 }
306 break;
307 case IDC_FORWARD:
308 if (web_contents->GetController().CanGoForward()) {
309 location_bar_->Revert();
310 web_contents->GetController().GoForward();
311 }
312 break;
313 case IDC_STOP:
314 web_contents->Stop();
315 break;
316 case IDC_RELOAD:
317 // Always reload bypassing cache.
318 case IDC_RELOAD_BYPASSING_CACHE:
319 case IDC_RELOAD_CLEARING_CACHE:
320 location_bar_->Revert();
321 web_contents->GetController().Reload(content::ReloadType::BYPASSING_CACHE,
322 true);
323 break;
324 default:
325 NOTREACHED();
326 }
327 }
328
329 std::unique_ptr<views::WidgetDelegate>
MakeWidgetDelegate()330 SimpleWebViewDialog::MakeWidgetDelegate() {
331 auto delegate = std::make_unique<views::WidgetDelegate>();
332 delegate->SetInitiallyFocusedView(web_view_);
333 delegate->SetOwnedByWidget(true);
334 return delegate;
335 }
336
LoadImages()337 void SimpleWebViewDialog::LoadImages() {
338 const ui::ThemeProvider* tp = GetThemeProvider();
339
340 back_->SetImage(views::Button::STATE_NORMAL, tp->GetImageSkiaNamed(IDR_BACK));
341 back_->SetImage(views::Button::STATE_HOVERED,
342 tp->GetImageSkiaNamed(IDR_BACK_H));
343 back_->SetImage(views::Button::STATE_PRESSED,
344 tp->GetImageSkiaNamed(IDR_BACK_P));
345 back_->SetImage(views::Button::STATE_DISABLED,
346 tp->GetImageSkiaNamed(IDR_BACK_D));
347
348 forward_->SetImage(views::Button::STATE_NORMAL,
349 tp->GetImageSkiaNamed(IDR_FORWARD));
350 forward_->SetImage(views::Button::STATE_HOVERED,
351 tp->GetImageSkiaNamed(IDR_FORWARD_H));
352 forward_->SetImage(views::Button::STATE_PRESSED,
353 tp->GetImageSkiaNamed(IDR_FORWARD_P));
354 forward_->SetImage(views::Button::STATE_DISABLED,
355 tp->GetImageSkiaNamed(IDR_FORWARD_D));
356 }
357
UpdateButtons()358 void SimpleWebViewDialog::UpdateButtons() {
359 content::NavigationController& navigation_controller =
360 web_view_->web_contents()->GetController();
361 back_->SetEnabled(navigation_controller.CanGoBack());
362 forward_->SetEnabled(navigation_controller.CanGoForward());
363 }
364
UpdateReload(bool is_loading,bool force)365 void SimpleWebViewDialog::UpdateReload(bool is_loading, bool force) {
366 if (reload_) {
367 reload_->ChangeMode(
368 is_loading ? ReloadButton::Mode::kStop : ReloadButton::Mode::kReload,
369 force);
370 }
371 }
372
373 } // namespace chromeos
374