Merge ~osomon/oxide:autofill into oxide:master
- Git
- lp:~osomon/oxide
- autofill
- Merge into master
Status: | Needs review | ||||
---|---|---|---|---|---|
Proposed branch: | ~osomon/oxide:autofill | ||||
Merge into: | oxide:master | ||||
Diff against target: |
5836 lines (+4175/-459) 69 files modified
qt/core/BUILD.gn (+7/-0) qt/core/browser/contents_view_impl.cc (+1/-1) qt/core/browser/oxide_qt_browser_platform_integration.cc (+6/-1) qt/core/browser/oxide_qt_browser_platform_integration.h (+2/-1) qt/core/browser/oxide_qt_web_context.cc (+22/-3) qt/core/browser/oxide_qt_web_context.h (+4/-1) qt/core/browser/oxide_qt_web_view.cc (+26/-1) qt/core/browser/oxide_qt_web_view.h (+5/-1) qt/core/browser/web_autofill_popup_host.cc (+139/-0) qt/core/browser/web_autofill_popup_host.h (+78/-0) qt/core/glue/autofill_suggestion.cc (+30/-0) qt/core/glue/autofill_suggestion.h (+50/-0) qt/core/glue/auxiliary_ui_factory.h (+10/-1) qt/core/glue/oxide_qt_web_context_proxy.h (+4/-1) qt/core/glue/web_autofill_popup.h (+43/-0) qt/core/glue/web_autofill_popup_client.h (+40/-0) qt/qmlplugin/oxide.qmltypes (+7/-423) qt/qmlplugin/oxide_qml_plugin.cc (+3/-1) qt/quick/api/oxideqquickwebcontext.cc (+31/-0) qt/quick/api/oxideqquickwebcontext.h (+7/-1) qt/quick/qquick_legacy_auxiliary_ui_factory.cc (+13/-1) qt/quick/qquick_legacy_auxiliary_ui_factory.h (+5/-1) qt/tests/qmltests/api/tst_WebContext_autofillEnabled.qml (+38/-0) qt/tests/qmltests/ubuntu_ui/tst_WebViewAutofillPopup_autofill_profiles.html (+23/-0) qt/tests/qmltests/ubuntu_ui/tst_WebViewAutofillPopup_autofill_profiles.qml (+300/-0) qt/tests/qmltests/ubuntu_ui/tst_WebViewAutofillPopup_datalist.html (+37/-0) qt/tests/qmltests/ubuntu_ui/tst_WebViewAutofillPopup_datalist.qml (+157/-0) qt/tests/qmltests/ubuntu_ui/tst_WebViewAutofillPopup_passwords.html (+11/-0) qt/tests/qmltests/ubuntu_ui/tst_WebViewAutofillPopup_passwords.qml (+105/-0) qt/tests/qmltests/ubuntu_ui/tst_WebViewAutofillPopup_single_fields.html (+11/-0) qt/tests/qmltests/ubuntu_ui/tst_WebViewAutofillPopup_single_fields.qml (+359/-0) qt/uitk/lib/CMakeLists.txt (+2/-1) qt/uitk/lib/resources.qrc (+1/-0) qt/uitk/lib/resources/WebAutofillPopup.qml (+139/-0) qt/uitk/lib/uitk_auxiliary_ui_factory.cc (+12/-1) qt/uitk/lib/uitk_auxiliary_ui_factory.h (+5/-1) qt/uitk/lib/uitk_web_autofill_popup.cc (+297/-0) qt/uitk/lib/uitk_web_autofill_popup.h (+87/-0) shared/BUILD.gn (+30/-1) shared/browser/autofill/autofill_client.cc (+272/-0) shared/browser/autofill/autofill_client.h (+116/-0) shared/browser/autofill/autofill_popup_controller.cc (+163/-0) shared/browser/autofill/autofill_popup_controller.h (+92/-0) shared/browser/autofill/web_autofill_popup.h (+42/-0) shared/browser/autofill/web_autofill_popup_client.h (+41/-0) shared/browser/filtered_pref_store.cc (+181/-0) shared/browser/filtered_pref_store.h (+107/-0) shared/browser/filtered_pref_store_unittest.cc (+209/-0) shared/browser/oxide_browser_context.cc (+100/-4) shared/browser/oxide_browser_context.h (+26/-2) shared/browser/oxide_browser_platform_integration.cc (+6/-1) shared/browser/oxide_browser_platform_integration.h (+4/-1) shared/browser/oxide_content_browser_client.cc (+41/-0) shared/browser/oxide_content_browser_client.h (+6/-2) shared/browser/oxide_user_agent_settings.cc (+45/-1) shared/browser/oxide_user_agent_settings.h (+10/-1) shared/browser/oxide_web_view.cc (+10/-2) shared/browser/personal_data_manager_factory.cc (+72/-0) shared/browser/personal_data_manager_factory.h (+60/-0) shared/browser/resources/browser_manifest_overlay.json (+15/-0) shared/browser/resources/renderer_manifest_overlay.json (+14/-0) shared/browser/web_contents_client.cc (+9/-1) shared/browser/web_contents_client.h (+13/-1) shared/browser/web_data_service_factory.cc (+100/-0) shared/browser/web_data_service_factory.h (+63/-0) shared/browser/web_data_service_wrapper.cc (+114/-0) shared/browser/web_data_service_wrapper.h (+83/-0) shared/oxide_resources.grd (+2/-0) shared/renderer/oxide_content_renderer_client.cc (+12/-1) |
||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Chris Coulson | Needs Fixing | ||
Review via email:
|
Commit message
Add support for autofill popups in UbuntuWebView (LP: #1214048).
This initial implementation supports single text fields, datalist entries and autofill profiles.
Credit cards and passwords are not supported.
There is no API to manage stored profiles, this will be implemented as a followup feature.
Description of the change
- 8f3dace... by Olivier Tilloy
-
Fix a unit test when run in single process mode.
- acc726e... by Olivier Tilloy
-
Reduce the height of the autofill entries.
- 2bf8c7c... by Olivier Tilloy
-
Preview autofill entry under mouse cursor.
- fca284a... by Olivier Tilloy
-
Highlight currently selected suggestion.
- 32f4f1e... by Olivier Tilloy
-
Simplify focus handling.
- 0fd49b9... by Olivier Tilloy
-
Fix FTBFS.
- 305a4b1... by Olivier Tilloy
-
Handle validation when no suggestion is selected.
- c6f3be8... by Olivier Tilloy
-
Add a unit test for autofill popup destruction.
- ff81c57... by Olivier Tilloy
-
Ensure unit tests are locale-independent.

Chris Coulson (chrisccoulson) wrote : | # |
I've left a few more comments now. I've not yet finished reviewing it though, so there will most likely be some more later.
- f7170cf... by Olivier Tilloy
-
Fix build errors when rebased on latest master.
- 12ec53f... by Olivier Tilloy
-
Always use an InMemoryPrefStore.
Persisting the value of OxideQQuickWebC
ontext: :autofillEnable d would be
inconsistent with every other setting exposed by the API
(eg, we don't persist popupBlockerEnabled or doNotTrackEnabled). - 2c47ca7... by Olivier Tilloy
-
Move CreateAutofillPopup to WebContentsClient.
- bd0082a... by Olivier Tilloy
-
Bump version for new WebContext API to 1.23.
- b7f468f... by Olivier Tilloy
-
Drop default case as there's already a branch for every value.
- 579a028... by Olivier Tilloy
-
Do not modify oxide::
ContentClient to access the application locale. Instead, expose the application locale as a new method on BrowserPlatform
Integration. - e1aa089... by Olivier Tilloy
-
Marked a private helper private.
- f0aa5a2... by Olivier Tilloy
-
Ensure that autofill works in incognito mode, as expected.

Olivier Tilloy (osomon) wrote : | # |
I addressed the first round of comments from two days ago. Still pending: add tests for autofill behaviour in incognito mode.
- 1d7be1b... by Olivier Tilloy
-
Add tests for autofill in incognito webviews.
- e48baae... by Olivier Tilloy
-
Make WebAutofillPopu
pHost:: Init not return anything, for consistency. - 4017f9d... by Olivier Tilloy
-
Remove redundant std::move().
- 4116cd7... by Olivier Tilloy
-
Rename methods to start with an uppercase letter, for consistency with newly-written code.
- 31d4425... by Olivier Tilloy
-
Take timeout into account.
- dc3f850... by Olivier Tilloy
-
Do not depend on the omnibox component in release builds.
- f4c8cba... by Olivier Tilloy
-
Rename files for consistency with newly-added code.
- 4fd1d34... by Olivier Tilloy
-
Remove unused references to gfx::NativeView (always null) in AutofillPopupCo
ntroller. - 88dfc51... by Olivier Tilloy
-
Remove unused method.
- 31c9a11... by Olivier Tilloy
-
Make ownership of AutofillPopupCo
ntroller explicit.

Olivier Tilloy (osomon) wrote : | # |
I addressed all comments (and answered questions) in the second review round except for the last one (the suggestion to re-implement a custom WebDataServiceW
- 8dcafd5... by Olivier Tilloy
-
Fork WebDataServiceW
rapper to remove bits that oxide doesn't need.

Olivier Tilloy (osomon) wrote : | # |
WebDataServiceW
- bc34ffb... by Olivier Tilloy
-
New FilteredPrefStore class that stores all preferences in memory except for a selected set which are persisted on disk.
- 133ba6a... by Olivier Tilloy
-
Unit tests for FilteredPrefStore.
- 1ac8924... by Olivier Tilloy
-
Remove stale line that remained after rebasing on master.
Unmerged commits
- 1ac8924... by Olivier Tilloy
-
Remove stale line that remained after rebasing on master.
- 133ba6a... by Olivier Tilloy
-
Unit tests for FilteredPrefStore.
- bc34ffb... by Olivier Tilloy
-
New FilteredPrefStore class that stores all preferences in memory except for a selected set which are persisted on disk.
- 8dcafd5... by Olivier Tilloy
-
Fork WebDataServiceW
rapper to remove bits that oxide doesn't need. - 31c9a11... by Olivier Tilloy
-
Make ownership of AutofillPopupCo
ntroller explicit. - 88dfc51... by Olivier Tilloy
-
Remove unused method.
- 4fd1d34... by Olivier Tilloy
-
Remove unused references to gfx::NativeView (always null) in AutofillPopupCo
ntroller. - f4c8cba... by Olivier Tilloy
-
Rename files for consistency with newly-added code.
- dc3f850... by Olivier Tilloy
-
Do not depend on the omnibox component in release builds.
- 31d4425... by Olivier Tilloy
-
Take timeout into account.
Preview Diff
1 | diff --git a/qt/core/BUILD.gn b/qt/core/BUILD.gn |
2 | index 4a12427..6dd0eb2 100644 |
3 | --- a/qt/core/BUILD.gn |
4 | +++ b/qt/core/BUILD.gn |
5 | @@ -92,6 +92,7 @@ source_set("core_sources") { |
6 | ":core_moc_gen", |
7 | ":oxide_version", |
8 | "//base", |
9 | + "//components/autofill/core/browser", |
10 | "//components/sessions", |
11 | "//content/public/browser", |
12 | "//content/public/common", |
13 | @@ -269,6 +270,8 @@ source_set("core_sources") { |
14 | "browser/touch_selection/touch_editing_menu_host.h", |
15 | "browser/touch_selection/touch_handle_drawable_host.cc", |
16 | "browser/touch_selection/touch_handle_drawable_host.h", |
17 | + "browser/web_autofill_popup_host.cc", |
18 | + "browser/web_autofill_popup_host.h", |
19 | "browser/web_contents_id_tracker.cc", |
20 | "browser/web_contents_id_tracker.h", |
21 | "browser/web_context_menu_host.cc", |
22 | @@ -278,6 +281,8 @@ source_set("core_sources") { |
23 | "browser/web_preferences.cc", |
24 | "browser/web_preferences.h", |
25 | "common/oxide_qt_export.h", |
26 | + "glue/autofill_suggestion.cc", |
27 | + "glue/autofill_suggestion.h", |
28 | "glue/chrome_controller.cc", |
29 | "glue/chrome_controller.h", |
30 | "glue/chrome_controller_client.h", |
31 | @@ -325,6 +330,8 @@ source_set("core_sources") { |
32 | "glue/screen_utils.h", |
33 | "glue/touch_editing_menu.h", |
34 | "glue/touch_editing_menu_client.h", |
35 | + "glue/web_autofill_popup.h", |
36 | + "glue/web_autofill_popup_client.h", |
37 | "glue/web_context_menu.h", |
38 | "glue/web_context_menu_actions.h", |
39 | "glue/web_context_menu_client.h", |
40 | diff --git a/qt/core/browser/contents_view_impl.cc b/qt/core/browser/contents_view_impl.cc |
41 | index e683c42..b648fc6 100644 |
42 | --- a/qt/core/browser/contents_view_impl.cc |
43 | +++ b/qt/core/browser/contents_view_impl.cc |
44 | @@ -1,5 +1,5 @@ |
45 | // vim:expandtab:shiftwidth=2:tabstop=2: |
46 | -// Copyright (C) 2016 Canonical Ltd. |
47 | +// Copyright (C) 2016-2017 Canonical Ltd. |
48 | |
49 | // This library is free software; you can redistribute it and/or |
50 | // modify it under the terms of the GNU Lesser General Public |
51 | diff --git a/qt/core/browser/oxide_qt_browser_platform_integration.cc b/qt/core/browser/oxide_qt_browser_platform_integration.cc |
52 | index 8c6455e..ee2226c 100644 |
53 | --- a/qt/core/browser/oxide_qt_browser_platform_integration.cc |
54 | +++ b/qt/core/browser/oxide_qt_browser_platform_integration.cc |
55 | @@ -1,5 +1,5 @@ |
56 | // vim:expandtab:shiftwidth=2:tabstop=2: |
57 | -// Copyright (C) 2014-2016 Canonical Ltd. |
58 | +// Copyright (C) 2014-2017 Canonical Ltd. |
59 | |
60 | // This library is free software; you can redistribute it and/or |
61 | // modify it under the terms of the GNU Lesser General Public |
62 | @@ -20,6 +20,7 @@ |
63 | #include <QDesktopServices> |
64 | #include <QEvent> |
65 | #include <QGuiApplication> |
66 | +#include <QLocale> |
67 | #include <QStyleHints> |
68 | #include <QPointer> |
69 | #include <QString> |
70 | @@ -183,6 +184,10 @@ std::string BrowserPlatformIntegration::GetApplicationName() { |
71 | return application_name_; |
72 | } |
73 | |
74 | +std::string BrowserPlatformIntegration::GetApplicationLocale() { |
75 | + return QLocale::system().name().toStdString(); |
76 | +} |
77 | + |
78 | std::unique_ptr<oxide::DragSource> BrowserPlatformIntegration::CreateDragSource( |
79 | oxide::DragSourceClient* client) { |
80 | return base::WrapUnique(new DragSource(client)); |
81 | diff --git a/qt/core/browser/oxide_qt_browser_platform_integration.h b/qt/core/browser/oxide_qt_browser_platform_integration.h |
82 | index 0f7eeb1..f676a1d 100644 |
83 | --- a/qt/core/browser/oxide_qt_browser_platform_integration.h |
84 | +++ b/qt/core/browser/oxide_qt_browser_platform_integration.h |
85 | @@ -1,5 +1,5 @@ |
86 | // vim:expandtab:shiftwidth=2:tabstop=2: |
87 | -// Copyright (C) 2014-2015 Canonical Ltd. |
88 | +// Copyright (C) 2014-2017 Canonical Ltd. |
89 | |
90 | // This library is free software; you can redistribute it and/or |
91 | // modify it under the terms of the GNU Lesser General Public |
92 | @@ -63,6 +63,7 @@ class BrowserPlatformIntegration : public QObject, |
93 | ApplicationState GetApplicationState() override; |
94 | virtual int GetClickInterval() override; |
95 | std::string GetApplicationName() override; |
96 | + std::string GetApplicationLocale() override; |
97 | std::unique_ptr<oxide::DragSource> CreateDragSource( |
98 | oxide::DragSourceClient* client) override; |
99 | void CreateVibrationManager( |
100 | diff --git a/qt/core/browser/oxide_qt_web_context.cc b/qt/core/browser/oxide_qt_web_context.cc |
101 | index 504d165..fc1492f 100644 |
102 | --- a/qt/core/browser/oxide_qt_web_context.cc |
103 | +++ b/qt/core/browser/oxide_qt_web_context.cc |
104 | @@ -1,5 +1,5 @@ |
105 | // vim:expandtab:shiftwidth=2:tabstop=2: |
106 | -// Copyright (C) 2013-2016 Canonical Ltd. |
107 | +// Copyright (C) 2013-2017 Canonical Ltd. |
108 | |
109 | // This library is free software; you can redistribute it and/or |
110 | // modify it under the terms of the GNU Lesser General Public |
111 | @@ -138,7 +138,8 @@ struct WebContext::ConstructProperties { |
112 | devtools_enabled(false), |
113 | devtools_port(-1), |
114 | legacy_user_agent_override_enabled(false), |
115 | - do_not_track(false) {} |
116 | + do_not_track(false), |
117 | + autofill_enabled(false) {} |
118 | |
119 | std::string product; |
120 | std::string user_agent; |
121 | @@ -158,6 +159,7 @@ struct WebContext::ConstructProperties { |
122 | std::vector<UserAgentSettings::UserAgentOverride> user_agent_overrides; |
123 | bool legacy_user_agent_override_enabled; |
124 | bool do_not_track; |
125 | + bool autofill_enabled; |
126 | }; |
127 | |
128 | class SetCookiesContext : public base::RefCounted<SetCookiesContext> { |
129 | @@ -499,6 +501,7 @@ BrowserContext* WebContext::GetContext() { |
130 | ua_settings->SetIsPopupBlockerEnabled( |
131 | construct_props_->popup_blocker_enabled); |
132 | ua_settings->SetDoNotTrack(construct_props_->do_not_track); |
133 | + ua_settings->SetAutofillEnabled(construct_props_->autofill_enabled); |
134 | |
135 | context_->SetCookiePolicy(construct_props_->cookie_policy); |
136 | |
137 | @@ -999,7 +1002,7 @@ void WebContext::DefaultVideoDeviceChanged() { |
138 | } |
139 | |
140 | bool WebContext::doNotTrack() const { |
141 | - if (IsInitialized()) { |
142 | + if (IsInitialized()) { |
143 | return UserAgentSettings::Get(context_.get())->GetDoNotTrack(); |
144 | } |
145 | |
146 | @@ -1014,5 +1017,21 @@ void WebContext::setDoNotTrack(bool dnt) { |
147 | } |
148 | } |
149 | |
150 | +bool WebContext::autofillEnabled() const { |
151 | + if (IsInitialized()) { |
152 | + return UserAgentSettings::Get(context_.get())->IsAutofillEnabled(); |
153 | + } |
154 | + |
155 | + return construct_props_->autofill_enabled; |
156 | +} |
157 | + |
158 | +void WebContext::setAutofillEnabled(bool enabled) { |
159 | + if (IsInitialized()) { |
160 | + UserAgentSettings::Get(context_.get())->SetAutofillEnabled(enabled); |
161 | + } else { |
162 | + construct_props_->autofill_enabled = enabled; |
163 | + } |
164 | +} |
165 | + |
166 | } // namespace qt |
167 | } // namespace oxide |
168 | diff --git a/qt/core/browser/oxide_qt_web_context.h b/qt/core/browser/oxide_qt_web_context.h |
169 | index 1425b38..1dd4134 100644 |
170 | --- a/qt/core/browser/oxide_qt_web_context.h |
171 | +++ b/qt/core/browser/oxide_qt_web_context.h |
172 | @@ -1,5 +1,5 @@ |
173 | // vim:expandtab:shiftwidth=2:tabstop=2: |
174 | -// Copyright (C) 2013-2016 Canonical Ltd. |
175 | +// Copyright (C) 2013-2017 Canonical Ltd. |
176 | |
177 | // This library is free software; you can redistribute it and/or |
178 | // modify it under the terms of the GNU Lesser General Public |
179 | @@ -144,6 +144,9 @@ class WebContext : public WebContextProxy, |
180 | bool doNotTrack() const override; |
181 | void setDoNotTrack(bool dnt) override; |
182 | |
183 | + bool autofillEnabled() const override; |
184 | + void setAutofillEnabled(bool enabled) override; |
185 | + |
186 | // oxide::MediaCaptureDevicesContextClient implementation |
187 | void DefaultAudioDeviceChanged() override; |
188 | void DefaultVideoDeviceChanged() override; |
189 | diff --git a/qt/core/browser/oxide_qt_web_view.cc b/qt/core/browser/oxide_qt_web_view.cc |
190 | index ab4d2d2..dd97d3d 100644 |
191 | --- a/qt/core/browser/oxide_qt_web_view.cc |
192 | +++ b/qt/core/browser/oxide_qt_web_view.cc |
193 | @@ -1,5 +1,5 @@ |
194 | // vim:expandtab:shiftwidth=2:tabstop=2: |
195 | -// Copyright (C) 2013-2016 Canonical Ltd. |
196 | +// Copyright (C) 2013-2017 Canonical Ltd. |
197 | |
198 | // This library is free software; you can redistribute it and/or |
199 | // modify it under the terms of the GNU Lesser General Public |
200 | @@ -25,6 +25,7 @@ |
201 | |
202 | #include <QGuiApplication> |
203 | #include <QInputEvent> |
204 | +#include <QRectF> |
205 | #include <QScreen> |
206 | #include <QString> |
207 | #include <QtDebug> |
208 | @@ -75,6 +76,7 @@ |
209 | #include "qt/core/glue/oxide_qt_web_frame_proxy_client.h" |
210 | #include "qt/core/glue/oxide_qt_web_view_proxy_client.h" |
211 | #include "qt/core/glue/touch_editing_menu.h" |
212 | +#include "qt/core/glue/web_autofill_popup.h" |
213 | #include "qt/core/glue/web_context_menu.h" |
214 | #include "qt/core/glue/web_context_menu_params.h" |
215 | #include "shared/browser/oxide_browser_process_main.h" |
216 | @@ -103,6 +105,7 @@ |
217 | #include "oxide_qt_type_conversions.h" |
218 | #include "oxide_qt_web_context.h" |
219 | #include "oxide_qt_web_frame.h" |
220 | +#include "web_autofill_popup_host.h" |
221 | #include "web_contents_id_tracker.h" |
222 | #include "web_context_menu_host.h" |
223 | #include "web_preferences.h" |
224 | @@ -693,6 +696,28 @@ std::unique_ptr<oxide::WebContextMenu> WebView::CreateContextMenu( |
225 | return std::move(host); |
226 | } |
227 | |
228 | +std::unique_ptr<oxide::WebAutofillPopup> WebView::CreateAutofillPopup( |
229 | + const std::vector<autofill::Suggestion>& suggestions, |
230 | + const gfx::RectF& bounds, |
231 | + oxide::WebAutofillPopupClient* client) { |
232 | + std::unique_ptr<WebAutofillPopupHost> host = |
233 | + base::MakeUnique<WebAutofillPopupHost>(client); |
234 | + QRectF qt_bounds = ToQt( |
235 | + DpiUtils::ConvertChromiumPixelsToQt(bounds, contents_view_->GetScreen())); |
236 | + std::unique_ptr<WebAutofillPopup> popup = |
237 | + aux_ui_factory_->CreateWebAutofillPopup( |
238 | + WebAutofillPopupHost::BuildSuggestions(suggestions), |
239 | + qt_bounds, |
240 | + host.get()); |
241 | + if (!popup) { |
242 | + return nullptr; |
243 | + } |
244 | + |
245 | + host->Init(std::move(popup)); |
246 | + |
247 | + return std::move(host); |
248 | +} |
249 | + |
250 | std::unique_ptr<oxide::TouchEditingMenuController> |
251 | WebView::CreateOverrideTouchEditingMenuController( |
252 | oxide::TouchEditingMenuControllerClient* client) { |
253 | diff --git a/qt/core/browser/oxide_qt_web_view.h b/qt/core/browser/oxide_qt_web_view.h |
254 | index 5da67af..f0d3e50 100644 |
255 | --- a/qt/core/browser/oxide_qt_web_view.h |
256 | +++ b/qt/core/browser/oxide_qt_web_view.h |
257 | @@ -1,5 +1,5 @@ |
258 | // vim:expandtab:shiftwidth=2:tabstop=2: |
259 | -// Copyright (C) 2013-2016 Canonical Ltd. |
260 | +// Copyright (C) 2013-2017 Canonical Ltd. |
261 | |
262 | // This library is free software; you can redistribute it and/or |
263 | // modify it under the terms of the GNU Lesser General Public |
264 | @@ -154,6 +154,10 @@ class WebView : public oxide::WebViewClient, |
265 | const content::ContextMenuParams& params, |
266 | const std::vector<content::MenuItem>& items, |
267 | oxide::WebContextMenuClient* client) override; |
268 | + std::unique_ptr<oxide::WebAutofillPopup> CreateAutofillPopup( |
269 | + const std::vector<autofill::Suggestion>& suggestions, |
270 | + const gfx::RectF& bounds, |
271 | + oxide::WebAutofillPopupClient* client) override; |
272 | std::unique_ptr<oxide::TouchEditingMenuController> |
273 | CreateOverrideTouchEditingMenuController( |
274 | oxide::TouchEditingMenuControllerClient* client) override; |
275 | diff --git a/qt/core/browser/web_autofill_popup_host.cc b/qt/core/browser/web_autofill_popup_host.cc |
276 | new file mode 100644 |
277 | index 0000000..05fe479 |
278 | --- /dev/null |
279 | +++ b/qt/core/browser/web_autofill_popup_host.cc |
280 | @@ -0,0 +1,139 @@ |
281 | +// vim:expandtab:shiftwidth=2:tabstop=2: |
282 | +// Copyright (C) 2017 Canonical Ltd. |
283 | + |
284 | +// This library is free software; you can redistribute it and/or |
285 | +// modify it under the terms of the GNU Lesser General Public |
286 | +// License as published by the Free Software Foundation; either |
287 | +// version 2.1 of the License, or (at your option) any later version. |
288 | + |
289 | +// This library is distributed in the hope that it will be useful, |
290 | +// but WITHOUT ANY WARRANTY; without even the implied warranty of |
291 | +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
292 | +// Lesser General Public License for more details. |
293 | + |
294 | +// You should have received a copy of the GNU Lesser General Public |
295 | +// License along with this library; if not, write to the Free Software |
296 | +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
297 | + |
298 | +#include "web_autofill_popup_host.h" |
299 | + |
300 | +#include "base/logging.h" |
301 | +#include "base/strings/utf_string_conversions.h" |
302 | +#include "components/autofill/core/browser/popup_item_ids.h" |
303 | +#include "components/autofill/core/browser/suggestion.h" |
304 | + |
305 | +#include "qt/core/glue/web_autofill_popup.h" |
306 | +#include "shared/browser/autofill/web_autofill_popup_client.h" |
307 | + |
308 | +namespace oxide { |
309 | +namespace qt { |
310 | + |
311 | +void WebAutofillPopupHost::Show() { |
312 | + popup_->Show(); |
313 | +} |
314 | + |
315 | +void WebAutofillPopupHost::UpdateDataListValues( |
316 | + const std::vector<base::string16>& values, |
317 | + const std::vector<base::string16>& labels) { |
318 | + std::vector<AutofillSuggestion> suggestions; |
319 | + for (unsigned int i = 0; i < values.size(); ++i) { |
320 | + AutofillSuggestion suggestion; |
321 | + suggestion.frontend_id = autofill::POPUP_ITEM_ID_DATALIST_ENTRY; |
322 | + suggestion.type = AutofillSuggestion::Type::DataListEntry; |
323 | + suggestion.value = QString::fromStdString(base::UTF16ToUTF8(values[i])); |
324 | + suggestion.label = QString::fromStdString(base::UTF16ToUTF8(labels[i])); |
325 | + suggestions.push_back(suggestion); |
326 | + } |
327 | + |
328 | + if (suggestions.size() > |
329 | + static_cast<size_t>(std::numeric_limits<int>::max() + 1)) { |
330 | + LOG(WARNING) |
331 | + << "Truncating autofill popup - there are too many suggestions!"; |
332 | + suggestions.resize(std::numeric_limits<int>::max() + 1); |
333 | + } |
334 | + |
335 | + popup_->UpdateDataListValues(suggestions); |
336 | +} |
337 | + |
338 | +void WebAutofillPopupHost::Hide() { |
339 | + popup_->Hide(); |
340 | +} |
341 | + |
342 | +void WebAutofillPopupHost::Close() { |
343 | + client_->Close(); |
344 | +} |
345 | + |
346 | +void WebAutofillPopupHost::SelectSuggestion( |
347 | + const AutofillSuggestion& suggestion) { |
348 | + client_->SelectSuggestion(suggestion.frontend_id, |
349 | + base::UTF8ToUTF16(suggestion.value.toStdString())); |
350 | +} |
351 | + |
352 | +void WebAutofillPopupHost::ClearSelection() { |
353 | + client_->ClearSelection(); |
354 | +} |
355 | + |
356 | +void WebAutofillPopupHost::AcceptSuggestion( |
357 | + const AutofillSuggestion& suggestion) { |
358 | + client_->AcceptSuggestion(suggestion.frontend_id, |
359 | + base::UTF8ToUTF16(suggestion.value.toStdString())); |
360 | +} |
361 | + |
362 | +bool WebAutofillPopupHost::RemoveSuggestion( |
363 | + const AutofillSuggestion& suggestion) { |
364 | + return client_->RemoveSuggestion( |
365 | + suggestion.frontend_id, |
366 | + base::UTF8ToUTF16(suggestion.value.toStdString())); |
367 | +} |
368 | + |
369 | +WebAutofillPopupHost::WebAutofillPopupHost( |
370 | + oxide::WebAutofillPopupClient* client) |
371 | + : client_(client) {} |
372 | + |
373 | +WebAutofillPopupHost::~WebAutofillPopupHost() = default; |
374 | + |
375 | +void WebAutofillPopupHost::Init(std::unique_ptr<qt::WebAutofillPopup> popup) { |
376 | + popup_ = std::move(popup); |
377 | +} |
378 | + |
379 | +// static |
380 | +std::vector<AutofillSuggestion> WebAutofillPopupHost::BuildSuggestions( |
381 | + const std::vector<autofill::Suggestion>& suggestions) { |
382 | + std::vector<autofill::Suggestion> local_suggestions = suggestions; |
383 | + if (local_suggestions.size() > |
384 | + static_cast<size_t>(std::numeric_limits<int>::max() + 1)) { |
385 | + LOG(WARNING) |
386 | + << "Truncating autofill popup - there are too many suggestions!"; |
387 | + local_suggestions.resize(std::numeric_limits<int>::max() + 1); |
388 | + } |
389 | + |
390 | + std::vector<AutofillSuggestion> rv; |
391 | + for (const auto& suggestion : local_suggestions) { |
392 | + int fid = suggestion.frontend_id; |
393 | + if (fid > 0 || |
394 | + fid == autofill::POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY || |
395 | + fid == autofill::POPUP_ITEM_ID_PASSWORD_ENTRY || |
396 | + fid == autofill::POPUP_ITEM_ID_DATALIST_ENTRY) { |
397 | + AutofillSuggestion as; |
398 | + as.frontend_id = fid; |
399 | + if (fid > 0) { |
400 | + as.type = AutofillSuggestion::Type::ProfileEntry; |
401 | + } else if (fid == autofill::POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY) { |
402 | + as.type = AutofillSuggestion::Type::AutoCompleteEntry; |
403 | + } else if (fid == autofill::POPUP_ITEM_ID_PASSWORD_ENTRY) { |
404 | + as.type = AutofillSuggestion::Type::PasswordEntry; |
405 | + } else if (fid == autofill::POPUP_ITEM_ID_DATALIST_ENTRY) { |
406 | + as.type = AutofillSuggestion::Type::DataListEntry; |
407 | + } |
408 | + as.value = QString::fromStdString(base::UTF16ToUTF8(suggestion.value)); |
409 | + as.label = QString::fromStdString(base::UTF16ToUTF8(suggestion.label)); |
410 | + as.icon = QString::fromStdString(base::UTF16ToUTF8(suggestion.icon)); |
411 | + rv.push_back(as); |
412 | + } |
413 | + } |
414 | + |
415 | + return std::move(rv); |
416 | +} |
417 | + |
418 | +} // namespace qt |
419 | +} // namespace oxide |
420 | diff --git a/qt/core/browser/web_autofill_popup_host.h b/qt/core/browser/web_autofill_popup_host.h |
421 | new file mode 100644 |
422 | index 0000000..513e778 |
423 | --- /dev/null |
424 | +++ b/qt/core/browser/web_autofill_popup_host.h |
425 | @@ -0,0 +1,78 @@ |
426 | +// vim:expandtab:shiftwidth=2:tabstop=2: |
427 | +// Copyright (C) 2017 Canonical Ltd. |
428 | + |
429 | +// This library is free software; you can redistribute it and/or |
430 | +// modify it under the terms of the GNU Lesser General Public |
431 | +// License as published by the Free Software Foundation; either |
432 | +// version 2.1 of the License, or (at your option) any later version. |
433 | + |
434 | +// This library is distributed in the hope that it will be useful, |
435 | +// but WITHOUT ANY WARRANTY; without even the implied warranty of |
436 | +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
437 | +// Lesser General Public License for more details. |
438 | + |
439 | +// You should have received a copy of the GNU Lesser General Public |
440 | +// License along with this library; if not, write to the Free Software |
441 | +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
442 | + |
443 | +#ifndef _OXIDE_QT_CORE_BROWSER_WEB_AUTOFILL_POPUP_HOST_H_ |
444 | +#define _OXIDE_QT_CORE_BROWSER_WEB_AUTOFILL_POPUP_HOST_H_ |
445 | + |
446 | +#include <memory> |
447 | +#include <vector> |
448 | + |
449 | +#include "base/macros.h" |
450 | + |
451 | +#include "qt/core/glue/autofill_suggestion.h" |
452 | +#include "qt/core/glue/web_autofill_popup_client.h" |
453 | +#include "shared/browser/autofill/web_autofill_popup.h" |
454 | + |
455 | +namespace autofill { |
456 | +struct Suggestion; |
457 | +} |
458 | + |
459 | +namespace oxide { |
460 | + |
461 | +class WebAutofillPopupClient; |
462 | + |
463 | +namespace qt { |
464 | + |
465 | +class WebAutofillPopup; |
466 | + |
467 | +class WebAutofillPopupHost : public oxide::WebAutofillPopup, |
468 | + public WebAutofillPopupClient { |
469 | + public: |
470 | + WebAutofillPopupHost(oxide::WebAutofillPopupClient* client); |
471 | + ~WebAutofillPopupHost() override; |
472 | + |
473 | + void Init(std::unique_ptr<qt::WebAutofillPopup> popup); |
474 | + |
475 | + static std::vector<AutofillSuggestion> BuildSuggestions( |
476 | + const std::vector<autofill::Suggestion>& suggestions); |
477 | + |
478 | + private: |
479 | + // oxide::WebAutofillPopup implementation |
480 | + void Show() override; |
481 | + void UpdateDataListValues( |
482 | + const std::vector<base::string16>& values, |
483 | + const std::vector<base::string16>& labels) override; |
484 | + void Hide() override; |
485 | + |
486 | + // WebAutofillPopupClient implementation |
487 | + void Close() override; |
488 | + void SelectSuggestion(const AutofillSuggestion& suggestion) override; |
489 | + void ClearSelection() override; |
490 | + void AcceptSuggestion(const AutofillSuggestion& suggestion) override; |
491 | + bool RemoveSuggestion(const AutofillSuggestion& suggestion) override; |
492 | + |
493 | + oxide::WebAutofillPopupClient* client_; // Owns us |
494 | + |
495 | + std::unique_ptr<qt::WebAutofillPopup> popup_; |
496 | + |
497 | + DISALLOW_COPY_AND_ASSIGN(WebAutofillPopupHost); |
498 | +}; |
499 | + |
500 | +} // namespace qt |
501 | +} // namespace oxide |
502 | + |
503 | +#endif // _OXIDE_QT_CORE_BROWSER_WEB_AUTOFILL_POPUP_HOST_H_ |
504 | diff --git a/qt/core/glue/autofill_suggestion.cc b/qt/core/glue/autofill_suggestion.cc |
505 | new file mode 100644 |
506 | index 0000000..5344a3d |
507 | --- /dev/null |
508 | +++ b/qt/core/glue/autofill_suggestion.cc |
509 | @@ -0,0 +1,30 @@ |
510 | +// vim:expandtab:shiftwidth=2:tabstop=2: |
511 | +// Copyright (C) 2017 Canonical Ltd. |
512 | + |
513 | +// This library is free software; you can redistribute it and/or |
514 | +// modify it under the terms of the GNU Lesser General Public |
515 | +// License as published by the Free Software Foundation; either |
516 | +// version 2.1 of the License, or (at your option) any later version. |
517 | + |
518 | +// This library is distributed in the hope that it will be useful, |
519 | +// but WITHOUT ANY WARRANTY; without even the implied warranty of |
520 | +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
521 | +// Lesser General Public License for more details. |
522 | + |
523 | +// You should have received a copy of the GNU Lesser General Public |
524 | +// License along with this library; if not, write to the Free Software |
525 | +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
526 | + |
527 | +#include "autofill_suggestion.h" |
528 | + |
529 | +namespace oxide { |
530 | +namespace qt { |
531 | + |
532 | +AutofillSuggestion::AutofillSuggestion() = default; |
533 | + |
534 | +AutofillSuggestion::AutofillSuggestion(const AutofillSuggestion& other) = default; |
535 | + |
536 | +AutofillSuggestion::~AutofillSuggestion() = default; |
537 | + |
538 | +} // namespace qt |
539 | +} // namespace oxide |
540 | diff --git a/qt/core/glue/autofill_suggestion.h b/qt/core/glue/autofill_suggestion.h |
541 | new file mode 100644 |
542 | index 0000000..01e4ad2 |
543 | --- /dev/null |
544 | +++ b/qt/core/glue/autofill_suggestion.h |
545 | @@ -0,0 +1,50 @@ |
546 | +// vim:expandtab:shiftwidth=2:tabstop=2: |
547 | +// Copyright (C) 2017 Canonical Ltd. |
548 | + |
549 | +// This library is free software; you can redistribute it and/or |
550 | +// modify it under the terms of the GNU Lesser General Public |
551 | +// License as published by the Free Software Foundation; either |
552 | +// version 2.1 of the License, or (at your option) any later version. |
553 | + |
554 | +// This library is distributed in the hope that it will be useful, |
555 | +// but WITHOUT ANY WARRANTY; without even the implied warranty of |
556 | +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
557 | +// Lesser General Public License for more details. |
558 | + |
559 | +// You should have received a copy of the GNU Lesser General Public |
560 | +// License along with this library; if not, write to the Free Software |
561 | +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
562 | + |
563 | +#ifndef _OXIDE_QT_CORE_GLUE_AUTOFILL_SUGGESTION_H_ |
564 | +#define _OXIDE_QT_CORE_GLUE_AUTOFILL_SUGGESTION_H_ |
565 | + |
566 | +#include <QString> |
567 | + |
568 | +#include "qt/core/api/oxideqglobal.h" |
569 | + |
570 | +namespace oxide { |
571 | +namespace qt { |
572 | + |
573 | +struct OXIDE_QTCORE_EXPORT AutofillSuggestion { |
574 | + AutofillSuggestion(); |
575 | + AutofillSuggestion(const AutofillSuggestion& other); |
576 | + ~AutofillSuggestion(); |
577 | + |
578 | + enum class Type { |
579 | + ProfileEntry, |
580 | + AutoCompleteEntry, |
581 | + PasswordEntry, |
582 | + DataListEntry |
583 | + }; |
584 | + |
585 | + int frontend_id; |
586 | + Type type; |
587 | + QString value; |
588 | + QString label; |
589 | + QString icon; |
590 | +}; |
591 | + |
592 | +} // namespace qt |
593 | +} // namespace oxide |
594 | + |
595 | +#endif // _OXIDE_QT_CORE_GLUE_AUTOFILL_SUGGESTION_H_ |
596 | diff --git a/qt/core/glue/auxiliary_ui_factory.h b/qt/core/glue/auxiliary_ui_factory.h |
597 | index 4150b1b..557cbcf 100644 |
598 | --- a/qt/core/glue/auxiliary_ui_factory.h |
599 | +++ b/qt/core/glue/auxiliary_ui_factory.h |
600 | @@ -1,5 +1,5 @@ |
601 | // vim:expandtab:shiftwidth=2:tabstop=2: |
602 | -// Copyright (C) 2016 Canonical Ltd. |
603 | +// Copyright (C) 2016-2017 Canonical Ltd. |
604 | |
605 | // This library is free software; you can redistribute it and/or |
606 | // modify it under the terms of the GNU Lesser General Public |
607 | @@ -23,10 +23,12 @@ |
608 | |
609 | #include <QtGlobal> |
610 | |
611 | +#include "qt/core/glue/autofill_suggestion.h" |
612 | #include "qt/core/glue/edit_capability_flags.h" |
613 | #include "qt/core/glue/menu_item.h" |
614 | |
615 | QT_BEGIN_NAMESPACE |
616 | +class QRectF; |
617 | class QString; |
618 | class QUrl; |
619 | QT_END_NAMESPACE |
620 | @@ -39,6 +41,8 @@ class JavaScriptDialogClient; |
621 | enum class JavaScriptDialogType; |
622 | class TouchEditingMenu; |
623 | class TouchEditingMenuClient; |
624 | +class WebAutofillPopup; |
625 | +class WebAutofillPopupClient; |
626 | class WebContextMenu; |
627 | class WebContextMenuClient; |
628 | struct WebContextMenuParams; |
629 | @@ -52,6 +56,11 @@ class AuxiliaryUIFactory { |
630 | const std::vector<MenuItem>& items, |
631 | WebContextMenuClient* client) = 0; |
632 | |
633 | + virtual std::unique_ptr<WebAutofillPopup> CreateWebAutofillPopup( |
634 | + const std::vector<AutofillSuggestion>& suggestions, |
635 | + const QRectF& bounds, |
636 | + WebAutofillPopupClient* client) = 0; |
637 | + |
638 | virtual std::unique_ptr<TouchEditingMenu> CreateTouchEditingMenu( |
639 | EditCapabilityFlags edit_flags, |
640 | TouchEditingMenuClient* client) = 0; |
641 | diff --git a/qt/core/glue/oxide_qt_web_context_proxy.h b/qt/core/glue/oxide_qt_web_context_proxy.h |
642 | index ff13a71..49f0180 100644 |
643 | --- a/qt/core/glue/oxide_qt_web_context_proxy.h |
644 | +++ b/qt/core/glue/oxide_qt_web_context_proxy.h |
645 | @@ -1,5 +1,5 @@ |
646 | // vim:expandtab:shiftwidth=2:tabstop=2: |
647 | -// Copyright (C) 2013-2016 Canonical Ltd. |
648 | +// Copyright (C) 2013-2017 Canonical Ltd. |
649 | |
650 | // This library is free software; you can redistribute it and/or |
651 | // modify it under the terms of the GNU Lesser General Public |
652 | @@ -137,6 +137,9 @@ class OXIDE_QTCORE_EXPORT WebContextProxy : public ProxyBase<WebContext> { |
653 | |
654 | virtual bool doNotTrack() const = 0; |
655 | virtual void setDoNotTrack(bool dnt) = 0; |
656 | + |
657 | + virtual bool autofillEnabled() const = 0; |
658 | + virtual void setAutofillEnabled(bool enabled) = 0; |
659 | }; |
660 | |
661 | } // namespace qt |
662 | diff --git a/qt/core/glue/web_autofill_popup.h b/qt/core/glue/web_autofill_popup.h |
663 | new file mode 100644 |
664 | index 0000000..c28d561 |
665 | --- /dev/null |
666 | +++ b/qt/core/glue/web_autofill_popup.h |
667 | @@ -0,0 +1,43 @@ |
668 | +// vim:expandtab:shiftwidth=2:tabstop=2: |
669 | +// Copyright (C) 2017 Canonical Ltd. |
670 | + |
671 | +// This library is free software; you can redistribute it and/or |
672 | +// modify it under the terms of the GNU Lesser General Public |
673 | +// License as published by the Free Software Foundation; either |
674 | +// version 2.1 of the License, or (at your option) any later version. |
675 | + |
676 | +// This library is distributed in the hope that it will be useful, |
677 | +// but WITHOUT ANY WARRANTY; without even the implied warranty of |
678 | +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
679 | +// Lesser General Public License for more details. |
680 | + |
681 | +// You should have received a copy of the GNU Lesser General Public |
682 | +// License along with this library; if not, write to the Free Software |
683 | +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
684 | + |
685 | +#ifndef _OXIDE_QT_CORE_GLUE_WEB_AUTOFILL_POPUP_H_ |
686 | +#define _OXIDE_QT_CORE_GLUE_WEB_AUTOFILL_POPUP_H_ |
687 | + |
688 | +#include <vector> |
689 | + |
690 | +namespace oxide { |
691 | +namespace qt { |
692 | + |
693 | +class AutofillSuggestion; |
694 | + |
695 | +class WebAutofillPopup { |
696 | + public: |
697 | + virtual ~WebAutofillPopup() = default; |
698 | + |
699 | + virtual void Show() = 0; |
700 | + |
701 | + virtual void UpdateDataListValues( |
702 | + const std::vector<AutofillSuggestion>& suggestions) = 0; |
703 | + |
704 | + virtual void Hide() = 0; |
705 | +}; |
706 | + |
707 | +} // namespace qt |
708 | +} // namespace oxide |
709 | + |
710 | +#endif // _OXIDE_QT_CORE_GLUE_WEB_AUTOFILL_POPUP_H_ |
711 | diff --git a/qt/core/glue/web_autofill_popup_client.h b/qt/core/glue/web_autofill_popup_client.h |
712 | new file mode 100644 |
713 | index 0000000..b31cae4 |
714 | --- /dev/null |
715 | +++ b/qt/core/glue/web_autofill_popup_client.h |
716 | @@ -0,0 +1,40 @@ |
717 | +// vim:expandtab:shiftwidth=2:tabstop=2: |
718 | +// Copyright (C) 2017 Canonical Ltd. |
719 | + |
720 | +// This library is free software; you can redistribute it and/or |
721 | +// modify it under the terms of the GNU Lesser General Public |
722 | +// License as published by the Free Software Foundation; either |
723 | +// version 2.1 of the License, or (at your option) any later version. |
724 | + |
725 | +// This library is distributed in the hope that it will be useful, |
726 | +// but WITHOUT ANY WARRANTY; without even the implied warranty of |
727 | +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
728 | +// Lesser General Public License for more details. |
729 | + |
730 | +// You should have received a copy of the GNU Lesser General Public |
731 | +// License along with this library; if not, write to the Free Software |
732 | +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
733 | + |
734 | +#ifndef _OXIDE_QT_CORE_GLUE_WEB_AUTOFILL_POPUP_CLIENT_H_ |
735 | +#define _OXIDE_QT_CORE_GLUE_WEB_AUTOFILL_POPUP_CLIENT_H_ |
736 | + |
737 | +namespace oxide { |
738 | +namespace qt { |
739 | + |
740 | +struct AutofillSuggestion; |
741 | + |
742 | +class WebAutofillPopupClient { |
743 | + public: |
744 | + virtual ~WebAutofillPopupClient() {} |
745 | + |
746 | + virtual void Close() = 0; |
747 | + virtual void SelectSuggestion(const AutofillSuggestion& suggestion) = 0; |
748 | + virtual void ClearSelection() = 0; |
749 | + virtual void AcceptSuggestion(const AutofillSuggestion& suggestion) = 0; |
750 | + virtual bool RemoveSuggestion(const AutofillSuggestion& suggestion) = 0; |
751 | +}; |
752 | + |
753 | +} // namespace qt |
754 | +} // namespace oxide |
755 | + |
756 | +#endif // _OXIDE_QT_CORE_GLUE_WEB_AUTOFILL_POPUP_CLIENT_H_ |
757 | diff --git a/qt/qmlplugin/oxide.qmltypes b/qt/qmlplugin/oxide.qmltypes |
758 | index 8a111b6..ab9848f 100644 |
759 | --- a/qt/qmlplugin/oxide.qmltypes |
760 | +++ b/qt/qmlplugin/oxide.qmltypes |
761 | @@ -4,10 +4,10 @@ import QtQuick.tooling 1.2 |
762 | // It is used for QML tooling purposes only. |
763 | // |
764 | // This file was auto-generated by: |
765 | -// 'qmlplugindump -v -noinstantiate com.canonical.Oxide 1.19 com/canonical/Oxide' |
766 | +// 'qmlplugindump -v -noinstantiate com.canonical.Oxide 1.23 com/canonical/Oxide' |
767 | |
768 | Module { |
769 | - dependencies: [] |
770 | + dependencies: ["QtQuick 2.0"] |
771 | Component { |
772 | name: "OxideQCertificateError" |
773 | prototype: "QObject" |
774 | @@ -414,11 +414,12 @@ Module { |
775 | prototype: "QObject" |
776 | exports: [ |
777 | "WebContext 1.0", |
778 | + "WebContext 1.23", |
779 | "WebContext 1.3", |
780 | "WebContext 1.6", |
781 | "WebContext 1.9" |
782 | ] |
783 | - exportMetaObjectRevisions: [0, 1, 2, 3] |
784 | + exportMetaObjectRevisions: [0, 1, 2, 3, 4] |
785 | Enum { |
786 | name: "CookiePolicy" |
787 | values: { |
788 | @@ -475,6 +476,7 @@ Module { |
789 | Property { name: "defaultVideoCaptureDeviceId"; revision: 3; type: "string" } |
790 | Property { name: "userAgentOverrides"; revision: 3; type: "QVariantList" } |
791 | Property { name: "doNotTrackEnabled"; revision: 3; type: "bool" } |
792 | + Property { name: "autofillEnabled"; revision: 4; type: "bool" } |
793 | Signal { name: "devtoolsBindIpChanged" } |
794 | Signal { name: "hostMappingRulesChanged"; revision: 1 } |
795 | Signal { name: "allowedExtraUrlSchemesChanged"; revision: 1 } |
796 | @@ -483,6 +485,7 @@ Module { |
797 | Signal { name: "defaultVideoCaptureDeviceIdChanged"; revision: 3 } |
798 | Signal { name: "userAgentOverridesChanged"; revision: 3 } |
799 | Signal { name: "doNotTrackEnabledChanged"; revision: 3 } |
800 | + Signal { name: "autofillEnabledChanged"; revision: 4 } |
801 | Method { |
802 | name: "addUserScript" |
803 | Parameter { name: "script"; type: "OxideQQuickUserScript"; isPointer: true } |
804 | @@ -575,7 +578,7 @@ Module { |
805 | "WebView 1.8", |
806 | "WebView 1.9" |
807 | ] |
808 | - exportMetaObjectRevisions: [0, 6, 7, 8, 9, 1, 2, 3, 4, 5] |
809 | + exportMetaObjectRevisions: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] |
810 | attachedType: "OxideQQuickWebViewAttached" |
811 | Enum { |
812 | name: "LogMessageSeverityLevel" |
813 | @@ -972,423 +975,4 @@ Module { |
814 | Property { name: "touchEnabled"; type: "bool" } |
815 | Signal { name: "sansSerifFontFamilyChanged" } |
816 | } |
817 | - Component { |
818 | - name: "QAbstractItemModel" |
819 | - prototype: "QObject" |
820 | - Enum { |
821 | - name: "LayoutChangeHint" |
822 | - values: { |
823 | - "NoLayoutChangeHint": 0, |
824 | - "VerticalSortHint": 1, |
825 | - "HorizontalSortHint": 2 |
826 | - } |
827 | - } |
828 | - Signal { |
829 | - name: "dataChanged" |
830 | - Parameter { name: "topLeft"; type: "QModelIndex" } |
831 | - Parameter { name: "bottomRight"; type: "QModelIndex" } |
832 | - Parameter { name: "roles"; type: "QVector<int>" } |
833 | - } |
834 | - Signal { |
835 | - name: "dataChanged" |
836 | - Parameter { name: "topLeft"; type: "QModelIndex" } |
837 | - Parameter { name: "bottomRight"; type: "QModelIndex" } |
838 | - } |
839 | - Signal { |
840 | - name: "headerDataChanged" |
841 | - Parameter { name: "orientation"; type: "Qt::Orientation" } |
842 | - Parameter { name: "first"; type: "int" } |
843 | - Parameter { name: "last"; type: "int" } |
844 | - } |
845 | - Signal { |
846 | - name: "layoutChanged" |
847 | - Parameter { name: "parents"; type: "QList<QPersistentModelIndex>" } |
848 | - Parameter { name: "hint"; type: "QAbstractItemModel::LayoutChangeHint" } |
849 | - } |
850 | - Signal { |
851 | - name: "layoutChanged" |
852 | - Parameter { name: "parents"; type: "QList<QPersistentModelIndex>" } |
853 | - } |
854 | - Signal { name: "layoutChanged" } |
855 | - Signal { |
856 | - name: "layoutAboutToBeChanged" |
857 | - Parameter { name: "parents"; type: "QList<QPersistentModelIndex>" } |
858 | - Parameter { name: "hint"; type: "QAbstractItemModel::LayoutChangeHint" } |
859 | - } |
860 | - Signal { |
861 | - name: "layoutAboutToBeChanged" |
862 | - Parameter { name: "parents"; type: "QList<QPersistentModelIndex>" } |
863 | - } |
864 | - Signal { name: "layoutAboutToBeChanged" } |
865 | - Signal { |
866 | - name: "rowsAboutToBeInserted" |
867 | - Parameter { name: "parent"; type: "QModelIndex" } |
868 | - Parameter { name: "first"; type: "int" } |
869 | - Parameter { name: "last"; type: "int" } |
870 | - } |
871 | - Signal { |
872 | - name: "rowsInserted" |
873 | - Parameter { name: "parent"; type: "QModelIndex" } |
874 | - Parameter { name: "first"; type: "int" } |
875 | - Parameter { name: "last"; type: "int" } |
876 | - } |
877 | - Signal { |
878 | - name: "rowsAboutToBeRemoved" |
879 | - Parameter { name: "parent"; type: "QModelIndex" } |
880 | - Parameter { name: "first"; type: "int" } |
881 | - Parameter { name: "last"; type: "int" } |
882 | - } |
883 | - Signal { |
884 | - name: "rowsRemoved" |
885 | - Parameter { name: "parent"; type: "QModelIndex" } |
886 | - Parameter { name: "first"; type: "int" } |
887 | - Parameter { name: "last"; type: "int" } |
888 | - } |
889 | - Signal { |
890 | - name: "columnsAboutToBeInserted" |
891 | - Parameter { name: "parent"; type: "QModelIndex" } |
892 | - Parameter { name: "first"; type: "int" } |
893 | - Parameter { name: "last"; type: "int" } |
894 | - } |
895 | - Signal { |
896 | - name: "columnsInserted" |
897 | - Parameter { name: "parent"; type: "QModelIndex" } |
898 | - Parameter { name: "first"; type: "int" } |
899 | - Parameter { name: "last"; type: "int" } |
900 | - } |
901 | - Signal { |
902 | - name: "columnsAboutToBeRemoved" |
903 | - Parameter { name: "parent"; type: "QModelIndex" } |
904 | - Parameter { name: "first"; type: "int" } |
905 | - Parameter { name: "last"; type: "int" } |
906 | - } |
907 | - Signal { |
908 | - name: "columnsRemoved" |
909 | - Parameter { name: "parent"; type: "QModelIndex" } |
910 | - Parameter { name: "first"; type: "int" } |
911 | - Parameter { name: "last"; type: "int" } |
912 | - } |
913 | - Signal { name: "modelAboutToBeReset" } |
914 | - Signal { name: "modelReset" } |
915 | - Signal { |
916 | - name: "rowsAboutToBeMoved" |
917 | - Parameter { name: "sourceParent"; type: "QModelIndex" } |
918 | - Parameter { name: "sourceStart"; type: "int" } |
919 | - Parameter { name: "sourceEnd"; type: "int" } |
920 | - Parameter { name: "destinationParent"; type: "QModelIndex" } |
921 | - Parameter { name: "destinationRow"; type: "int" } |
922 | - } |
923 | - Signal { |
924 | - name: "rowsMoved" |
925 | - Parameter { name: "parent"; type: "QModelIndex" } |
926 | - Parameter { name: "start"; type: "int" } |
927 | - Parameter { name: "end"; type: "int" } |
928 | - Parameter { name: "destination"; type: "QModelIndex" } |
929 | - Parameter { name: "row"; type: "int" } |
930 | - } |
931 | - Signal { |
932 | - name: "columnsAboutToBeMoved" |
933 | - Parameter { name: "sourceParent"; type: "QModelIndex" } |
934 | - Parameter { name: "sourceStart"; type: "int" } |
935 | - Parameter { name: "sourceEnd"; type: "int" } |
936 | - Parameter { name: "destinationParent"; type: "QModelIndex" } |
937 | - Parameter { name: "destinationColumn"; type: "int" } |
938 | - } |
939 | - Signal { |
940 | - name: "columnsMoved" |
941 | - Parameter { name: "parent"; type: "QModelIndex" } |
942 | - Parameter { name: "start"; type: "int" } |
943 | - Parameter { name: "end"; type: "int" } |
944 | - Parameter { name: "destination"; type: "QModelIndex" } |
945 | - Parameter { name: "column"; type: "int" } |
946 | - } |
947 | - Method { name: "submit"; type: "bool" } |
948 | - Method { name: "revert" } |
949 | - Method { |
950 | - name: "hasIndex" |
951 | - type: "bool" |
952 | - Parameter { name: "row"; type: "int" } |
953 | - Parameter { name: "column"; type: "int" } |
954 | - Parameter { name: "parent"; type: "QModelIndex" } |
955 | - } |
956 | - Method { |
957 | - name: "hasIndex" |
958 | - type: "bool" |
959 | - Parameter { name: "row"; type: "int" } |
960 | - Parameter { name: "column"; type: "int" } |
961 | - } |
962 | - Method { |
963 | - name: "index" |
964 | - type: "QModelIndex" |
965 | - Parameter { name: "row"; type: "int" } |
966 | - Parameter { name: "column"; type: "int" } |
967 | - Parameter { name: "parent"; type: "QModelIndex" } |
968 | - } |
969 | - Method { |
970 | - name: "index" |
971 | - type: "QModelIndex" |
972 | - Parameter { name: "row"; type: "int" } |
973 | - Parameter { name: "column"; type: "int" } |
974 | - } |
975 | - Method { |
976 | - name: "parent" |
977 | - type: "QModelIndex" |
978 | - Parameter { name: "child"; type: "QModelIndex" } |
979 | - } |
980 | - Method { |
981 | - name: "sibling" |
982 | - type: "QModelIndex" |
983 | - Parameter { name: "row"; type: "int" } |
984 | - Parameter { name: "column"; type: "int" } |
985 | - Parameter { name: "idx"; type: "QModelIndex" } |
986 | - } |
987 | - Method { |
988 | - name: "rowCount" |
989 | - type: "int" |
990 | - Parameter { name: "parent"; type: "QModelIndex" } |
991 | - } |
992 | - Method { name: "rowCount"; type: "int" } |
993 | - Method { |
994 | - name: "columnCount" |
995 | - type: "int" |
996 | - Parameter { name: "parent"; type: "QModelIndex" } |
997 | - } |
998 | - Method { name: "columnCount"; type: "int" } |
999 | - Method { |
1000 | - name: "hasChildren" |
1001 | - type: "bool" |
1002 | - Parameter { name: "parent"; type: "QModelIndex" } |
1003 | - } |
1004 | - Method { name: "hasChildren"; type: "bool" } |
1005 | - Method { |
1006 | - name: "data" |
1007 | - type: "QVariant" |
1008 | - Parameter { name: "index"; type: "QModelIndex" } |
1009 | - Parameter { name: "role"; type: "int" } |
1010 | - } |
1011 | - Method { |
1012 | - name: "data" |
1013 | - type: "QVariant" |
1014 | - Parameter { name: "index"; type: "QModelIndex" } |
1015 | - } |
1016 | - Method { |
1017 | - name: "setData" |
1018 | - type: "bool" |
1019 | - Parameter { name: "index"; type: "QModelIndex" } |
1020 | - Parameter { name: "value"; type: "QVariant" } |
1021 | - Parameter { name: "role"; type: "int" } |
1022 | - } |
1023 | - Method { |
1024 | - name: "setData" |
1025 | - type: "bool" |
1026 | - Parameter { name: "index"; type: "QModelIndex" } |
1027 | - Parameter { name: "value"; type: "QVariant" } |
1028 | - } |
1029 | - Method { |
1030 | - name: "headerData" |
1031 | - type: "QVariant" |
1032 | - Parameter { name: "section"; type: "int" } |
1033 | - Parameter { name: "orientation"; type: "Qt::Orientation" } |
1034 | - Parameter { name: "role"; type: "int" } |
1035 | - } |
1036 | - Method { |
1037 | - name: "headerData" |
1038 | - type: "QVariant" |
1039 | - Parameter { name: "section"; type: "int" } |
1040 | - Parameter { name: "orientation"; type: "Qt::Orientation" } |
1041 | - } |
1042 | - Method { |
1043 | - name: "fetchMore" |
1044 | - Parameter { name: "parent"; type: "QModelIndex" } |
1045 | - } |
1046 | - Method { |
1047 | - name: "canFetchMore" |
1048 | - type: "bool" |
1049 | - Parameter { name: "parent"; type: "QModelIndex" } |
1050 | - } |
1051 | - Method { |
1052 | - name: "flags" |
1053 | - type: "Qt::ItemFlags" |
1054 | - Parameter { name: "index"; type: "QModelIndex" } |
1055 | - } |
1056 | - Method { |
1057 | - name: "match" |
1058 | - type: "QModelIndexList" |
1059 | - Parameter { name: "start"; type: "QModelIndex" } |
1060 | - Parameter { name: "role"; type: "int" } |
1061 | - Parameter { name: "value"; type: "QVariant" } |
1062 | - Parameter { name: "hits"; type: "int" } |
1063 | - Parameter { name: "flags"; type: "Qt::MatchFlags" } |
1064 | - } |
1065 | - Method { |
1066 | - name: "match" |
1067 | - type: "QModelIndexList" |
1068 | - Parameter { name: "start"; type: "QModelIndex" } |
1069 | - Parameter { name: "role"; type: "int" } |
1070 | - Parameter { name: "value"; type: "QVariant" } |
1071 | - Parameter { name: "hits"; type: "int" } |
1072 | - } |
1073 | - Method { |
1074 | - name: "match" |
1075 | - type: "QModelIndexList" |
1076 | - Parameter { name: "start"; type: "QModelIndex" } |
1077 | - Parameter { name: "role"; type: "int" } |
1078 | - Parameter { name: "value"; type: "QVariant" } |
1079 | - } |
1080 | - } |
1081 | - Component { name: "QAbstractListModel"; prototype: "QAbstractItemModel" } |
1082 | - Component { |
1083 | - name: "QQuickItem" |
1084 | - defaultProperty: "data" |
1085 | - prototype: "QObject" |
1086 | - Enum { |
1087 | - name: "TransformOrigin" |
1088 | - values: { |
1089 | - "TopLeft": 0, |
1090 | - "Top": 1, |
1091 | - "TopRight": 2, |
1092 | - "Left": 3, |
1093 | - "Center": 4, |
1094 | - "Right": 5, |
1095 | - "BottomLeft": 6, |
1096 | - "Bottom": 7, |
1097 | - "BottomRight": 8 |
1098 | - } |
1099 | - } |
1100 | - Property { name: "parent"; type: "QQuickItem"; isPointer: true } |
1101 | - Property { name: "data"; type: "QObject"; isList: true; isReadonly: true } |
1102 | - Property { name: "resources"; type: "QObject"; isList: true; isReadonly: true } |
1103 | - Property { name: "children"; type: "QQuickItem"; isList: true; isReadonly: true } |
1104 | - Property { name: "x"; type: "double" } |
1105 | - Property { name: "y"; type: "double" } |
1106 | - Property { name: "z"; type: "double" } |
1107 | - Property { name: "width"; type: "double" } |
1108 | - Property { name: "height"; type: "double" } |
1109 | - Property { name: "opacity"; type: "double" } |
1110 | - Property { name: "enabled"; type: "bool" } |
1111 | - Property { name: "visible"; type: "bool" } |
1112 | - Property { name: "visibleChildren"; type: "QQuickItem"; isList: true; isReadonly: true } |
1113 | - Property { name: "states"; type: "QQuickState"; isList: true; isReadonly: true } |
1114 | - Property { name: "transitions"; type: "QQuickTransition"; isList: true; isReadonly: true } |
1115 | - Property { name: "state"; type: "string" } |
1116 | - Property { name: "childrenRect"; type: "QRectF"; isReadonly: true } |
1117 | - Property { name: "anchors"; type: "QQuickAnchors"; isReadonly: true; isPointer: true } |
1118 | - Property { name: "left"; type: "QQuickAnchorLine"; isReadonly: true } |
1119 | - Property { name: "right"; type: "QQuickAnchorLine"; isReadonly: true } |
1120 | - Property { name: "horizontalCenter"; type: "QQuickAnchorLine"; isReadonly: true } |
1121 | - Property { name: "top"; type: "QQuickAnchorLine"; isReadonly: true } |
1122 | - Property { name: "bottom"; type: "QQuickAnchorLine"; isReadonly: true } |
1123 | - Property { name: "verticalCenter"; type: "QQuickAnchorLine"; isReadonly: true } |
1124 | - Property { name: "baseline"; type: "QQuickAnchorLine"; isReadonly: true } |
1125 | - Property { name: "baselineOffset"; type: "double" } |
1126 | - Property { name: "clip"; type: "bool" } |
1127 | - Property { name: "focus"; type: "bool" } |
1128 | - Property { name: "activeFocus"; type: "bool"; isReadonly: true } |
1129 | - Property { name: "activeFocusOnTab"; revision: 1; type: "bool" } |
1130 | - Property { name: "rotation"; type: "double" } |
1131 | - Property { name: "scale"; type: "double" } |
1132 | - Property { name: "transformOrigin"; type: "TransformOrigin" } |
1133 | - Property { name: "transformOriginPoint"; type: "QPointF"; isReadonly: true } |
1134 | - Property { name: "transform"; type: "QQuickTransform"; isList: true; isReadonly: true } |
1135 | - Property { name: "smooth"; type: "bool" } |
1136 | - Property { name: "antialiasing"; type: "bool" } |
1137 | - Property { name: "implicitWidth"; type: "double" } |
1138 | - Property { name: "implicitHeight"; type: "double" } |
1139 | - Property { name: "layer"; type: "QQuickItemLayer"; isReadonly: true; isPointer: true } |
1140 | - Signal { |
1141 | - name: "childrenRectChanged" |
1142 | - Parameter { type: "QRectF" } |
1143 | - } |
1144 | - Signal { |
1145 | - name: "baselineOffsetChanged" |
1146 | - Parameter { type: "double" } |
1147 | - } |
1148 | - Signal { |
1149 | - name: "stateChanged" |
1150 | - Parameter { type: "string" } |
1151 | - } |
1152 | - Signal { |
1153 | - name: "focusChanged" |
1154 | - Parameter { type: "bool" } |
1155 | - } |
1156 | - Signal { |
1157 | - name: "activeFocusChanged" |
1158 | - Parameter { type: "bool" } |
1159 | - } |
1160 | - Signal { |
1161 | - name: "activeFocusOnTabChanged" |
1162 | - revision: 1 |
1163 | - Parameter { type: "bool" } |
1164 | - } |
1165 | - Signal { |
1166 | - name: "parentChanged" |
1167 | - Parameter { type: "QQuickItem"; isPointer: true } |
1168 | - } |
1169 | - Signal { |
1170 | - name: "transformOriginChanged" |
1171 | - Parameter { type: "TransformOrigin" } |
1172 | - } |
1173 | - Signal { |
1174 | - name: "smoothChanged" |
1175 | - Parameter { type: "bool" } |
1176 | - } |
1177 | - Signal { |
1178 | - name: "antialiasingChanged" |
1179 | - Parameter { type: "bool" } |
1180 | - } |
1181 | - Signal { |
1182 | - name: "clipChanged" |
1183 | - Parameter { type: "bool" } |
1184 | - } |
1185 | - Signal { |
1186 | - name: "windowChanged" |
1187 | - revision: 1 |
1188 | - Parameter { name: "window"; type: "QQuickWindow"; isPointer: true } |
1189 | - } |
1190 | - Method { name: "update" } |
1191 | - Method { |
1192 | - name: "grabToImage" |
1193 | - revision: 2 |
1194 | - type: "bool" |
1195 | - Parameter { name: "callback"; type: "QJSValue" } |
1196 | - Parameter { name: "targetSize"; type: "QSize" } |
1197 | - } |
1198 | - Method { |
1199 | - name: "grabToImage" |
1200 | - revision: 2 |
1201 | - type: "bool" |
1202 | - Parameter { name: "callback"; type: "QJSValue" } |
1203 | - } |
1204 | - Method { |
1205 | - name: "contains" |
1206 | - type: "bool" |
1207 | - Parameter { name: "point"; type: "QPointF" } |
1208 | - } |
1209 | - Method { |
1210 | - name: "mapFromItem" |
1211 | - Parameter { type: "QQmlV4Function"; isPointer: true } |
1212 | - } |
1213 | - Method { |
1214 | - name: "mapToItem" |
1215 | - Parameter { type: "QQmlV4Function"; isPointer: true } |
1216 | - } |
1217 | - Method { name: "forceActiveFocus" } |
1218 | - Method { |
1219 | - name: "forceActiveFocus" |
1220 | - Parameter { name: "reason"; type: "Qt::FocusReason" } |
1221 | - } |
1222 | - Method { |
1223 | - name: "nextItemInFocusChain" |
1224 | - revision: 1 |
1225 | - type: "QQuickItem*" |
1226 | - Parameter { name: "forward"; type: "bool" } |
1227 | - } |
1228 | - Method { name: "nextItemInFocusChain"; revision: 1; type: "QQuickItem*" } |
1229 | - Method { |
1230 | - name: "childAt" |
1231 | - type: "QQuickItem*" |
1232 | - Parameter { name: "x"; type: "double" } |
1233 | - Parameter { name: "y"; type: "double" } |
1234 | - } |
1235 | - } |
1236 | } |
1237 | diff --git a/qt/qmlplugin/oxide_qml_plugin.cc b/qt/qmlplugin/oxide_qml_plugin.cc |
1238 | index 1597b5d..b56fb51 100644 |
1239 | --- a/qt/qmlplugin/oxide_qml_plugin.cc |
1240 | +++ b/qt/qmlplugin/oxide_qml_plugin.cc |
1241 | @@ -1,5 +1,5 @@ |
1242 | // vim:expandtab:shiftwidth=2:tabstop=2: |
1243 | -// Copyright (C) 2013-2016 Canonical Ltd. |
1244 | +// Copyright (C) 2013-2017 Canonical Ltd. |
1245 | |
1246 | // This library is free software; you can redistribute it and/or |
1247 | // modify it under the terms of the GNU Lesser General Public |
1248 | @@ -215,6 +215,8 @@ class OxideQmlPlugin : public QQmlExtensionPlugin { |
1249 | qmlRegisterUncreatableType<OxideQQuickNavigationHistory, 1>( |
1250 | uri, 1, 19, "NavigationHistory", |
1251 | "NavigationHistory is accessed via WebView.navigationHistory"); |
1252 | + |
1253 | + qmlRegisterType<OxideQQuickWebContext, 4>(uri, 1, 23, "WebContext"); |
1254 | } |
1255 | }; |
1256 | |
1257 | diff --git a/qt/quick/api/oxideqquickwebcontext.cc b/qt/quick/api/oxideqquickwebcontext.cc |
1258 | index 6fe1ef7..1946af0 100644 |
1259 | --- a/qt/quick/api/oxideqquickwebcontext.cc |
1260 | +++ b/qt/quick/api/oxideqquickwebcontext.cc |
1261 | @@ -1561,4 +1561,35 @@ void OxideQQuickWebContext::setDoNotTrack(bool dnt) { |
1262 | emit doNotTrackEnabledChanged(); |
1263 | } |
1264 | |
1265 | +/*! |
1266 | +\qmlproperty bool WebContext::autofillEnabled |
1267 | +\since OxideQt 1.22 |
1268 | + |
1269 | +Whether to enable autofill. The default is false. |
1270 | + |
1271 | +Autofill is most probably neither useful nor desirable outside of the browser |
1272 | +use case, and as such is disabled by default. |
1273 | + |
1274 | +The base Oxide WebView does not know how to display autofill suggestions, |
1275 | +use the WebView from the Oxide.Ubuntu module if you need them. |
1276 | +*/ |
1277 | + |
1278 | +bool OxideQQuickWebContext::autofillEnabled() const { |
1279 | + Q_D(const OxideQQuickWebContext); |
1280 | + |
1281 | + return d->proxy_->autofillEnabled(); |
1282 | +} |
1283 | + |
1284 | +void OxideQQuickWebContext::setAutofillEnabled(bool enabled) { |
1285 | + Q_D(OxideQQuickWebContext); |
1286 | + |
1287 | + if (autofillEnabled() == enabled) { |
1288 | + return; |
1289 | + } |
1290 | + |
1291 | + d->proxy_->setAutofillEnabled(enabled); |
1292 | + |
1293 | + emit autofillEnabledChanged(); |
1294 | +} |
1295 | + |
1296 | #include "moc_oxideqquickwebcontext.cpp" |
1297 | diff --git a/qt/quick/api/oxideqquickwebcontext.h b/qt/quick/api/oxideqquickwebcontext.h |
1298 | index 99de73a..f8ca6fa 100644 |
1299 | --- a/qt/quick/api/oxideqquickwebcontext.h |
1300 | +++ b/qt/quick/api/oxideqquickwebcontext.h |
1301 | @@ -1,5 +1,5 @@ |
1302 | // vim:expandtab:shiftwidth=2:tabstop=2: |
1303 | -// Copyright (C) 2013-2015 Canonical Ltd. |
1304 | +// Copyright (C) 2013-2017 Canonical Ltd. |
1305 | |
1306 | // This library is free software; you can redistribute it and/or |
1307 | // modify it under the terms of the GNU Lesser General Public |
1308 | @@ -77,6 +77,8 @@ class OXIDE_QTQUICK_EXPORT OxideQQuickWebContext : public QObject, |
1309 | |
1310 | Q_PROPERTY(bool doNotTrackEnabled READ doNotTrack WRITE setDoNotTrack NOTIFY doNotTrackEnabledChanged REVISION 3) |
1311 | |
1312 | + Q_PROPERTY(bool autofillEnabled READ autofillEnabled WRITE setAutofillEnabled NOTIFY autofillEnabledChanged REVISION 4) |
1313 | + |
1314 | Q_ENUMS(CookiePolicy) |
1315 | Q_ENUMS(SessionCookieMode) |
1316 | |
1317 | @@ -173,6 +175,9 @@ class OXIDE_QTQUICK_EXPORT OxideQQuickWebContext : public QObject, |
1318 | bool doNotTrack() const; |
1319 | void setDoNotTrack(bool dnt); |
1320 | |
1321 | + bool autofillEnabled() const; |
1322 | + void setAutofillEnabled(bool enabled); |
1323 | + |
1324 | Q_SIGNALS: |
1325 | void productChanged(); |
1326 | void userAgentChanged(); |
1327 | @@ -196,6 +201,7 @@ class OXIDE_QTQUICK_EXPORT OxideQQuickWebContext : public QObject, |
1328 | Q_REVISION(3) void defaultVideoCaptureDeviceIdChanged(); |
1329 | Q_REVISION(3) void userAgentOverridesChanged(); |
1330 | Q_REVISION(3) void doNotTrackEnabledChanged(); |
1331 | + Q_REVISION(4) void autofillEnabledChanged(); |
1332 | |
1333 | protected: |
1334 | // QQmlParserStatus implementation |
1335 | diff --git a/qt/quick/qquick_legacy_auxiliary_ui_factory.cc b/qt/quick/qquick_legacy_auxiliary_ui_factory.cc |
1336 | index c0084c2..e50b6c3 100644 |
1337 | --- a/qt/quick/qquick_legacy_auxiliary_ui_factory.cc |
1338 | +++ b/qt/quick/qquick_legacy_auxiliary_ui_factory.cc |
1339 | @@ -1,5 +1,5 @@ |
1340 | // vim:expandtab:shiftwidth=2:tabstop=2: |
1341 | -// Copyright (C) 2016 Canonical Ltd. |
1342 | +// Copyright (C) 2016-2017 Canonical Ltd. |
1343 | |
1344 | // This library is free software; you can redistribute it and/or |
1345 | // modify it under the terms of the GNU Lesser General Public |
1346 | @@ -21,6 +21,7 @@ |
1347 | |
1348 | #include "qt/core/glue/javascript_dialog_type.h" |
1349 | #include "qt/core/glue/touch_editing_menu.h" |
1350 | +#include "qt/core/glue/web_autofill_popup.h" |
1351 | |
1352 | #include "qquick_legacy_alert_dialog.h" |
1353 | #include "qquick_legacy_before_unload_dialog.h" |
1354 | @@ -31,11 +32,13 @@ |
1355 | namespace oxide { |
1356 | namespace qquick { |
1357 | |
1358 | +using qt::AutofillSuggestion; |
1359 | using qt::EditCapabilityFlags; |
1360 | using qt::JavaScriptDialogClient; |
1361 | using qt::JavaScriptDialogType; |
1362 | using qt::MenuItem; |
1363 | using qt::TouchEditingMenuClient; |
1364 | +using qt::WebAutofillPopupClient; |
1365 | using qt::WebContextMenuClient; |
1366 | using qt::WebContextMenuParams; |
1367 | |
1368 | @@ -52,6 +55,15 @@ LegacyAuxiliaryUIFactory::CreateWebContextMenu( |
1369 | new LegacyWebContextMenu(item_, context_menu_, params, client)); |
1370 | } |
1371 | |
1372 | +std::unique_ptr<qt::WebAutofillPopup> |
1373 | +LegacyAuxiliaryUIFactory::CreateWebAutofillPopup( |
1374 | + const std::vector<AutofillSuggestion>& suggestions, |
1375 | + const QRectF& bounds, |
1376 | + WebAutofillPopupClient* client) { |
1377 | + Q_ASSERT(0); |
1378 | + return nullptr; |
1379 | +} |
1380 | + |
1381 | std::unique_ptr<qt::TouchEditingMenu> |
1382 | LegacyAuxiliaryUIFactory::CreateTouchEditingMenu( |
1383 | EditCapabilityFlags edit_flags, |
1384 | diff --git a/qt/quick/qquick_legacy_auxiliary_ui_factory.h b/qt/quick/qquick_legacy_auxiliary_ui_factory.h |
1385 | index a7cec12..e969e6e 100644 |
1386 | --- a/qt/quick/qquick_legacy_auxiliary_ui_factory.h |
1387 | +++ b/qt/quick/qquick_legacy_auxiliary_ui_factory.h |
1388 | @@ -1,5 +1,5 @@ |
1389 | // vim:expandtab:shiftwidth=2:tabstop=2: |
1390 | -// Copyright (C) 2016 Canonical Ltd. |
1391 | +// Copyright (C) 2016-2017 Canonical Ltd. |
1392 | |
1393 | // This library is free software; you can redistribute it and/or |
1394 | // modify it under the terms of the GNU Lesser General Public |
1395 | @@ -59,6 +59,10 @@ class LegacyAuxiliaryUIFactory : public qt::AuxiliaryUIFactory { |
1396 | const qt::WebContextMenuParams& params, |
1397 | const std::vector<qt::MenuItem>& items, |
1398 | qt::WebContextMenuClient* client) override; |
1399 | + std::unique_ptr<qt::WebAutofillPopup> CreateWebAutofillPopup( |
1400 | + const std::vector<qt::AutofillSuggestion>& suggestions, |
1401 | + const QRectF& bounds, |
1402 | + qt::WebAutofillPopupClient* client) override; |
1403 | std::unique_ptr<qt::TouchEditingMenu> CreateTouchEditingMenu( |
1404 | qt::EditCapabilityFlags edit_flags, |
1405 | qt::TouchEditingMenuClient* client) override; |
1406 | diff --git a/qt/tests/qmltests/api/tst_WebContext_autofillEnabled.qml b/qt/tests/qmltests/api/tst_WebContext_autofillEnabled.qml |
1407 | new file mode 100644 |
1408 | index 0000000..7350196 |
1409 | --- /dev/null |
1410 | +++ b/qt/tests/qmltests/api/tst_WebContext_autofillEnabled.qml |
1411 | @@ -0,0 +1,38 @@ |
1412 | +import QtQuick 2.0 |
1413 | +import QtTest 1.0 |
1414 | +import com.canonical.Oxide 1.22 |
1415 | +import Oxide.testsupport 1.0 |
1416 | + |
1417 | +TestWebView { |
1418 | + id: webView |
1419 | + |
1420 | + SignalSpy { |
1421 | + id: spy |
1422 | + signalName: "autofillEnabledChanged" |
1423 | + } |
1424 | + |
1425 | + TestCase { |
1426 | + name: "WebContext_autofillEnabled" |
1427 | + when: windowShown |
1428 | + |
1429 | + function test_WebContext_autofillEnabled1_default() { |
1430 | + compare(webView.context.autofillEnabled, false, |
1431 | + "Autofill should be disabled by default"); |
1432 | + } |
1433 | + |
1434 | + function test_WebContext_autofillEnabled2_get_set() { |
1435 | + spy.target = webView.context; |
1436 | + |
1437 | + verify(!webView.context.autofillEnabled); |
1438 | + compare(spy.count, 0); |
1439 | + |
1440 | + webView.context.autofillEnabled = true; |
1441 | + compare(spy.count, 1); |
1442 | + verify(webView.context.autofillEnabled); |
1443 | + |
1444 | + webView.context.autofillEnabled = false; |
1445 | + compare(spy.count, 2); |
1446 | + verify(!webView.context.autofillEnabled); |
1447 | + } |
1448 | + } |
1449 | +} |
1450 | diff --git a/qt/tests/qmltests/ubuntu_ui/tst_WebViewAutofillPopup_autofill_profiles.html b/qt/tests/qmltests/ubuntu_ui/tst_WebViewAutofillPopup_autofill_profiles.html |
1451 | new file mode 100644 |
1452 | index 0000000..e28755c |
1453 | --- /dev/null |
1454 | +++ b/qt/tests/qmltests/ubuntu_ui/tst_WebViewAutofillPopup_autofill_profiles.html |
1455 | @@ -0,0 +1,23 @@ |
1456 | +<html> |
1457 | + <body> |
1458 | + <form action="empty.html"> |
1459 | + <input id="firstname" name="firstname" type="text" required autofocus /> |
1460 | + <br /> |
1461 | + <input id="lastname" name="lastname" type="text" required /> |
1462 | + <br /> |
1463 | + <input id="email" name="email" type="text" required /> |
1464 | + <br /> |
1465 | + <input id="country" name="country" type="text" required /> |
1466 | + <br /> |
1467 | + <input id="state" name="state" type="text" /> |
1468 | + <br /> |
1469 | + <input id="zipcode" name="zipcode" type="text" required /> |
1470 | + <br /> |
1471 | + <input id="city" name="city" type="text" required /> |
1472 | + <br /> |
1473 | + <input id="street" name="street" type="text" required /> |
1474 | + <br /> |
1475 | + <input type="submit" value="Submit" /> |
1476 | + </form> |
1477 | + </body> |
1478 | +</html> |
1479 | diff --git a/qt/tests/qmltests/ubuntu_ui/tst_WebViewAutofillPopup_autofill_profiles.qml b/qt/tests/qmltests/ubuntu_ui/tst_WebViewAutofillPopup_autofill_profiles.qml |
1480 | new file mode 100644 |
1481 | index 0000000..e65d221 |
1482 | --- /dev/null |
1483 | +++ b/qt/tests/qmltests/ubuntu_ui/tst_WebViewAutofillPopup_autofill_profiles.qml |
1484 | @@ -0,0 +1,300 @@ |
1485 | +import QtQuick 2.0 |
1486 | +import QtTest 1.0 |
1487 | +import com.canonical.Oxide 1.22 |
1488 | +import Oxide.Ubuntu 1.0 |
1489 | +import Oxide.testsupport 1.0 |
1490 | +import Ubuntu.Components 1.3 |
1491 | + |
1492 | +FocusScope { |
1493 | + width: 800 |
1494 | + height: 600 |
1495 | + |
1496 | + focus: true |
1497 | + |
1498 | + UbuntuTestWebView { |
1499 | + id: webView |
1500 | + objectName: "webView" |
1501 | + anchors.fill: parent |
1502 | + visible: false |
1503 | + } |
1504 | + |
1505 | + UbuntuTestWebView { |
1506 | + id: incognitoWebView |
1507 | + objectName: "incognitoWebView" |
1508 | + anchors.fill: parent |
1509 | + incognito: true |
1510 | + visible: false |
1511 | + } |
1512 | + |
1513 | + TestCase { |
1514 | + name: "WebViewAutofillPopup_autofill_profiles" |
1515 | + when: windowShown |
1516 | + |
1517 | + function loadForm(webView) { |
1518 | + webView.visible = true; |
1519 | + webView.focus = true; |
1520 | + webView.context.autofillEnabled = true; |
1521 | + webView.url = |
1522 | + "http://testsuite/tst_WebViewAutofillPopup_autofill_profiles.html"; |
1523 | + verify(webView.waitForLoadSucceeded()); |
1524 | + } |
1525 | + |
1526 | + function verify_field_focused(webView, field) { |
1527 | + verify(TestUtils.waitFor(function() { |
1528 | + return webView.getTestApi().evaluateCode( |
1529 | + "document.activeElement.id") == field; })); |
1530 | + } |
1531 | + |
1532 | + function compare_field_value(webView, field, value) { |
1533 | + verify(TestUtils.waitFor(function() { |
1534 | + return webView.getTestApi().evaluateCode( |
1535 | + "document.querySelector('#%1').value".arg(field)) == value; })); |
1536 | + } |
1537 | + |
1538 | + function typeStringInField(webView, string, field) { |
1539 | + verify_field_focused(webView, field); |
1540 | + for (var i = 0; i < string.length; ++i) { |
1541 | + keyClick(string[i]); |
1542 | + } |
1543 | + compare_field_value(webView, field, string); |
1544 | + } |
1545 | + |
1546 | + function inputAndValidateProfile(webView, data) { |
1547 | + var fields = ["firstname", "lastname", "email", "country", "state", |
1548 | + "zipcode", "city", "street"]; |
1549 | + for (var i = 0; i < fields.length; ++i) { |
1550 | + typeStringInField(webView, data[i], fields[i]); |
1551 | + keyClick(Qt.Key_Tab); |
1552 | + } |
1553 | + keyClick(Qt.Key_Enter); |
1554 | + verify(webView.waitForLoadSucceeded()); |
1555 | + loadForm(webView); |
1556 | + } |
1557 | + |
1558 | + function initTestCase() { |
1559 | + loadForm(webView); |
1560 | + |
1561 | + // Initial population of the autofill profiles database |
1562 | + var data = [ |
1563 | + ["John", "Doe", "john.doe@nospam.org", |
1564 | + "US", "New York", "10016", "NYC", "Park Avenue"], |
1565 | + ["John", "Lennon", "john@thebeatles.com", |
1566 | + "UK", "", "L25 6DA", "Liverpool", "Beaconsfield Road"], |
1567 | + ["Bruce", "Lee", "bruce@lee.com", |
1568 | + "US", "California", "94108", "San Francisco", "Joice Street"], |
1569 | + ]; |
1570 | + for (var i = 0; i < data.length; ++i) { |
1571 | + inputAndValidateProfile(webView, data[i]); |
1572 | + } |
1573 | + } |
1574 | + |
1575 | + function getAutofillPopup(webView) { |
1576 | + return TestSupport.findItemInScene( |
1577 | + TestWindow.rootItem, "%1_WebAutofillPopup".arg(webView.objectName)); |
1578 | + } |
1579 | + |
1580 | + function waitForAutofillPopupToClose(webView) { |
1581 | + var popup = getAutofillPopup(webView); |
1582 | + if (!popup) { |
1583 | + return true; |
1584 | + } |
1585 | + |
1586 | + var helper = TestSupport.createQObjectTestHelper(popup); |
1587 | + |
1588 | + return TestUtils.waitFor(function() { |
1589 | + return !getAutofillPopup(webView); }) && |
1590 | + TestUtils.waitFor(function() { return helper.destroyed; }); |
1591 | + } |
1592 | + |
1593 | + function waitForAutofillPopup(webView, timeout) { |
1594 | + return TestUtils.waitFor(function() { |
1595 | + return !!getAutofillPopup(webView) && |
1596 | + getAutofillPopup(webView).visible; }, |
1597 | + timeout); |
1598 | + } |
1599 | + |
1600 | + function getSuggestion(webView, index) { |
1601 | + return TestSupport.findItemInScene( |
1602 | + TestWindow.rootItem, |
1603 | + "%1_WebAutofillPopup_item%2".arg(webView.objectName).arg(index)); |
1604 | + } |
1605 | + |
1606 | + function compareBoundsToClientRect(bounds, rect) { |
1607 | + compare(bounds.x, rect.x); |
1608 | + compare(bounds.y, rect.y); |
1609 | + compare(bounds.width, rect.width); |
1610 | + compare(bounds.height, rect.height); |
1611 | + } |
1612 | + |
1613 | + function init() { |
1614 | + loadForm(webView); |
1615 | + } |
1616 | + |
1617 | + function get_webviews_data() { |
1618 | + var data = [ { webView: webView } ]; |
1619 | + if (incognitoWebView.incognito) { |
1620 | + // When run in single process mode, incognito cannot be set |
1621 | + data.push({ webView: incognitoWebView }); |
1622 | + } |
1623 | + return data; |
1624 | + } |
1625 | + |
1626 | + function test_initial_state_data() { |
1627 | + return get_webviews_data(); |
1628 | + } |
1629 | + |
1630 | + function test_initial_state(data) { |
1631 | + loadForm(data.webView); |
1632 | + typeStringInField(data.webView, "jo", "firstname"); |
1633 | + var popup = getAutofillPopup(data.webView); |
1634 | + var r = data.webView.getTestApi() |
1635 | + .getBoundingClientRectForSelector("#firstname"); |
1636 | + compareBoundsToClientRect(popup.elementBounds, r); |
1637 | + compare(popup.currentIndex, -1); |
1638 | + compare(popup.count, 2); |
1639 | + compare(getSuggestion(data.webView, 0).value, "John"); |
1640 | + compare(getSuggestion(data.webView, 1).value, "John"); |
1641 | + data.webView.visible = false; |
1642 | + } |
1643 | + |
1644 | + function test_toggle_autofillEnabled_data() { |
1645 | + return get_webviews_data(); |
1646 | + } |
1647 | + |
1648 | + function test_toggle_autofillEnabled(data) { |
1649 | + loadForm(data.webView); |
1650 | + typeStringInField(data.webView, "j", "firstname"); |
1651 | + verify(waitForAutofillPopup(data.webView)); |
1652 | + keyClick(Qt.Key_Backspace); |
1653 | + verify(waitForAutofillPopupToClose(data.webView)); |
1654 | + |
1655 | + data.webView.context.autofillEnabled = false; |
1656 | + typeStringInField(data.webView, "j", "firstname"); |
1657 | + verify(!waitForAutofillPopup(data.webView, 1000)); |
1658 | + keyClick(Qt.Key_Backspace); |
1659 | + |
1660 | + data.webView.context.autofillEnabled = true; |
1661 | + typeStringInField(data.webView, "j", "firstname"); |
1662 | + verify(waitForAutofillPopup(data.webView)); |
1663 | + data.webView.visible = false; |
1664 | + } |
1665 | + |
1666 | + function test_escape_dismisses_popup_and_resets_field_value_data() { |
1667 | + return get_webviews_data(); |
1668 | + } |
1669 | + |
1670 | + function test_escape_dismisses_popup_and_resets_field_value(data) { |
1671 | + loadForm(data.webView); |
1672 | + typeStringInField(data.webView, "br", "firstname"); |
1673 | + verify(waitForAutofillPopup(data.webView)); |
1674 | + var popup = getAutofillPopup(data.webView); |
1675 | + compare(popup.count, 1); |
1676 | + compare(getSuggestion(data.webView, 0).value, "Bruce"); |
1677 | + keyClick(Qt.Key_Down); |
1678 | + tryCompare(popup, "currentIndex", 0); |
1679 | + keyClick(Qt.Key_Escape); |
1680 | + verify(waitForAutofillPopupToClose(data.webView)); |
1681 | + compare_field_value(data.webView, "firstname", "br"); |
1682 | + compare_field_value(data.webView, "lastname", ""); |
1683 | + compare_field_value(data.webView, "email", ""); |
1684 | + compare_field_value(data.webView, "country", ""); |
1685 | + compare_field_value(data.webView, "state", ""); |
1686 | + compare_field_value(data.webView, "zipcode", ""); |
1687 | + compare_field_value(data.webView, "city", ""); |
1688 | + compare_field_value(data.webView, "street", ""); |
1689 | + data.webView.visible = false; |
1690 | + } |
1691 | + |
1692 | + function test_validate_suggestion_with_mouse_data() { |
1693 | + return get_webviews_data(); |
1694 | + } |
1695 | + |
1696 | + function test_validate_suggestion_with_mouse(data) { |
1697 | + loadForm(data.webView); |
1698 | + typeStringInField(data.webView, "br", "firstname"); |
1699 | + verify(waitForAutofillPopup(data.webView)); |
1700 | + var popup = getAutofillPopup(data.webView); |
1701 | + compare(popup.count, 1); |
1702 | + compare(getSuggestion(data.webView, 0).value, "Bruce"); |
1703 | + var item = getSuggestion(data.webView, 0); |
1704 | + mouseClick(item); |
1705 | + verify(waitForAutofillPopupToClose(data.webView)); |
1706 | + verify_field_focused(data.webView, "firstname"); |
1707 | + compare_field_value(data.webView, "firstname", "Bruce"); |
1708 | + compare_field_value(data.webView, "lastname", "Lee"); |
1709 | + compare_field_value(data.webView, "email", "bruce@lee.com"); |
1710 | + compare_field_value(data.webView, "state", "California"); |
1711 | + compare_field_value(data.webView, "zipcode", "94108"); |
1712 | + compare_field_value(data.webView, "city", "San Francisco"); |
1713 | + compare_field_value(data.webView, "street", "Joice Street"); |
1714 | + data.webView.visible = false; |
1715 | + } |
1716 | + |
1717 | + function test_validate_suggestion_with_keyboard_data() { |
1718 | + return [ |
1719 | + { webView: webView, key: Qt.Key_Enter, focus: "lastname" }, |
1720 | + { webView: webView, key: Qt.Key_Return, focus: "lastname" }, |
1721 | + { webView: webView, key: Qt.Key_Tab, focus: "email" }, |
1722 | + { webView: incognitoWebView, key: Qt.Key_Enter, focus: "lastname" }, |
1723 | + { webView: incognitoWebView, key: Qt.Key_Return, focus: "lastname" }, |
1724 | + { webView: incognitoWebView, key: Qt.Key_Tab, focus: "email" }, |
1725 | + ]; |
1726 | + } |
1727 | + |
1728 | + function test_validate_suggestion_with_keyboard(data) { |
1729 | + loadForm(data.webView); |
1730 | + keyClick(Qt.Key_Tab); |
1731 | + typeStringInField(data.webView, "len", "lastname"); |
1732 | + var popup = getAutofillPopup(data.webView); |
1733 | + compare(popup.count, 1); |
1734 | + compare(getSuggestion(data.webView, 0).value, "Lennon"); |
1735 | + keyClick(Qt.Key_Down); |
1736 | + tryCompare(popup, "currentIndex", 0); |
1737 | + keyClick(data.key); |
1738 | + verify(waitForAutofillPopupToClose(data.webView)); |
1739 | + verify_field_focused(data.webView, data.focus); |
1740 | + compare_field_value(data.webView, "firstname", "John"); |
1741 | + compare_field_value(data.webView, "lastname", "Lennon"); |
1742 | + compare_field_value(data.webView, "email", "john@thebeatles.com"); |
1743 | + compare_field_value(data.webView, "state", ""); |
1744 | + compare_field_value(data.webView, "zipcode", "L25 6DA"); |
1745 | + compare_field_value(data.webView, "city", "Liverpool"); |
1746 | + compare_field_value(data.webView, "street", "Beaconsfield Road"); |
1747 | + data.webView.visible = false; |
1748 | + } |
1749 | + |
1750 | + function test_shiftdel_deletes_suggestion() { |
1751 | + var data = ["Paul", "McCartney", "paul@thebeatles.com", |
1752 | + "UK", "", "L18 1DE", "Liverpool", "Penny Lane"]; |
1753 | + inputAndValidateProfile(webView, data); |
1754 | + for (var i = 0; i < 6; ++i) { |
1755 | + keyClick(Qt.Key_Tab); |
1756 | + } |
1757 | + typeStringInField(webView, "Live", "city"); |
1758 | + verify(waitForAutofillPopup(webView)); |
1759 | + var popup = getAutofillPopup(webView); |
1760 | + compare(popup.count, 2); |
1761 | + compare(getSuggestion(webView, 0).label, "Penny Lane"); |
1762 | + compare(getSuggestion(webView, 1).label, "Beaconsfield Road"); |
1763 | + keyClick(Qt.Key_Down); |
1764 | + tryCompare(popup, "currentIndex", 0); |
1765 | + keyClick(Qt.Key_Delete, Qt.ShiftModifier); |
1766 | + tryCompare(popup, "currentIndex", -1); |
1767 | + tryCompare(popup, "count", 1); |
1768 | + compare(getSuggestion(webView, 0).label, "Beaconsfield Road"); |
1769 | + } |
1770 | + |
1771 | + function test_incognito_profile_not_saved() { |
1772 | + if (!incognitoWebView.incognito) { |
1773 | + skip("WebView.incognito cannot be set in single process mode"); |
1774 | + } |
1775 | + loadForm(incognitoWebView); |
1776 | + var data = ["Paul", "McCartney", "paul@thebeatles.com", |
1777 | + "UK", "", "L18 1DE", "Liverpool", "Penny Lane"]; |
1778 | + inputAndValidateProfile(incognitoWebView, data); |
1779 | + typeStringInField(incognitoWebView, "P", "firstname"); |
1780 | + verify(!waitForAutofillPopup(incognitoWebView, 1000)); |
1781 | + incognitoWebView.visible = false; |
1782 | + } |
1783 | + } |
1784 | +} |
1785 | diff --git a/qt/tests/qmltests/ubuntu_ui/tst_WebViewAutofillPopup_datalist.html b/qt/tests/qmltests/ubuntu_ui/tst_WebViewAutofillPopup_datalist.html |
1786 | new file mode 100644 |
1787 | index 0000000..cded135 |
1788 | --- /dev/null |
1789 | +++ b/qt/tests/qmltests/ubuntu_ui/tst_WebViewAutofillPopup_datalist.html |
1790 | @@ -0,0 +1,37 @@ |
1791 | +<html> |
1792 | + <body> |
1793 | + <form action="tst_WebViewAutofillPopup_datalist.html"> |
1794 | + <input id="static" name="static" list="staticdatalist" type="text" autofocus /> |
1795 | + <datalist id="staticdatalist"> |
1796 | + <option>bar</option> |
1797 | + <option>baz</option> |
1798 | + <option>qux</option> |
1799 | + </datalist> |
1800 | + <br /> |
1801 | + <input id="static2" name="static2" list="staticdatalist" type="text" /> |
1802 | + <br /> |
1803 | + <input id="dynamic" name="dynamic" list="dynamicdatalist" type="text" /> |
1804 | + <datalist id="dynamicdatalist"></datalist> |
1805 | + <script> |
1806 | + function createDatalist() { |
1807 | + var value = document.getElementById("dynamic").value; |
1808 | + var list = []; |
1809 | + if (value == "f") { |
1810 | + list = ["foo", "flip"]; |
1811 | + } else if (value == "b") { |
1812 | + list = ["bar", "beard", "beam"]; |
1813 | + } |
1814 | + var datalist = document.getElementById("dynamicdatalist"); |
1815 | + datalist.innerHTML = ""; |
1816 | + for (var i = 0; i < list.length; ++i) { |
1817 | + var option = document.createElement('option'); |
1818 | + option.value = list[i]; |
1819 | + datalist.appendChild(option); |
1820 | + } |
1821 | + } |
1822 | + document.getElementById("dynamic").addEventListener("input", createDatalist); |
1823 | + </script> |
1824 | + <input type="submit" value="Submit" /> |
1825 | + </form> |
1826 | + </body> |
1827 | +</html> |
1828 | diff --git a/qt/tests/qmltests/ubuntu_ui/tst_WebViewAutofillPopup_datalist.qml b/qt/tests/qmltests/ubuntu_ui/tst_WebViewAutofillPopup_datalist.qml |
1829 | new file mode 100644 |
1830 | index 0000000..1288857 |
1831 | --- /dev/null |
1832 | +++ b/qt/tests/qmltests/ubuntu_ui/tst_WebViewAutofillPopup_datalist.qml |
1833 | @@ -0,0 +1,157 @@ |
1834 | +import QtQuick 2.0 |
1835 | +import QtTest 1.0 |
1836 | +import com.canonical.Oxide 1.22 |
1837 | +import Oxide.Ubuntu 1.0 |
1838 | +import Oxide.testsupport 1.0 |
1839 | +import Ubuntu.Components 1.3 |
1840 | + |
1841 | +UbuntuTestWebView { |
1842 | + id: webView |
1843 | + objectName: "webView" |
1844 | + |
1845 | + width: 800 |
1846 | + height: 600 |
1847 | + |
1848 | + focus: true |
1849 | + |
1850 | + TestCase { |
1851 | + name: "WebViewAutofillPopup_datalist" |
1852 | + when: windowShown |
1853 | + |
1854 | + function verify_field_focused(field) { |
1855 | + verify(TestUtils.waitFor(function() { |
1856 | + return webView.getTestApi().evaluateCode( |
1857 | + "document.activeElement.id") == field; })); |
1858 | + } |
1859 | + |
1860 | + function compare_field_value(field, value) { |
1861 | + verify(TestUtils.waitFor(function() { |
1862 | + return webView.getTestApi().evaluateCode( |
1863 | + "document.querySelector('#%1').value".arg(field)) == value; })); |
1864 | + } |
1865 | + |
1866 | + function typeStringInField(string, field) { |
1867 | + verify_field_focused(field); |
1868 | + for (var i = 0; i < string.length; ++i) { |
1869 | + keyClick(string[i]); |
1870 | + } |
1871 | + compare_field_value(field, string); |
1872 | + } |
1873 | + |
1874 | + function initTestCase() { |
1875 | + webView.context.autofillEnabled = true; |
1876 | + } |
1877 | + |
1878 | + function getAutofillPopup() { |
1879 | + return TestSupport.findItemInScene(TestWindow.rootItem, |
1880 | + "webView_WebAutofillPopup"); |
1881 | + } |
1882 | + |
1883 | + function waitForAutofillPopupToClose() { |
1884 | + var popup = getAutofillPopup(); |
1885 | + if (!popup) { |
1886 | + return true; |
1887 | + } |
1888 | + |
1889 | + var helper = TestSupport.createQObjectTestHelper(popup); |
1890 | + |
1891 | + return TestUtils.waitFor(function() { return !getAutofillPopup(); }) && |
1892 | + TestUtils.waitFor(function() { return helper.destroyed; }); |
1893 | + } |
1894 | + |
1895 | + function waitForAutofillPopup() { |
1896 | + return TestUtils.waitFor(function() { |
1897 | + return !!getAutofillPopup() && getAutofillPopup().visible; }); |
1898 | + } |
1899 | + |
1900 | + function getSuggestion(index) { |
1901 | + return TestSupport.findItemInScene( |
1902 | + TestWindow.rootItem, "webView_WebAutofillPopup_item%1".arg(index)); |
1903 | + } |
1904 | + |
1905 | + function init() { |
1906 | + webView.url = |
1907 | + "http://testsuite/tst_WebViewAutofillPopup_datalist.html"; |
1908 | + verify(webView.waitForLoadSucceeded()); |
1909 | + } |
1910 | + |
1911 | + function test_static_datalist() { |
1912 | + typeStringInField("b", "static"); |
1913 | + verify(waitForAutofillPopup()); |
1914 | + var popup = getAutofillPopup(); |
1915 | + compare(popup.count, 2); |
1916 | + compare(getSuggestion(0).value, "bar"); |
1917 | + compare(getSuggestion(1).value, "baz"); |
1918 | + keyClick("a"); |
1919 | + compare(popup.count, 2); |
1920 | + keyClick("e"); |
1921 | + verify(waitForAutofillPopupToClose()); |
1922 | + |
1923 | + keyClick(Qt.Key_Backspace); |
1924 | + verify(waitForAutofillPopup()); |
1925 | + popup = getAutofillPopup(); |
1926 | + compare(popup.count, 2); |
1927 | + keyClick(Qt.Key_Backspace); |
1928 | + keyClick(Qt.Key_Backspace); |
1929 | + verify(waitForAutofillPopupToClose()); |
1930 | + |
1931 | + typeStringInField("q", "static"); |
1932 | + verify(waitForAutofillPopup()); |
1933 | + popup = getAutofillPopup(); |
1934 | + compare(popup.count, 1); |
1935 | + compare(getSuggestion(0).value, "qux"); |
1936 | + compare(popup.currentIndex, -1); |
1937 | + keyClick(Qt.Key_Down); |
1938 | + compare(popup.currentIndex, 0); |
1939 | + keyClick(Qt.Key_Return); |
1940 | + verify(waitForAutofillPopupToClose()); |
1941 | + compare_field_value("static", "qux"); |
1942 | + } |
1943 | + |
1944 | + function test_combined_datalist_autofill_suggestions() { |
1945 | + keyClick(Qt.Key_Tab); |
1946 | + typeStringInField("quantal", "static2"); |
1947 | + keyClick(Qt.Key_Enter); |
1948 | + verify(webView.waitForLoadSucceeded()); |
1949 | + |
1950 | + keyClick(Qt.Key_Tab); |
1951 | + typeStringInField("q", "static2"); |
1952 | + verify(waitForAutofillPopup()); |
1953 | + var popup = getAutofillPopup(); |
1954 | + compare(popup.count, 2); |
1955 | + compare(getSuggestion(0).value, "qux"); |
1956 | + compare(getSuggestion(1).value, "quantal"); |
1957 | + } |
1958 | + |
1959 | + function test_dynamic_datalist() { |
1960 | + keyClick(Qt.Key_Tab); |
1961 | + keyClick(Qt.Key_Tab); |
1962 | + typeStringInField("f", "dynamic"); |
1963 | + verify(waitForAutofillPopup()); |
1964 | + var popup = getAutofillPopup(); |
1965 | + compare(popup.count, 2); |
1966 | + compare(getSuggestion(0).value, "foo"); |
1967 | + compare(getSuggestion(1).value, "flip"); |
1968 | + keyClick("a"); |
1969 | + verify(waitForAutofillPopupToClose()); |
1970 | + keyClick(Qt.Key_Backspace); |
1971 | + verify(waitForAutofillPopup()); |
1972 | + keyClick(Qt.Key_Backspace); |
1973 | + verify(waitForAutofillPopupToClose()); |
1974 | + compare_field_value("dynamic", ""); |
1975 | + |
1976 | + typeStringInField("b", "dynamic"); |
1977 | + verify(waitForAutofillPopup()); |
1978 | + popup = getAutofillPopup(); |
1979 | + compare(popup.count, 3); |
1980 | + compare(getSuggestion(0).value, "bar"); |
1981 | + compare(getSuggestion(1).value, "beard"); |
1982 | + compare(getSuggestion(2).value, "beam"); |
1983 | + keyClick(Qt.Key_Up); |
1984 | + compare(popup.currentIndex, 2); |
1985 | + keyClick(Qt.Key_Enter); |
1986 | + verify(waitForAutofillPopupToClose()); |
1987 | + compare_field_value("dynamic", "beam"); |
1988 | + } |
1989 | + } |
1990 | +} |
1991 | diff --git a/qt/tests/qmltests/ubuntu_ui/tst_WebViewAutofillPopup_passwords.html b/qt/tests/qmltests/ubuntu_ui/tst_WebViewAutofillPopup_passwords.html |
1992 | new file mode 100644 |
1993 | index 0000000..8a712e6 |
1994 | --- /dev/null |
1995 | +++ b/qt/tests/qmltests/ubuntu_ui/tst_WebViewAutofillPopup_passwords.html |
1996 | @@ -0,0 +1,11 @@ |
1997 | +<html> |
1998 | + <body> |
1999 | + <form action="empty.html"> |
2000 | + <input id="username" name="username" type="text" required autofocus /> |
2001 | + <br /> |
2002 | + <input id="password" name="password" type="password" required /> |
2003 | + <br /> |
2004 | + <input type="submit" value="Submit" /> |
2005 | + </form> |
2006 | + </body> |
2007 | +</html> |
2008 | diff --git a/qt/tests/qmltests/ubuntu_ui/tst_WebViewAutofillPopup_passwords.qml b/qt/tests/qmltests/ubuntu_ui/tst_WebViewAutofillPopup_passwords.qml |
2009 | new file mode 100644 |
2010 | index 0000000..b1aede3 |
2011 | --- /dev/null |
2012 | +++ b/qt/tests/qmltests/ubuntu_ui/tst_WebViewAutofillPopup_passwords.qml |
2013 | @@ -0,0 +1,105 @@ |
2014 | +import QtQuick 2.0 |
2015 | +import QtTest 1.0 |
2016 | +import com.canonical.Oxide 1.22 |
2017 | +import Oxide.Ubuntu 1.0 |
2018 | +import Oxide.testsupport 1.0 |
2019 | +import Ubuntu.Components 1.3 |
2020 | + |
2021 | +UbuntuTestWebView { |
2022 | + id: webView |
2023 | + objectName: "webView" |
2024 | + |
2025 | + width: 800 |
2026 | + height: 600 |
2027 | + |
2028 | + focus: true |
2029 | + |
2030 | + TestCase { |
2031 | + name: "WebViewAutofillPopup_passwords" |
2032 | + when: windowShown |
2033 | + |
2034 | + function loadForm() { |
2035 | + webView.url = |
2036 | + "http://testsuite/tst_WebViewAutofillPopup_passwords.html"; |
2037 | + verify(webView.waitForLoadSucceeded()); |
2038 | + } |
2039 | + |
2040 | + function verify_field_focused(field) { |
2041 | + verify(TestUtils.waitFor(function() { |
2042 | + return webView.getTestApi().evaluateCode( |
2043 | + "document.activeElement.id") == field; })); |
2044 | + } |
2045 | + |
2046 | + function compare_field_value(field, value) { |
2047 | + verify(TestUtils.waitFor(function() { |
2048 | + return webView.getTestApi().evaluateCode( |
2049 | + "document.querySelector('#%1').value".arg(field)) == value; })); |
2050 | + } |
2051 | + |
2052 | + function typeStringInField(string, field) { |
2053 | + verify_field_focused(field); |
2054 | + for (var i = 0; i < string.length; ++i) { |
2055 | + keyClick(string[i]); |
2056 | + } |
2057 | + compare_field_value(field, string); |
2058 | + } |
2059 | + |
2060 | + function initTestCase() { |
2061 | + webView.context.autofillEnabled = true; |
2062 | + } |
2063 | + |
2064 | + function getAutofillPopup() { |
2065 | + return TestSupport.findItemInScene(TestWindow.rootItem, |
2066 | + "webView_WebAutofillPopup"); |
2067 | + } |
2068 | + |
2069 | + function waitForAutofillPopupToClose() { |
2070 | + var popup = getAutofillPopup(); |
2071 | + if (!popup) { |
2072 | + return true; |
2073 | + } |
2074 | + |
2075 | + var helper = TestSupport.createQObjectTestHelper(popup); |
2076 | + |
2077 | + return TestUtils.waitFor(function() { return !getAutofillPopup(); }) && |
2078 | + TestUtils.waitFor(function() { return helper.destroyed; }); |
2079 | + } |
2080 | + |
2081 | + function waitForAutofillPopup(timeout) { |
2082 | + return TestUtils.waitFor(function() { |
2083 | + return !!getAutofillPopup() && getAutofillPopup().visible; }, |
2084 | + timeout); |
2085 | + } |
2086 | + |
2087 | + function getSuggestion(index) { |
2088 | + return TestSupport.findItemInScene( |
2089 | + TestWindow.rootItem, "webView_WebAutofillPopup_item%1".arg(index)); |
2090 | + } |
2091 | + |
2092 | + function init() { |
2093 | + loadForm(); |
2094 | + } |
2095 | + |
2096 | + // Autofill is not implemented yet for passwords |
2097 | + function test_passwords_not_autofilled() { |
2098 | + typeStringInField("myuser", "username"); |
2099 | + keyClick(Qt.Key_Tab); |
2100 | + typeStringInField("mypass", "password"); |
2101 | + keyClick(Qt.Key_Enter); |
2102 | + verify(webView.waitForLoadSucceeded()); |
2103 | + |
2104 | + loadForm(); |
2105 | + typeStringInField("my", "username"); |
2106 | + verify(waitForAutofillPopup()); |
2107 | + var popup = getAutofillPopup(); |
2108 | + compare(popup.count, 1); |
2109 | + compare(getSuggestion(0).value, "myuser"); |
2110 | + keyClick(Qt.Key_Down); |
2111 | + compare(popup.currentIndex, 0); |
2112 | + keyClick(Qt.Key_Enter); |
2113 | + verify(waitForAutofillPopupToClose()); |
2114 | + compare_field_value("username", "myuser"); |
2115 | + compare_field_value("password", ""); |
2116 | + } |
2117 | + } |
2118 | +} |
2119 | diff --git a/qt/tests/qmltests/ubuntu_ui/tst_WebViewAutofillPopup_single_fields.html b/qt/tests/qmltests/ubuntu_ui/tst_WebViewAutofillPopup_single_fields.html |
2120 | new file mode 100644 |
2121 | index 0000000..7389fe5 |
2122 | --- /dev/null |
2123 | +++ b/qt/tests/qmltests/ubuntu_ui/tst_WebViewAutofillPopup_single_fields.html |
2124 | @@ -0,0 +1,11 @@ |
2125 | +<html> |
2126 | + <body> |
2127 | + <form action="empty.html"> |
2128 | + <input id="field1" name="field1" type="text" autofocus /> |
2129 | + <br /> |
2130 | + <input id="field2" name="field2" type="text" /> |
2131 | + <br /> |
2132 | + <input type="submit" value="Submit" /> |
2133 | + </form> |
2134 | + </body> |
2135 | +</html> |
2136 | diff --git a/qt/tests/qmltests/ubuntu_ui/tst_WebViewAutofillPopup_single_fields.qml b/qt/tests/qmltests/ubuntu_ui/tst_WebViewAutofillPopup_single_fields.qml |
2137 | new file mode 100644 |
2138 | index 0000000..26a88fb |
2139 | --- /dev/null |
2140 | +++ b/qt/tests/qmltests/ubuntu_ui/tst_WebViewAutofillPopup_single_fields.qml |
2141 | @@ -0,0 +1,359 @@ |
2142 | +import QtQuick 2.0 |
2143 | +import QtTest 1.0 |
2144 | +import com.canonical.Oxide 1.22 |
2145 | +import Oxide.Ubuntu 1.0 |
2146 | +import Oxide.testsupport 1.0 |
2147 | +import Ubuntu.Components 1.3 |
2148 | + |
2149 | +FocusScope { |
2150 | + id: testRoot |
2151 | + |
2152 | + width: 800 |
2153 | + height: 600 |
2154 | + |
2155 | + focus: true |
2156 | + |
2157 | + UbuntuTestWebView { |
2158 | + id: webView |
2159 | + objectName: "webView" |
2160 | + anchors.fill: parent |
2161 | + visible: false |
2162 | + } |
2163 | + |
2164 | + UbuntuTestWebView { |
2165 | + id: incognitoWebView |
2166 | + objectName: "incognitoWebView" |
2167 | + anchors.fill: parent |
2168 | + incognito: true |
2169 | + visible: false |
2170 | + } |
2171 | + |
2172 | + Component { |
2173 | + id: webViewFactory |
2174 | + UbuntuTestWebView { |
2175 | + objectName: "webView2" |
2176 | + anchors.fill: parent |
2177 | + } |
2178 | + } |
2179 | + |
2180 | + TestCase { |
2181 | + name: "WebViewAutofillPopup_single_fields" |
2182 | + when: windowShown |
2183 | + |
2184 | + function loadForm(webView) { |
2185 | + webView.visible = true; |
2186 | + webView.focus = true; |
2187 | + webView.context.autofillEnabled = true; |
2188 | + webView.url = |
2189 | + "http://testsuite/tst_WebViewAutofillPopup_single_fields.html"; |
2190 | + verify(webView.waitForLoadSucceeded()); |
2191 | + } |
2192 | + |
2193 | + function verify_field_focused(webView, field) { |
2194 | + verify(TestUtils.waitFor(function() { |
2195 | + return webView.getTestApi().evaluateCode( |
2196 | + "document.activeElement.id") == field; })); |
2197 | + } |
2198 | + |
2199 | + function compare_field_value(webView, field, value) { |
2200 | + verify(TestUtils.waitFor(function() { |
2201 | + return webView.getTestApi().evaluateCode( |
2202 | + "document.querySelector('#%1').value".arg(field)) == value; })); |
2203 | + } |
2204 | + |
2205 | + function typeStringInField(webView, string, field) { |
2206 | + verify_field_focused(webView, field); |
2207 | + for (var i = 0; i < string.length; ++i) { |
2208 | + keyClick(string[i]); |
2209 | + } |
2210 | + compare_field_value(webView, field, string); |
2211 | + } |
2212 | + |
2213 | + function initTestCase() { |
2214 | + loadForm(webView); |
2215 | + // Initial population of the autofill database |
2216 | + var data = ["foo", "for", "four"]; |
2217 | + for (var i = 0; i < data.length; ++i) { |
2218 | + webView.url = |
2219 | + "http://testsuite/tst_WebViewAutofillPopup_single_fields.html"; |
2220 | + verify(webView.waitForLoadSucceeded()); |
2221 | + typeStringInField(webView, data[i], "field1"); |
2222 | + keyClick(Qt.Key_Enter); |
2223 | + verify(webView.waitForLoadSucceeded()); |
2224 | + } |
2225 | + } |
2226 | + |
2227 | + function getAutofillPopup(webView) { |
2228 | + return TestSupport.findItemInScene( |
2229 | + TestWindow.rootItem, "%1_WebAutofillPopup".arg(webView.objectName)); |
2230 | + } |
2231 | + |
2232 | + function waitForAutofillPopupToClose(webView) { |
2233 | + var popup = getAutofillPopup(webView); |
2234 | + if (!popup) { |
2235 | + return true; |
2236 | + } |
2237 | + |
2238 | + var helper = TestSupport.createQObjectTestHelper(popup); |
2239 | + |
2240 | + return TestUtils.waitFor(function() { |
2241 | + return !getAutofillPopup(webView); }) && |
2242 | + TestUtils.waitFor(function() { return helper.destroyed; }); |
2243 | + } |
2244 | + |
2245 | + function waitForAutofillPopup(webView, timeout) { |
2246 | + return TestUtils.waitFor(function() { |
2247 | + return !!getAutofillPopup(webView) && |
2248 | + getAutofillPopup(webView).visible; }, |
2249 | + timeout); |
2250 | + } |
2251 | + |
2252 | + function getSuggestion(webView, index) { |
2253 | + return TestSupport.findItemInScene( |
2254 | + TestWindow.rootItem, |
2255 | + "%1_WebAutofillPopup_item%2".arg(webView.objectName).arg(index)); |
2256 | + } |
2257 | + |
2258 | + function compareBoundsToClientRect(bounds, rect) { |
2259 | + compare(bounds.x, rect.x); |
2260 | + compare(bounds.y, rect.y); |
2261 | + compare(bounds.width, rect.width); |
2262 | + compare(bounds.height, rect.height); |
2263 | + } |
2264 | + |
2265 | + function init() { |
2266 | + loadForm(webView); |
2267 | + } |
2268 | + |
2269 | + function get_webviews_data() { |
2270 | + var data = [ { webView: webView } ]; |
2271 | + if (incognitoWebView.incognito) { |
2272 | + // When run in single process mode, incognito cannot be set |
2273 | + data.push({ webView: incognitoWebView }); |
2274 | + } |
2275 | + return data; |
2276 | + } |
2277 | + |
2278 | + function test_initial_state_data() { |
2279 | + return get_webviews_data(); |
2280 | + } |
2281 | + |
2282 | + function test_initial_state(data) { |
2283 | + loadForm(data.webView); |
2284 | + typeStringInField(data.webView, "f", "field1"); |
2285 | + verify(waitForAutofillPopup(data.webView)); |
2286 | + var popup = getAutofillPopup(data.webView); |
2287 | + var r = |
2288 | + data.webView.getTestApi().getBoundingClientRectForSelector("#field1"); |
2289 | + compareBoundsToClientRect(popup.elementBounds, r); |
2290 | + compare(popup.currentIndex, -1); |
2291 | + compare(popup.count, 3); |
2292 | + compare(getSuggestion(data.webView, 0).value, "foo"); |
2293 | + compare(getSuggestion(data.webView, 1).value, "for"); |
2294 | + compare(getSuggestion(data.webView, 2).value, "four"); |
2295 | + data.webView.visible = false; |
2296 | + } |
2297 | + |
2298 | + function test_destroy_on_webview_close() { |
2299 | + var webView2 = webViewFactory.createObject(testRoot); |
2300 | + loadForm(webView2); |
2301 | + typeStringInField(webView2, "f", "field1"); |
2302 | + |
2303 | + verify(TestUtils.waitFor(function() { |
2304 | + return !!getAutofillPopup(webView2) && |
2305 | + getAutofillPopup(webView2).visible; })); |
2306 | + var popup = getAutofillPopup(webView2); |
2307 | + var helper = TestSupport.createQObjectTestHelper(popup); |
2308 | + |
2309 | + webView2.destroy(); |
2310 | + verify(TestUtils.waitFor(function() { return helper.destroyed; })); |
2311 | + } |
2312 | + |
2313 | + function test_down_arrow_key_navigation_data() { |
2314 | + return get_webviews_data(); |
2315 | + } |
2316 | + |
2317 | + function test_down_arrow_key_navigation(data) { |
2318 | + loadForm(data.webView); |
2319 | + typeStringInField(data.webView, "f", "field1"); |
2320 | + verify(waitForAutofillPopup(data.webView)); |
2321 | + var popup = getAutofillPopup(data.webView); |
2322 | + keyClick(Qt.Key_Down); |
2323 | + compare(popup.currentIndex, 0); |
2324 | + keyClick(Qt.Key_Down); |
2325 | + compare(popup.currentIndex, 1); |
2326 | + keyClick(Qt.Key_Down); |
2327 | + compare(popup.currentIndex, 2); |
2328 | + keyClick(Qt.Key_Down); |
2329 | + compare(popup.currentIndex, 0); |
2330 | + data.webView.visible = false; |
2331 | + } |
2332 | + |
2333 | + function test_up_arrow_key_navigation_data() { |
2334 | + return get_webviews_data(); |
2335 | + } |
2336 | + |
2337 | + function test_up_arrow_key_navigation(data) { |
2338 | + loadForm(data.webView); |
2339 | + typeStringInField(data.webView, "f", "field1"); |
2340 | + verify(waitForAutofillPopup(data.webView)); |
2341 | + var popup = getAutofillPopup(data.webView); |
2342 | + keyClick(Qt.Key_Up); |
2343 | + compare(popup.currentIndex, 2); |
2344 | + keyClick(Qt.Key_Up); |
2345 | + compare(popup.currentIndex, 1); |
2346 | + keyClick(Qt.Key_Up); |
2347 | + compare(popup.currentIndex, 0); |
2348 | + keyClick(Qt.Key_Up); |
2349 | + compare(popup.currentIndex, 2); |
2350 | + data.webView.visible = false; |
2351 | + } |
2352 | + |
2353 | + function test_escape_dismisses_popup_data() { |
2354 | + return get_webviews_data(); |
2355 | + } |
2356 | + |
2357 | + function test_escape_dismisses_popup(data) { |
2358 | + loadForm(data.webView); |
2359 | + typeStringInField(data.webView, "f", "field1"); |
2360 | + verify(waitForAutofillPopup(data.webView)); |
2361 | + keyClick(Qt.Key_Escape); |
2362 | + verify(waitForAutofillPopupToClose(data.webView)); |
2363 | + data.webView.visible = false; |
2364 | + } |
2365 | + |
2366 | + function test_escape_dismisses_popup_and_resets_field_value_data() { |
2367 | + return get_webviews_data(); |
2368 | + } |
2369 | + |
2370 | + function test_escape_dismisses_popup_and_resets_field_value(data) { |
2371 | + loadForm(data.webView); |
2372 | + typeStringInField(data.webView, "f", "field1"); |
2373 | + verify(waitForAutofillPopup(data.webView)); |
2374 | + var popup = getAutofillPopup(data.webView); |
2375 | + keyClick(Qt.Key_Down); |
2376 | + compare(popup.currentIndex, 0); |
2377 | + keyClick(Qt.Key_Escape); |
2378 | + verify(waitForAutofillPopupToClose(data.webView)); |
2379 | + compare_field_value(data.webView, "field1", "f"); |
2380 | + data.webView.visible = false; |
2381 | + } |
2382 | + |
2383 | + function test_validate_suggestion_with_mouse_data() { |
2384 | + return get_webviews_data(); |
2385 | + } |
2386 | + |
2387 | + function test_validate_suggestion_with_mouse(data) { |
2388 | + loadForm(data.webView); |
2389 | + typeStringInField(data.webView, "f", "field1"); |
2390 | + verify(waitForAutofillPopup(data.webView)); |
2391 | + var popup = getAutofillPopup(data.webView); |
2392 | + var item = getSuggestion(data.webView, 1); |
2393 | + mouseClick(item); |
2394 | + verify(waitForAutofillPopupToClose(data.webView)); |
2395 | + verify_field_focused(data.webView, "field1"); |
2396 | + compare_field_value(data.webView, "field1", "for"); |
2397 | + data.webView.visible = false; |
2398 | + } |
2399 | + |
2400 | + function test_validate_suggestion_with_keyboard_data() { |
2401 | + return [ |
2402 | + { webView: webView, key: Qt.Key_Enter, focus: "field1" }, |
2403 | + { webView: webView, key: Qt.Key_Return, focus: "field1" }, |
2404 | + { webView: webView, key: Qt.Key_Tab, focus: "field2" }, |
2405 | + { webView: incognitoWebView, key: Qt.Key_Enter, focus: "field1" }, |
2406 | + { webView: incognitoWebView, key: Qt.Key_Return, focus: "field1" }, |
2407 | + { webView: incognitoWebView, key: Qt.Key_Tab, focus: "field2" }, |
2408 | + ]; |
2409 | + } |
2410 | + |
2411 | + function test_validate_suggestion_with_keyboard(data) { |
2412 | + loadForm(data.webView); |
2413 | + typeStringInField(data.webView, "f", "field1"); |
2414 | + verify(waitForAutofillPopup(data.webView)); |
2415 | + var popup = getAutofillPopup(data.webView); |
2416 | + keyClick(Qt.Key_Down); |
2417 | + compare(popup.currentIndex, 0); |
2418 | + keyClick(data.key); |
2419 | + verify(waitForAutofillPopupToClose(data.webView)); |
2420 | + verify_field_focused(data.webView, data.focus); |
2421 | + compare_field_value(data.webView, "field1", "foo"); |
2422 | + data.webView.visible = false; |
2423 | + } |
2424 | + |
2425 | + function test_shiftdel_deletes_suggestion() { |
2426 | + typeStringInField(webView, "f", "field1"); |
2427 | + verify(waitForAutofillPopup(webView)); |
2428 | + keyClick("l"); |
2429 | + verify(waitForAutofillPopupToClose(webView)); |
2430 | + keyClick("i"); |
2431 | + keyClick("p"); |
2432 | + compare_field_value(webView, "field1", "flip"); |
2433 | + keyClick(Qt.Key_Enter); |
2434 | + verify(webView.waitForLoadSucceeded()); |
2435 | + webView.url = |
2436 | + "http://testsuite/tst_WebViewAutofillPopup_single_fields.html"; |
2437 | + verify(webView.waitForLoadSucceeded()); |
2438 | + typeStringInField(webView, "f", "field1"); |
2439 | + verify(waitForAutofillPopup(webView)); |
2440 | + var popup = getAutofillPopup(webView); |
2441 | + compare(popup.count, 4); |
2442 | + compare(getSuggestion(webView, 0).value, "flip"); |
2443 | + keyClick(Qt.Key_Down); |
2444 | + compare(popup.currentIndex, 0); |
2445 | + keyClick(Qt.Key_Delete, Qt.ShiftModifier); |
2446 | + tryCompare(popup, "currentIndex", -1); |
2447 | + tryCompare(popup, "count", 3); |
2448 | + } |
2449 | + |
2450 | + function test_tab_no_suggestion_data() { |
2451 | + return get_webviews_data(); |
2452 | + } |
2453 | + |
2454 | + function test_tab_no_suggestion(data) { |
2455 | + loadForm(data.webView); |
2456 | + typeStringInField(data.webView, "f", "field1"); |
2457 | + verify(waitForAutofillPopup(data.webView)); |
2458 | + var popup = getAutofillPopup(data.webView); |
2459 | + compare(popup.currentIndex, -1); |
2460 | + verify_field_focused(data.webView, "field1"); |
2461 | + keyClick(Qt.Key_Tab); |
2462 | + verify(waitForAutofillPopupToClose(data.webView)); |
2463 | + verify_field_focused(data.webView, "field2"); |
2464 | + data.webView.visible = false; |
2465 | + } |
2466 | + |
2467 | + function test_incognito_data_not_saved() { |
2468 | + if (!incognitoWebView.incognito) { |
2469 | + skip("WebView.incognito cannot be set in single process mode"); |
2470 | + } |
2471 | + loadForm(incognitoWebView); |
2472 | + typeStringInField(incognitoWebView, "bar", "field1"); |
2473 | + keyClick(Qt.Key_Enter); |
2474 | + verify(incognitoWebView.waitForLoadSucceeded()); |
2475 | + loadForm(incognitoWebView); |
2476 | + typeStringInField(incognitoWebView, "b", "field1"); |
2477 | + verify(!waitForAutofillPopup(incognitoWebView, 1000)); |
2478 | + incognitoWebView.visible = false; |
2479 | + } |
2480 | + |
2481 | + function test_zlast_validate_no_suggestion_data() { |
2482 | + return [ |
2483 | + { key: Qt.Key_Enter }, |
2484 | + { key: Qt.Key_Return }, |
2485 | + ]; |
2486 | + } |
2487 | + |
2488 | + // This test needs to be run last as it adds a suggestion that is |
2489 | + // not removed afterwards, thus breaking other tests' assumptions |
2490 | + function test_zlast_validate_no_suggestion(data) { |
2491 | + typeStringInField(webView, "f", "field1"); |
2492 | + verify(waitForAutofillPopup(webView)); |
2493 | + var popup = getAutofillPopup(webView); |
2494 | + compare(popup.currentIndex, -1); |
2495 | + keyClick(data.key); |
2496 | + verify(waitForAutofillPopupToClose(webView)); |
2497 | + verify(webView.waitForLoadSucceeded()); |
2498 | + } |
2499 | + } |
2500 | +} |
2501 | diff --git a/qt/uitk/lib/CMakeLists.txt b/qt/uitk/lib/CMakeLists.txt |
2502 | index 9e76ebe..8f73100 100644 |
2503 | --- a/qt/uitk/lib/CMakeLists.txt |
2504 | +++ b/qt/uitk/lib/CMakeLists.txt |
2505 | @@ -1,6 +1,6 @@ |
2506 | # vim:expandtab:shiftwidth=2:tabstop=2: |
2507 | |
2508 | -# Copyright (C) 2016 Canonical Ltd. |
2509 | +# Copyright (C) 2016-2017 Canonical Ltd. |
2510 | |
2511 | # This library is free software; you can redistribute it and/or |
2512 | # modify it under the terms of the GNU Lesser General Public |
2513 | @@ -27,6 +27,7 @@ set(OXIDE_UITKLIB_SRCS |
2514 | uitk_javascript_dialog.cc |
2515 | uitk_touch_editing_menu.cc |
2516 | uitk_touch_handle_drawable.cc |
2517 | + uitk_web_autofill_popup.cc |
2518 | uitk_web_context_menu.cc |
2519 | uitk_web_popup_menu.cc) |
2520 | |
2521 | diff --git a/qt/uitk/lib/resources.qrc b/qt/uitk/lib/resources.qrc |
2522 | index f2cf4ba..83f258a 100644 |
2523 | --- a/qt/uitk/lib/resources.qrc |
2524 | +++ b/qt/uitk/lib/resources.qrc |
2525 | @@ -6,6 +6,7 @@ |
2526 | <file alias="TouchEditingMenu.qml">resources/TouchEditingMenu.qml</file> |
2527 | <file alias="TouchHandle@27.png">resources/TouchHandle@27.png</file> |
2528 | <file alias="TouchHandle.qml">resources/TouchHandle.qml</file> |
2529 | + <file alias="WebAutofillPopup.qml">resources/WebAutofillPopup.qml</file> |
2530 | <file alias="WebContextMenuMobile.qml">resources/WebContextMenuMobile.qml</file> |
2531 | <file alias="WebContextMenuDesktop.qml">resources/WebContextMenuDesktop.qml</file> |
2532 | <file alias="WebPopupMenu.qml">resources/WebPopupMenu.qml</file> |
2533 | diff --git a/qt/uitk/lib/resources/WebAutofillPopup.qml b/qt/uitk/lib/resources/WebAutofillPopup.qml |
2534 | new file mode 100644 |
2535 | index 0000000..848cf0e |
2536 | --- /dev/null |
2537 | +++ b/qt/uitk/lib/resources/WebAutofillPopup.qml |
2538 | @@ -0,0 +1,139 @@ |
2539 | +// vim:expandtab:shiftwidth=2:tabstop=2: |
2540 | +// Copyright (C) 2017 Canonical Ltd. |
2541 | + |
2542 | +// This library is free software; you can redistribute it and/or |
2543 | +// modify it under the terms of the GNU Lesser General Public |
2544 | +// License as published by the Free Software Foundation; either |
2545 | +// version 2.1 of the License, or (at your option) any later version. |
2546 | + |
2547 | +// This library is distributed in the hope that it will be useful, |
2548 | +// but WITHOUT ANY WARRANTY; without even the implied warranty of |
2549 | +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
2550 | +// Lesser General Public License for more details. |
2551 | + |
2552 | +// You should have received a copy of the GNU Lesser General Public |
2553 | +// License along with this library; if not, write to the Free Software |
2554 | +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
2555 | + |
2556 | +import QtQuick 2.4 |
2557 | +import Ubuntu.Components 1.3 |
2558 | + |
2559 | +FocusScope { |
2560 | + objectName: parent && parent.objectName ? parent.objectName + "_WebAutofillPopup" : "" |
2561 | + |
2562 | + property alias model: listview.model |
2563 | + property rect elementBounds |
2564 | + readonly property int currentIndex: listview.currentIndex |
2565 | + readonly property int count: listview.count |
2566 | + |
2567 | + signal close() |
2568 | + signal acceptedSuggestion(int index) |
2569 | + signal removeSuggestion(int index) |
2570 | + |
2571 | + focus:Â true |
2572 | + clip: true |
2573 | + |
2574 | + x: elementBounds.x |
2575 | + y: elementBounds.y + elementBounds.height |
2576 | + width: elementBounds.width |
2577 | + readonly property real maxHeight: parent ? parent.height - elementBounds.y - elementBounds.height :Â 0 |
2578 | + height: Math.min(maxHeight, listview.count * listview.itemHeight) |
2579 | + |
2580 | + Rectangle { |
2581 | + anchors.fill: parent |
2582 | + color: theme.palette.normal.overlay |
2583 | + function newColorWithAlpha(color, alpha) { |
2584 | + return Qt.rgba(color.r, color.g, color.b, alpha); |
2585 | + } |
2586 | + border { |
2587 | + width: units.dp(1) |
2588 | + color: newColorWithAlpha(theme.palette.normal.base, 0.4) |
2589 | + } |
2590 | + } |
2591 | + |
2592 | + MouseArea { |
2593 | + anchors.fill: parent |
2594 | + hoverEnabled: true |
2595 | + onPositionChanged:Â listview.currentIndex = listview.indexAt(mouse.x, mouse.y) |
2596 | + onExited:Â listview.currentIndex = -1 |
2597 | + } |
2598 | + |
2599 | + ListView { |
2600 | + id: listview |
2601 | + |
2602 | + property real itemHeight: 0 |
2603 | + anchors.fill:Â parent |
2604 | + |
2605 | + delegate: ListItem { |
2606 | + objectName: "%1_item%2".arg(listview.parent.objectName).arg(index) |
2607 | + readonly property string value: model.value |
2608 | + readonly property string label: model.label |
2609 | + height: units.gu(5) |
2610 | + ListItemLayout { |
2611 | + anchors.verticalCenter: parent.verticalCenter |
2612 | + title { |
2613 | + text: model.value |
2614 | + textSize: Label.Small |
2615 | + } |
2616 | + subtitle { |
2617 | + text: model.label |
2618 | + textSize: Label.XSmall |
2619 | + } |
2620 | + } |
2621 | + color: ListView.isCurrentItem ? theme.palette.normal.focus : "transparent" |
2622 | + Component.onCompleted: listview.itemHeight = height |
2623 | + |
2624 | + onClicked: acceptedSuggestion(index) |
2625 | + |
2626 | + property bool removalRequested: false |
2627 | + Keys.onDeletePressed: { |
2628 | + if (event.modifiers & Qt.ShiftModifier) { |
2629 | + removalRequested = true; |
2630 | + removeSuggestion(index); |
2631 | + } else { |
2632 | + event.accepted = false; |
2633 | + } |
2634 | + } |
2635 | + ListView.onRemove: { |
2636 | + if (removalRequested) { |
2637 | + listview.currentIndex = -1; |
2638 | + } |
2639 | + } |
2640 | + } |
2641 | + |
2642 | + Keys.onEnterPressed: { |
2643 | + if (currentItem) { |
2644 | + currentItem.clicked(); |
2645 | + } else { |
2646 | + event.accepted = false; |
2647 | + } |
2648 | + } |
2649 | + Keys.onReturnPressed: { |
2650 | + if (currentItem) { |
2651 | + currentItem.clicked(); |
2652 | + } else { |
2653 | + event.accepted = false; |
2654 | + } |
2655 | + } |
2656 | + Keys.onTabPressed: { |
2657 | + event.accepted = false; |
2658 | + if (currentItem) { |
2659 | + currentItem.clicked(); |
2660 | + } |
2661 | + } |
2662 | + |
2663 | + keyNavigationWraps: true |
2664 | + currentIndex: -1 |
2665 | + |
2666 | + Component.onCompleted: { |
2667 | + // Work around the UITK ListViewProxy extension that forces |
2668 | + // activeFocusOnTab, thus breaking tab key propagation. Setting |
2669 | + // activeFocusOnTab to false needs to be done before the item is the |
2670 | + // active focus item. |
2671 | + activeFocusOnTab = false; |
2672 | + focus = true; |
2673 | + } |
2674 | + } |
2675 | + |
2676 | + Keys.onEscapePressed: close() |
2677 | +} |
2678 | diff --git a/qt/uitk/lib/uitk_auxiliary_ui_factory.cc b/qt/uitk/lib/uitk_auxiliary_ui_factory.cc |
2679 | index e6f64fb..48731e0 100644 |
2680 | --- a/qt/uitk/lib/uitk_auxiliary_ui_factory.cc |
2681 | +++ b/qt/uitk/lib/uitk_auxiliary_ui_factory.cc |
2682 | @@ -1,5 +1,5 @@ |
2683 | // vim:expandtab:shiftwidth=2:tabstop=2: |
2684 | -// Copyright (C) 2016 Canonical Ltd. |
2685 | +// Copyright (C) 2016-2017 Canonical Ltd. |
2686 | |
2687 | // This library is free software; you can redistribute it and/or |
2688 | // modify it under the terms of the GNU Lesser General Public |
2689 | @@ -38,6 +38,7 @@ |
2690 | #include "uitk_before_unload_dialog.h" |
2691 | #include "uitk_javascript_dialog.h" |
2692 | #include "uitk_touch_editing_menu.h" |
2693 | +#include "uitk_web_autofill_popup.h" |
2694 | #include "uitk_web_context_menu.h" |
2695 | |
2696 | static void InitResources() { |
2697 | @@ -47,11 +48,13 @@ static void InitResources() { |
2698 | namespace oxide { |
2699 | namespace uitk { |
2700 | |
2701 | +using qt::AutofillSuggestion; |
2702 | using qt::EditCapabilityFlags; |
2703 | using qt::GetScreenFormFactor; |
2704 | using qt::MenuItem; |
2705 | using qt::ScreenFormFactor; |
2706 | using qt::TouchEditingMenuClient; |
2707 | +using qt::WebAutofillPopupClient; |
2708 | using qt::WebContextMenuAction; |
2709 | using qt::WebContextMenuClient; |
2710 | using qt::WebContextMenuParams; |
2711 | @@ -230,6 +233,14 @@ std::unique_ptr<qt::WebContextMenu> AuxiliaryUIFactory::CreateWebContextMenu( |
2712 | IsItemOnMobileScreen(item_)); |
2713 | } |
2714 | |
2715 | +std::unique_ptr<qt::WebAutofillPopup> |
2716 | +AuxiliaryUIFactory::CreateWebAutofillPopup( |
2717 | + const std::vector<AutofillSuggestion>& suggestions, |
2718 | + const QRectF& bounds, |
2719 | + WebAutofillPopupClient* client) { |
2720 | + return WebAutofillPopup::Create(item_, suggestions, bounds, client); |
2721 | +} |
2722 | + |
2723 | std::unique_ptr<qt::TouchEditingMenu> |
2724 | AuxiliaryUIFactory::CreateTouchEditingMenu( |
2725 | EditCapabilityFlags edit_flags, |
2726 | diff --git a/qt/uitk/lib/uitk_auxiliary_ui_factory.h b/qt/uitk/lib/uitk_auxiliary_ui_factory.h |
2727 | index 3d169e4..d0ae8e7 100644 |
2728 | --- a/qt/uitk/lib/uitk_auxiliary_ui_factory.h |
2729 | +++ b/qt/uitk/lib/uitk_auxiliary_ui_factory.h |
2730 | @@ -1,5 +1,5 @@ |
2731 | // vim:expandtab:shiftwidth=2:tabstop=2: |
2732 | -// Copyright (C) 2016 Canonical Ltd. |
2733 | +// Copyright (C) 2016-2017 Canonical Ltd. |
2734 | |
2735 | // This library is free software; you can redistribute it and/or |
2736 | // modify it under the terms of the GNU Lesser General Public |
2737 | @@ -56,6 +56,10 @@ class AuxiliaryUIFactory : public qt::AuxiliaryUIFactory { |
2738 | const qt::WebContextMenuParams& params, |
2739 | const std::vector<qt::MenuItem>& items, |
2740 | qt::WebContextMenuClient* client) override; |
2741 | + std::unique_ptr<qt::WebAutofillPopup> CreateWebAutofillPopup( |
2742 | + const std::vector<qt::AutofillSuggestion>& suggestions, |
2743 | + const QRectF& bounds, |
2744 | + qt::WebAutofillPopupClient* client) override; |
2745 | std::unique_ptr<qt::TouchEditingMenu> CreateTouchEditingMenu( |
2746 | qt::EditCapabilityFlags edit_flags, |
2747 | qt::TouchEditingMenuClient* client) override; |
2748 | diff --git a/qt/uitk/lib/uitk_web_autofill_popup.cc b/qt/uitk/lib/uitk_web_autofill_popup.cc |
2749 | new file mode 100644 |
2750 | index 0000000..4085608 |
2751 | --- /dev/null |
2752 | +++ b/qt/uitk/lib/uitk_web_autofill_popup.cc |
2753 | @@ -0,0 +1,297 @@ |
2754 | +// vim:expandtab:shiftwidth=2:tabstop=2: |
2755 | +// Copyright (C) 2017 Canonical Ltd. |
2756 | + |
2757 | +// This library is free software; you can redistribute it and/or |
2758 | +// modify it under the terms of the GNU Lesser General Public |
2759 | +// License as published by the Free Software Foundation; either |
2760 | +// version 2.1 of the License, or (at your option) any later version. |
2761 | + |
2762 | +// This library is distributed in the hope that it will be useful, |
2763 | +// but WITHOUT ANY WARRANTY; without even the implied warranty of |
2764 | +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
2765 | +// Lesser General Public License for more details. |
2766 | + |
2767 | +// You should have received a copy of the GNU Lesser General Public |
2768 | +// License along with this library; if not, write to the Free Software |
2769 | +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
2770 | + |
2771 | +#include "uitk_web_autofill_popup.h" |
2772 | + |
2773 | +#include <QAbstractListModel> |
2774 | +#include <QMetaObject> |
2775 | +#include <QQmlComponent> |
2776 | +#include <QQmlEngine> |
2777 | +#include <QQmlError> |
2778 | +#include <QQmlProperty> |
2779 | +#include <QQuickItem> |
2780 | +#include <QtDebug> |
2781 | +#include <QVariant> |
2782 | +#include <QVector> |
2783 | + |
2784 | +#include "qt/core/glue/autofill_suggestion.h" |
2785 | +#include "qt/core/glue/web_autofill_popup_client.h" |
2786 | + |
2787 | +namespace oxide { |
2788 | +namespace uitk { |
2789 | + |
2790 | +using qt::AutofillSuggestion; |
2791 | + |
2792 | +class WebAutofillPopup::Model : public QAbstractListModel { |
2793 | + public: |
2794 | + Model(const std::vector<AutofillSuggestion>& suggestions); |
2795 | + ~Model() override; |
2796 | + |
2797 | + enum Role { |
2798 | + RoleType = Qt::UserRole, |
2799 | + RoleValue, |
2800 | + RoleLabel, |
2801 | + RoleIcon |
2802 | + }; |
2803 | + |
2804 | + // QAbstractItemModel implementation |
2805 | + int rowCount(const QModelIndex& parent = QModelIndex()) const override; |
2806 | + QVariant data(const QModelIndex& index, |
2807 | + int role = Qt::DisplayRole) const override; |
2808 | + QHash<int, QByteArray> roleNames() const override; |
2809 | + |
2810 | + protected: |
2811 | + friend class WebAutofillPopup; |
2812 | + void updateDataListValues(const std::vector<AutofillSuggestion>& suggestions); |
2813 | + void removeSuggestion(int index); |
2814 | + |
2815 | + QVector<AutofillSuggestion> suggestions_; |
2816 | +}; |
2817 | + |
2818 | +WebAutofillPopup::Model::Model( |
2819 | + const std::vector<AutofillSuggestion>& suggestions) { |
2820 | + suggestions_ = QVector<AutofillSuggestion>::fromStdVector(suggestions); |
2821 | +} |
2822 | + |
2823 | +WebAutofillPopup::Model::~Model() = default; |
2824 | + |
2825 | +int WebAutofillPopup::Model::rowCount(const QModelIndex& parent) const { |
2826 | + return suggestions_.size(); |
2827 | +} |
2828 | + |
2829 | +QVariant WebAutofillPopup::Model::data(const QModelIndex& index, |
2830 | + int role) const { |
2831 | + Q_ASSERT(index.isValid()); |
2832 | + Q_ASSERT(index.row() >= 0 && index.row() < suggestions_.size()); |
2833 | + Q_ASSERT(index.column() == 0); |
2834 | + Q_ASSERT(!index.parent().isValid()); |
2835 | + |
2836 | + const AutofillSuggestion& suggestion = suggestions_[index.row()]; |
2837 | + |
2838 | + switch (role) { |
2839 | + case RoleType: { |
2840 | + switch (suggestion.type) { |
2841 | + case AutofillSuggestion::Type::ProfileEntry: |
2842 | + return QStringLiteral("profile"); |
2843 | + case AutofillSuggestion::Type::AutoCompleteEntry: |
2844 | + return QStringLiteral("autocomplete"); |
2845 | + case AutofillSuggestion::Type::PasswordEntry: |
2846 | + return QStringLiteral("password"); |
2847 | + case AutofillSuggestion::Type::DataListEntry: |
2848 | + return QStringLiteral("datalist"); |
2849 | + default: |
2850 | + Q_UNREACHABLE(); |
2851 | + } |
2852 | + } |
2853 | + case RoleValue: |
2854 | + return suggestion.value; |
2855 | + case RoleLabel: |
2856 | + return suggestion.label; |
2857 | + case RoleIcon: |
2858 | + return suggestion.icon; |
2859 | + default: |
2860 | + Q_UNREACHABLE(); |
2861 | + } |
2862 | +} |
2863 | + |
2864 | +QHash<int, QByteArray> WebAutofillPopup::Model::roleNames() const { |
2865 | + static QHash<int, QByteArray> roles; |
2866 | + |
2867 | + if (roles.size() > 0) { |
2868 | + return roles; |
2869 | + } |
2870 | + |
2871 | + roles[RoleType] = "type"; |
2872 | + roles[RoleValue] = "value"; |
2873 | + roles[RoleLabel] = "label"; |
2874 | + roles[RoleIcon] = "icon"; |
2875 | + |
2876 | + return roles; |
2877 | +} |
2878 | + |
2879 | +void WebAutofillPopup::Model::updateDataListValues( |
2880 | + const std::vector<AutofillSuggestion>& suggestions) { |
2881 | + // Remove all the old data list values, which should always be at the top of |
2882 | + // the list if they are present. |
2883 | + if (!suggestions_.isEmpty()) { |
2884 | + int i = suggestions_.size() - 1; |
2885 | + while (i >= 0 && |
2886 | + suggestions_[i--].type != AutofillSuggestion::Type::DataListEntry); |
2887 | + if (i >= 0) { |
2888 | + beginRemoveRows(QModelIndex(), 0, i); |
2889 | + suggestions_.remove(0, i + 1); |
2890 | + endRemoveRows(); |
2891 | + } |
2892 | + } |
2893 | + |
2894 | + // Prepend the new data list values to the suggestions we already have. |
2895 | + beginInsertRows(QModelIndex(), 0, suggestions.size() - 1); |
2896 | + suggestions_ = |
2897 | + QVector<AutofillSuggestion>::fromStdVector(suggestions) + suggestions_; |
2898 | + endInsertRows(); |
2899 | +} |
2900 | + |
2901 | +void WebAutofillPopup::Model::removeSuggestion(int index) { |
2902 | + beginRemoveRows(QModelIndex(), index, index); |
2903 | + suggestions_.remove(index); |
2904 | + endRemoveRows(); |
2905 | +} |
2906 | + |
2907 | +void WebAutofillPopup::Show() { |
2908 | + item_->setVisible(true); |
2909 | +} |
2910 | + |
2911 | +void WebAutofillPopup::UpdateDataListValues( |
2912 | + const std::vector<AutofillSuggestion>& suggestions) { |
2913 | + model_->updateDataListValues(suggestions); |
2914 | +} |
2915 | + |
2916 | +void WebAutofillPopup::Hide() { |
2917 | + item_->setVisible(false); |
2918 | +} |
2919 | + |
2920 | +WebAutofillPopup::WebAutofillPopup( |
2921 | + const std::vector<AutofillSuggestion>& suggestions, |
2922 | + const QRectF& bounds, |
2923 | + qt::WebAutofillPopupClient* client) |
2924 | + : model_(new Model(suggestions)), |
2925 | + bounds_(bounds), |
2926 | + client_(client) {} |
2927 | + |
2928 | +bool WebAutofillPopup::Init(QQuickItem* parent) { |
2929 | + QQmlEngine* engine = qmlEngine(parent); |
2930 | + if (!engine) { |
2931 | + qWarning() << |
2932 | + "uitk::WebAutofillPopup: Failed to create autofill popup - " |
2933 | + "cannot determine QQmlEngine for parent item"; |
2934 | + return false; |
2935 | + } |
2936 | + |
2937 | + QQmlComponent component(engine); |
2938 | + component.loadUrl(QUrl("qrc:///WebAutofillPopup.qml")); |
2939 | + |
2940 | + if (component.isError()) { |
2941 | + qCritical() << |
2942 | + "uitk::WebAutofillPopup: Failed to initialize autofill popup component " |
2943 | + "because of the following errors: "; |
2944 | + for (const auto& error : component.errors()) { |
2945 | + qCritical() << error; |
2946 | + } |
2947 | + return false; |
2948 | + } |
2949 | + |
2950 | + Q_ASSERT(component.isReady()); |
2951 | + |
2952 | + QObject* popup = component.beginCreate(engine->rootContext()); |
2953 | + if (!popup) { |
2954 | + qCritical() << |
2955 | + "uitk::WebAutofillPopup: Failed to create autofill popup instance"; |
2956 | + return false; |
2957 | + } |
2958 | + |
2959 | + item_.reset(qobject_cast<QQuickItem*>(popup)); |
2960 | + if (!item_) { |
2961 | + qCritical() << |
2962 | + "uitk::WebAutofillPopup: Autofill popup instance is not a QQuickItem"; |
2963 | + delete popup; |
2964 | + return false; |
2965 | + } |
2966 | + |
2967 | + item_->setProperty("model", QVariant::fromValue(model_.get())); |
2968 | + item_->setProperty("elementBounds", bounds_); |
2969 | + item_->setParentItem(parent); |
2970 | + |
2971 | + component.completeCreate(); |
2972 | + |
2973 | + connect(item_.get(), SIGNAL(close()), this, SLOT(OnCloseRequested())); |
2974 | + connect(item_.get(), SIGNAL(currentIndexChanged()), |
2975 | + this, SLOT(OnSuggestionSelected())); |
2976 | + connect(item_.get(), SIGNAL(acceptedSuggestion(int)), |
2977 | + this, SLOT(OnSuggestionAccepted(int))); |
2978 | + connect(item_.get(), SIGNAL(removeSuggestion(int)), |
2979 | + this, SLOT(OnSuggestionRemovalRequested(int))); |
2980 | + |
2981 | + return true; |
2982 | +} |
2983 | + |
2984 | +void WebAutofillPopup::OnCloseRequested() { |
2985 | + client_->Close(); |
2986 | +} |
2987 | + |
2988 | +void WebAutofillPopup::OnSuggestionSelected() { |
2989 | + int index = |
2990 | + QQmlProperty(item_.get(), QStringLiteral("currentIndex")).read().toInt(); |
2991 | + |
2992 | + if (index == -1) { |
2993 | + client_->ClearSelection(); |
2994 | + return; |
2995 | + } |
2996 | + |
2997 | + if (index < 0 || index >= model_->rowCount()) { |
2998 | + qWarning() << "uitk::WebAutofillPopup: invalid index"; |
2999 | + return; |
3000 | + } |
3001 | + |
3002 | + const AutofillSuggestion& suggestion = model_->suggestions_[index]; |
3003 | + client_->SelectSuggestion(suggestion); |
3004 | +} |
3005 | + |
3006 | +void WebAutofillPopup::OnSuggestionAccepted(int index) { |
3007 | + if (index < 0 || index >= model_->rowCount()) { |
3008 | + qWarning() << "uitk::WebAutofillPopup: invalid index"; |
3009 | + return; |
3010 | + } |
3011 | + |
3012 | + const AutofillSuggestion& suggestion = model_->suggestions_[index]; |
3013 | + client_->AcceptSuggestion(suggestion); |
3014 | +} |
3015 | + |
3016 | +void WebAutofillPopup::OnSuggestionRemovalRequested(int index) { |
3017 | + if (index < 0 || index >= model_->rowCount()) { |
3018 | + qWarning() << "uitk::WebAutofillPopup: invalid index"; |
3019 | + return; |
3020 | + } |
3021 | + |
3022 | + const AutofillSuggestion& suggestion = model_->suggestions_[index]; |
3023 | + if (client_->RemoveSuggestion(suggestion)) { |
3024 | + model_->removeSuggestion(index); |
3025 | + } |
3026 | +} |
3027 | + |
3028 | +// static |
3029 | +std::unique_ptr<WebAutofillPopup> WebAutofillPopup::Create( |
3030 | + QQuickItem* parent, |
3031 | + const std::vector<AutofillSuggestion>& suggestions, |
3032 | + const QRectF& bounds, |
3033 | + qt::WebAutofillPopupClient* client) { |
3034 | + if (suggestions.empty()) { |
3035 | + return nullptr; |
3036 | + } |
3037 | + |
3038 | + std::unique_ptr<WebAutofillPopup> popup( |
3039 | + new WebAutofillPopup(suggestions, bounds, client)); |
3040 | + if (!popup->Init(parent)) { |
3041 | + return nullptr; |
3042 | + } |
3043 | + |
3044 | + return std::move(popup); |
3045 | +} |
3046 | + |
3047 | +WebAutofillPopup::~WebAutofillPopup() = default; |
3048 | + |
3049 | +} // namespace uitk |
3050 | +} // namespace oxide |
3051 | diff --git a/qt/uitk/lib/uitk_web_autofill_popup.h b/qt/uitk/lib/uitk_web_autofill_popup.h |
3052 | new file mode 100644 |
3053 | index 0000000..4dfbf38 |
3054 | --- /dev/null |
3055 | +++ b/qt/uitk/lib/uitk_web_autofill_popup.h |
3056 | @@ -0,0 +1,87 @@ |
3057 | +// vim:expandtab:shiftwidth=2:tabstop=2: |
3058 | +// Copyright (C) 2017 Canonical Ltd. |
3059 | + |
3060 | +// This library is free software; you can redistribute it and/or |
3061 | +// modify it under the terms of the GNU Lesser General Public |
3062 | +// License as published by the Free Software Foundation; either |
3063 | +// version 2.1 of the License, or (at your option) any later version. |
3064 | + |
3065 | +// This library is distributed in the hope that it will be useful, |
3066 | +// but WITHOUT ANY WARRANTY; without even the implied warranty of |
3067 | +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
3068 | +// Lesser General Public License for more details. |
3069 | + |
3070 | +// You should have received a copy of the GNU Lesser General Public |
3071 | +// License along with this library; if not, write to the Free Software |
3072 | +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
3073 | + |
3074 | +#ifndef _OXIDE_UITK_LIB_WEB_AUTOFILL_POPUP_H_ |
3075 | +#define _OXIDE_UITK_LIB_WEB_AUTOFILL_POPUP_H_ |
3076 | + |
3077 | +#include "qt/core/glue/web_autofill_popup.h" |
3078 | + |
3079 | +#include <memory> |
3080 | +#include <vector> |
3081 | + |
3082 | +#include <QObject> |
3083 | +#include <QRectF> |
3084 | +#include <QtGlobal> |
3085 | + |
3086 | +QT_BEGIN_NAMESPACE |
3087 | +class QQuickItem; |
3088 | +QT_END_NAMESPACE |
3089 | + |
3090 | +namespace oxide { |
3091 | + |
3092 | +namespace qt { |
3093 | +struct AutofillSuggestion; |
3094 | +class WebAutofillPopupClient; |
3095 | +} |
3096 | + |
3097 | +namespace uitk { |
3098 | + |
3099 | +class WebAutofillPopup : public QObject, |
3100 | + public qt::WebAutofillPopup { |
3101 | + Q_OBJECT |
3102 | + Q_DISABLE_COPY(WebAutofillPopup) |
3103 | + |
3104 | + public: |
3105 | + static std::unique_ptr<WebAutofillPopup> Create( |
3106 | + QQuickItem* parent, |
3107 | + const std::vector<qt::AutofillSuggestion>& suggestions, |
3108 | + const QRectF& bounds, |
3109 | + qt::WebAutofillPopupClient* client); |
3110 | + ~WebAutofillPopup() override; |
3111 | + |
3112 | + private Q_SLOTS: |
3113 | + void OnCloseRequested(); |
3114 | + void OnSuggestionSelected(); |
3115 | + void OnSuggestionAccepted(int index); |
3116 | + void OnSuggestionRemovalRequested(int index); |
3117 | + |
3118 | + private: |
3119 | + WebAutofillPopup(const std::vector<qt::AutofillSuggestion>& suggestions, |
3120 | + const QRectF& bounds, |
3121 | + qt::WebAutofillPopupClient* client); |
3122 | + bool Init(QQuickItem* parent); |
3123 | + |
3124 | + // qt::WebAutofillPopup implementation |
3125 | + void Show() override; |
3126 | + void UpdateDataListValues( |
3127 | + const std::vector<qt::AutofillSuggestion>& suggestions) override; |
3128 | + void Hide() override; |
3129 | + |
3130 | + class Model; |
3131 | + std::unique_ptr<Model> model_; |
3132 | + |
3133 | + QRectF bounds_; |
3134 | + |
3135 | + qt::WebAutofillPopupClient* client_; |
3136 | + |
3137 | + std::unique_ptr<QQuickItem> item_; |
3138 | +}; |
3139 | + |
3140 | +} // namespace uitk |
3141 | +} // namespace oxide |
3142 | + |
3143 | +#endif // _OXIDE_UITK_LIB_WEB_AUTOFILL_POPUP_H_ |
3144 | diff --git a/shared/BUILD.gn b/shared/BUILD.gn |
3145 | index 77eaeca..1aaf81d 100644 |
3146 | --- a/shared/BUILD.gn |
3147 | +++ b/shared/BUILD.gn |
3148 | @@ -1,6 +1,6 @@ |
3149 | # vim:expandtab:shiftwidth=2:tabstop=2: |
3150 | |
3151 | -# Copyright (C) 2016 Canonical Ltd. |
3152 | +# Copyright (C) 2016-2017 Canonical Ltd. |
3153 | |
3154 | # This library is free software; you can redistribute it and/or |
3155 | # modify it under the terms of the GNU Lesser General Public |
3156 | @@ -113,6 +113,7 @@ repack_locales("shared_repack_locales") { |
3157 | output_locales = locales |
3158 | |
3159 | source_patterns = [ |
3160 | + "${root_gen_dir}/components/strings/components_strings_", |
3161 | "${root_gen_dir}/content/app/strings/content_strings_", |
3162 | "${root_gen_dir}/ui/strings/app_locale_settings_", |
3163 | ] |
3164 | @@ -120,6 +121,7 @@ repack_locales("shared_repack_locales") { |
3165 | output_dir = "${root_out_dir}/chromium_l10n" |
3166 | |
3167 | deps = [ |
3168 | + "//components/strings", |
3169 | "//content/app/strings", |
3170 | "//ui/strings:app_locale_settings", |
3171 | ] |
3172 | @@ -180,13 +182,23 @@ component("shared") { |
3173 | "//base:i18n", |
3174 | "//cc", |
3175 | "//cc/surfaces", |
3176 | + "//components/autofill/content/browser", |
3177 | + "//components/autofill/content/renderer", |
3178 | + "//components/autofill/core/browser", |
3179 | "//components/keyed_service/content", |
3180 | "//components/keyed_service/core", |
3181 | + "//components/password_manager/content/browser", |
3182 | + "//components/pref_registry", |
3183 | + "//components/prefs", |
3184 | + "//components/sync", |
3185 | + "//components/user_prefs", |
3186 | "//components/sessions", |
3187 | + "//components/webdata/common", |
3188 | "//content/public/app:both", |
3189 | "//content/public/browser", |
3190 | "//content/public/child", |
3191 | "//content/public/common", |
3192 | + "//content/public/common:service_names", |
3193 | "//content/public/gpu", |
3194 | "//content/public/renderer", |
3195 | "//content/public/utility", |
3196 | @@ -198,6 +210,7 @@ component("shared") { |
3197 | "//device/vibration:mojo_bindings", |
3198 | "//extensions/common", |
3199 | "//gin", |
3200 | + "//google_apis", |
3201 | "//gpu/command_buffer/client", |
3202 | "//gpu/command_buffer/common", |
3203 | "//gpu/command_buffer/service", |
3204 | @@ -244,6 +257,12 @@ component("shared") { |
3205 | "app/oxide_main.cc", |
3206 | "app/oxide_main.h", |
3207 | "app/oxide_platform_delegate.h", |
3208 | + "browser/autofill/autofill_client.cc", |
3209 | + "browser/autofill/autofill_client.h", |
3210 | + "browser/autofill/autofill_popup_controller.cc", |
3211 | + "browser/autofill/autofill_popup_controller.h", |
3212 | + "browser/autofill/web_autofill_popup.h", |
3213 | + "browser/autofill/web_autofill_popup_client.h", |
3214 | "browser/browser_object_weak_ptrs.h", |
3215 | "browser/chrome_controller.cc", |
3216 | "browser/chrome_controller.h", |
3217 | @@ -299,6 +318,8 @@ component("shared") { |
3218 | "browser/device/power_save_blocker.h", |
3219 | "browser/device/power_save_blocker_linux.cc", |
3220 | "browser/display_form_factor.h", |
3221 | + "browser/filtered_pref_store.cc", |
3222 | + "browser/filtered_pref_store.h", |
3223 | "browser/input/input_method_context.h", |
3224 | "browser/input/input_method_context_client.cc", |
3225 | "browser/input/input_method_context_client.h", |
3226 | @@ -454,6 +475,8 @@ component("shared") { |
3227 | "browser/permissions/oxide_permission_request_response.h", |
3228 | "browser/permissions/oxide_temporary_saved_permission_context.cc", |
3229 | "browser/permissions/oxide_temporary_saved_permission_context.h", |
3230 | + "browser/personal_data_manager_factory.cc", |
3231 | + "browser/personal_data_manager_factory.h", |
3232 | "browser/screen.cc", |
3233 | "browser/screen.h", |
3234 | "browser/screen_observer.cc", |
3235 | @@ -487,6 +510,10 @@ component("shared") { |
3236 | "browser/web_contents_data_tracker.h", |
3237 | "browser/web_contents_helper.cc", |
3238 | "browser/web_contents_helper.h", |
3239 | + "browser/web_data_service_factory.cc", |
3240 | + "browser/web_data_service_factory.h", |
3241 | + "browser/web_data_service_wrapper.cc", |
3242 | + "browser/web_data_service_wrapper.h", |
3243 | "browser/web_popup_menu.h", |
3244 | "browser/web_popup_menu_client.h", |
3245 | "browser/web_popup_menu_host.cc", |
3246 | @@ -714,6 +741,7 @@ test_executable("shared_unittests") { |
3247 | "//base", |
3248 | "//base/test:test_support", |
3249 | "//cc", |
3250 | + "//components/prefs:test_support", |
3251 | "//content/public/browser", |
3252 | "//content/public/common", |
3253 | "//content/test:test_support", |
3254 | @@ -729,6 +757,7 @@ test_executable("shared_unittests") { |
3255 | ] |
3256 | |
3257 | sources = [ |
3258 | + "browser/filtered_pref_store_unittest.cc", |
3259 | "browser/javascript_dialogs/javascript_dialog_contents_helper_unittest.cc", |
3260 | "browser/javascript_dialogs/javascript_dialog_host_unittest.cc", |
3261 | "browser/javascript_dialogs/javascript_dialog_testing_utils.cc", |
3262 | diff --git a/shared/browser/autofill/autofill_client.cc b/shared/browser/autofill/autofill_client.cc |
3263 | new file mode 100644 |
3264 | index 0000000..bbf22ee |
3265 | --- /dev/null |
3266 | +++ b/shared/browser/autofill/autofill_client.cc |
3267 | @@ -0,0 +1,272 @@ |
3268 | +// vim:expandtab:shiftwidth=2:tabstop=2: |
3269 | +// Copyright (C) 2016-2017 Canonical Ltd. |
3270 | + |
3271 | +// This library is free software; you can redistribute it and/or |
3272 | +// modify it under the terms of the GNU Lesser General Public |
3273 | +// License as published by the Free Software Foundation; either |
3274 | +// version 2.1 of the License, or (at your option) any later version. |
3275 | + |
3276 | +// This library is distributed in the hope that it will be useful, |
3277 | +// but WITHOUT ANY WARRANTY; without even the implied warranty of |
3278 | +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
3279 | +// Lesser General Public License for more details. |
3280 | + |
3281 | +// You should have received a copy of the GNU Lesser General Public |
3282 | +// License along with this library; if not, write to the Free Software |
3283 | +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
3284 | + |
3285 | +#include "autofill_client.h" |
3286 | + |
3287 | +#include "base/logging.h" |
3288 | +#include "components/autofill/content/browser/content_autofill_driver.h" |
3289 | +#include "components/autofill/content/browser/content_autofill_driver_factory.h" |
3290 | +#include "components/autofill/core/common/autofill_pref_names.h" |
3291 | +#include "components/prefs/pref_service.h" |
3292 | +#include "content/public/browser/browser_context.h" |
3293 | +#include "content/public/browser/navigation_entry.h" |
3294 | +#include "content/public/browser/render_frame_host.h" |
3295 | +#include "content/public/browser/ssl_status.h" |
3296 | +#include "google_apis/gaia/identity_provider.h" |
3297 | + |
3298 | +#include "shared/browser/oxide_browser_context.h" |
3299 | +#include "shared/browser/personal_data_manager_factory.h" |
3300 | +#include "shared/browser/web_data_service_factory.h" |
3301 | + |
3302 | +#include "autofill_popup_controller.h" |
3303 | + |
3304 | +namespace oxide { |
3305 | + |
3306 | +DEFINE_WEB_CONTENTS_USER_DATA_KEY(oxide::AutofillClient); |
3307 | + |
3308 | +class DummyIdentityProvider : public IdentityProvider { |
3309 | + public: |
3310 | + explicit DummyIdentityProvider(); |
3311 | + ~DummyIdentityProvider() override; |
3312 | + |
3313 | + std::string GetActiveUsername() override; |
3314 | + std::string GetActiveAccountId() override; |
3315 | + OAuth2TokenService* GetTokenService() override; |
3316 | + bool RequestLogin() override; |
3317 | + |
3318 | + private: |
3319 | + DISALLOW_COPY_AND_ASSIGN(DummyIdentityProvider); |
3320 | +}; |
3321 | + |
3322 | +DummyIdentityProvider::DummyIdentityProvider() {} |
3323 | + |
3324 | +DummyIdentityProvider::~DummyIdentityProvider() {} |
3325 | + |
3326 | +std::string DummyIdentityProvider::GetActiveUsername() { |
3327 | + return std::string(); |
3328 | +} |
3329 | + |
3330 | +std::string DummyIdentityProvider::GetActiveAccountId() { |
3331 | + return std::string(); |
3332 | +} |
3333 | + |
3334 | +OAuth2TokenService* DummyIdentityProvider::GetTokenService() { |
3335 | + return nullptr; |
3336 | +} |
3337 | + |
3338 | +bool DummyIdentityProvider::RequestLogin() { |
3339 | + return false; |
3340 | +} |
3341 | + |
3342 | +AutofillClient::AutofillClient(content::WebContents* web_contents) |
3343 | + : content::WebContentsObserver(web_contents) { |
3344 | + DCHECK(web_contents); |
3345 | +} |
3346 | + |
3347 | +AutofillClient::~AutofillClient() { |
3348 | + DCHECK(!popup_controller_); |
3349 | +} |
3350 | + |
3351 | +void AutofillClient::DidHideAutofillPopup() { |
3352 | + DCHECK(popup_controller_); |
3353 | + |
3354 | + base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, |
3355 | + popup_controller_.release()); |
3356 | +} |
3357 | + |
3358 | +autofill::PersonalDataManager* AutofillClient::GetPersonalDataManager() { |
3359 | + return PersonalDataManagerFactory::GetForContext( |
3360 | + web_contents()->GetBrowserContext()); |
3361 | +} |
3362 | + |
3363 | +scoped_refptr<autofill::AutofillWebDataService> |
3364 | +AutofillClient::GetDatabase() { |
3365 | + return WebDataServiceFactory::GetAutofillWebDataForContext( |
3366 | + web_contents()->GetBrowserContext()); |
3367 | +} |
3368 | + |
3369 | +PrefService* AutofillClient::GetPrefs() { |
3370 | + return BrowserContext::FromContent(web_contents()->GetBrowserContext()) |
3371 | + ->GetPrefs(); |
3372 | +} |
3373 | + |
3374 | +syncer::SyncService* AutofillClient::GetSyncService() { |
3375 | + return nullptr; |
3376 | +} |
3377 | + |
3378 | +IdentityProvider* AutofillClient::GetIdentityProvider() { |
3379 | + if (!identity_provider_) { |
3380 | + identity_provider_.reset(new DummyIdentityProvider()); |
3381 | + } |
3382 | + |
3383 | + return identity_provider_.get(); |
3384 | +} |
3385 | + |
3386 | +rappor::RapporServiceImpl* AutofillClient::GetRapporServiceImpl() { |
3387 | + return nullptr; |
3388 | +} |
3389 | + |
3390 | +ukm::UkmService* AutofillClient::GetUkmService() { |
3391 | + return nullptr; |
3392 | +} |
3393 | + |
3394 | +void AutofillClient::ShowAutofillSettings() { |
3395 | + NOTIMPLEMENTED(); |
3396 | +} |
3397 | + |
3398 | +void AutofillClient::ShowUnmaskPrompt( |
3399 | + const autofill::CreditCard& card, |
3400 | + UnmaskCardReason reason, |
3401 | + base::WeakPtr<autofill::CardUnmaskDelegate> delegate) { |
3402 | + NOTIMPLEMENTED(); |
3403 | +} |
3404 | + |
3405 | +void AutofillClient::OnUnmaskVerificationResult( |
3406 | + PaymentsRpcResult result) { |
3407 | + NOTIMPLEMENTED(); |
3408 | +} |
3409 | + |
3410 | +void AutofillClient::ConfirmSaveCreditCardLocally( |
3411 | + const autofill::CreditCard& card, |
3412 | + const base::Closure& callback) { |
3413 | + NOTIMPLEMENTED(); |
3414 | +} |
3415 | + |
3416 | +void AutofillClient::ConfirmSaveCreditCardToCloud( |
3417 | + const autofill::CreditCard& card, |
3418 | + std::unique_ptr<base::DictionaryValue> legal_message, |
3419 | + const base::Closure& callback) { |
3420 | + NOTIMPLEMENTED(); |
3421 | +} |
3422 | + |
3423 | +void AutofillClient::ConfirmCreditCardFillAssist( |
3424 | + const autofill::CreditCard& card, |
3425 | + const base::Closure& callback) { |
3426 | + NOTIMPLEMENTED(); |
3427 | +} |
3428 | + |
3429 | +void AutofillClient::LoadRiskData( |
3430 | + const base::Callback<void(const std::string&)>& callback) { |
3431 | + NOTIMPLEMENTED(); |
3432 | +} |
3433 | + |
3434 | +bool AutofillClient::HasCreditCardScanFeature() { |
3435 | + return false; |
3436 | +} |
3437 | + |
3438 | +void AutofillClient::ScanCreditCard( |
3439 | + const CreditCardScanCallback& callback) { |
3440 | + NOTIMPLEMENTED(); |
3441 | +} |
3442 | + |
3443 | +void AutofillClient::ShowAutofillPopup( |
3444 | + const gfx::RectF& element_bounds, |
3445 | + base::i18n::TextDirection text_direction, |
3446 | + const std::vector<autofill::Suggestion>& suggestions, |
3447 | + base::WeakPtr<autofill::AutofillPopupDelegate> delegate) { |
3448 | + // Will delete or reuse the old |popup_controller_|. |
3449 | + popup_controller_.reset( |
3450 | + AutofillPopupController::GetOrCreate( |
3451 | + popup_controller_, delegate, web_contents(), element_bounds, |
3452 | + text_direction, base::Bind(&AutofillClient::DidHideAutofillPopup, |
3453 | + base::Unretained(this)))); |
3454 | + |
3455 | + popup_controller_->Show(suggestions); |
3456 | +} |
3457 | + |
3458 | +void AutofillClient::UpdateAutofillPopupDataListValues( |
3459 | + const std::vector<base::string16>& values, |
3460 | + const std::vector<base::string16>& labels) { |
3461 | + if (popup_controller_.get()) { |
3462 | + popup_controller_->UpdateDataListValues(values, labels); |
3463 | + } |
3464 | +} |
3465 | + |
3466 | +void AutofillClient::HideAutofillPopup() { |
3467 | + if (popup_controller_.get()) { |
3468 | + popup_controller_->Hide(); |
3469 | + } |
3470 | +} |
3471 | + |
3472 | +bool AutofillClient::IsAutocompleteEnabled() { |
3473 | + return GetPrefs()->GetBoolean(autofill::prefs::kAutofillEnabled); |
3474 | +} |
3475 | + |
3476 | +void AutofillClient::MainFrameWasResized(bool width_changed) { |
3477 | + HideAutofillPopup(); |
3478 | +} |
3479 | + |
3480 | +void AutofillClient::WebContentsDestroyed() { |
3481 | + HideAutofillPopup(); |
3482 | +} |
3483 | + |
3484 | +void AutofillClient::PropagateAutofillPredictions( |
3485 | + content::RenderFrameHost* rfh, |
3486 | + const std::vector<autofill::FormStructure*>& forms) { |
3487 | + NOTIMPLEMENTED(); |
3488 | +} |
3489 | + |
3490 | +void AutofillClient::DidFillOrPreviewField( |
3491 | + const base::string16& autofilled_value, |
3492 | + const base::string16& profile_full_name) {} |
3493 | + |
3494 | +void AutofillClient::OnFirstUserGestureObserved() { |
3495 | + autofill::ContentAutofillDriverFactory* factory = |
3496 | + autofill::ContentAutofillDriverFactory::FromWebContents(web_contents()); |
3497 | + DCHECK(factory); |
3498 | + |
3499 | + for (content::RenderFrameHost* frame : web_contents()->GetAllFrames()) { |
3500 | + if (!frame->IsRenderFrameLive()) { |
3501 | + continue; |
3502 | + } |
3503 | + autofill::ContentAutofillDriver* driver = factory->DriverForFrame(frame); |
3504 | + DCHECK(driver); |
3505 | + driver->NotifyFirstUserGestureObservedInTab(); |
3506 | + } |
3507 | +} |
3508 | + |
3509 | +bool AutofillClient::IsContextSecure() { |
3510 | + content::SSLStatus ssl_status; |
3511 | + content::NavigationEntry* navigation_entry = |
3512 | + web_contents()->GetController().GetLastCommittedEntry(); |
3513 | + if (!navigation_entry) { |
3514 | + return false; |
3515 | + } |
3516 | + |
3517 | + ssl_status = navigation_entry->GetSSL(); |
3518 | + return navigation_entry->GetURL().SchemeIsCryptographic() && |
3519 | + ssl_status.certificate && |
3520 | + (!net::IsCertStatusError(ssl_status.cert_status) || |
3521 | + net::IsCertStatusMinorError(ssl_status.cert_status)) && |
3522 | + !(ssl_status.content_status & |
3523 | + content::SSLStatus::RAN_INSECURE_CONTENT); |
3524 | +} |
3525 | + |
3526 | +bool AutofillClient::ShouldShowSigninPromo() { |
3527 | + NOTIMPLEMENTED(); |
3528 | + return false; |
3529 | +} |
3530 | + |
3531 | +void AutofillClient::StartSigninFlow() { |
3532 | + NOTIMPLEMENTED(); |
3533 | +} |
3534 | + |
3535 | +void AutofillClient::ShowHttpNotSecureExplanation() { |
3536 | + NOTIMPLEMENTED(); |
3537 | +} |
3538 | + |
3539 | +} // namespace oxide |
3540 | diff --git a/shared/browser/autofill/autofill_client.h b/shared/browser/autofill/autofill_client.h |
3541 | new file mode 100644 |
3542 | index 0000000..b31fe3c |
3543 | --- /dev/null |
3544 | +++ b/shared/browser/autofill/autofill_client.h |
3545 | @@ -0,0 +1,116 @@ |
3546 | +// vim:expandtab:shiftwidth=2:tabstop=2: |
3547 | +// Copyright (C) 2016-2017 Canonical Ltd. |
3548 | + |
3549 | +// This library is free software; you can redistribute it and/or |
3550 | +// modify it under the terms of the GNU Lesser General Public |
3551 | +// License as published by the Free Software Foundation; either |
3552 | +// version 2.1 of the License, or (at your option) any later version. |
3553 | + |
3554 | +// This library is distributed in the hope that it will be useful, |
3555 | +// but WITHOUT ANY WARRANTY; without even the implied warranty of |
3556 | +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
3557 | +// Lesser General Public License for more details. |
3558 | + |
3559 | +// You should have received a copy of the GNU Lesser General Public |
3560 | +// License along with this library; if not, write to the Free Software |
3561 | +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
3562 | + |
3563 | +#ifndef _OXIDE_SHARED_BROWSER_AUTOFILL_AUTOFILL_CLIENT_H_ |
3564 | +#define _OXIDE_SHARED_BROWSER_AUTOFILL_AUTOFILL_CLIENT_H_ |
3565 | + |
3566 | +#include <memory> |
3567 | +#include <string> |
3568 | +#include <vector> |
3569 | + |
3570 | +#include "base/callback.h" |
3571 | +#include "base/compiler_specific.h" |
3572 | +#include "base/i18n/rtl.h" |
3573 | +#include "base/macros.h" |
3574 | +#include "base/memory/weak_ptr.h" |
3575 | +#include "components/autofill/core/browser/autofill_client.h" |
3576 | +#include "content/public/browser/web_contents_observer.h" |
3577 | +#include "content/public/browser/web_contents_user_data.h" |
3578 | + |
3579 | +namespace content { |
3580 | +class WebContents; |
3581 | +} |
3582 | + |
3583 | +namespace oxide { |
3584 | + |
3585 | +class AutofillPopupController; |
3586 | +class DummyIdentityProvider; |
3587 | + |
3588 | +class AutofillClient |
3589 | + : public autofill::AutofillClient, |
3590 | + public content::WebContentsUserData<AutofillClient>, |
3591 | + public content::WebContentsObserver { |
3592 | + public: |
3593 | + ~AutofillClient() override; |
3594 | + |
3595 | + // AutofillClient: |
3596 | + autofill::PersonalDataManager* GetPersonalDataManager() override; |
3597 | + scoped_refptr<autofill::AutofillWebDataService> GetDatabase() override; |
3598 | + PrefService* GetPrefs() override; |
3599 | + syncer::SyncService* GetSyncService() override; |
3600 | + IdentityProvider* GetIdentityProvider() override; |
3601 | + rappor::RapporServiceImpl* GetRapporServiceImpl() override; |
3602 | + ukm::UkmService* GetUkmService() override; |
3603 | + void ShowAutofillSettings() override; |
3604 | + void ShowUnmaskPrompt( |
3605 | + const autofill::CreditCard& card, |
3606 | + UnmaskCardReason reason, |
3607 | + base::WeakPtr<autofill::CardUnmaskDelegate> delegate) override; |
3608 | + void OnUnmaskVerificationResult(PaymentsRpcResult result) override; |
3609 | + void ConfirmSaveCreditCardLocally(const autofill::CreditCard& card, |
3610 | + const base::Closure& callback) override; |
3611 | + void ConfirmSaveCreditCardToCloud( |
3612 | + const autofill::CreditCard& card, |
3613 | + std::unique_ptr<base::DictionaryValue> legal_message, |
3614 | + const base::Closure& callback) override; |
3615 | + void ConfirmCreditCardFillAssist(const autofill::CreditCard& card, |
3616 | + const base::Closure& callback) override; |
3617 | + void LoadRiskData( |
3618 | + const base::Callback<void(const std::string&)>& callback) override; |
3619 | + bool HasCreditCardScanFeature() override; |
3620 | + void ScanCreditCard(const CreditCardScanCallback& callback) override; |
3621 | + void ShowAutofillPopup( |
3622 | + const gfx::RectF& element_bounds, |
3623 | + base::i18n::TextDirection text_direction, |
3624 | + const std::vector<autofill::Suggestion>& suggestions, |
3625 | + base::WeakPtr<autofill::AutofillPopupDelegate> delegate) override; |
3626 | + void UpdateAutofillPopupDataListValues( |
3627 | + const std::vector<base::string16>& values, |
3628 | + const std::vector<base::string16>& labels) override; |
3629 | + void HideAutofillPopup() override; |
3630 | + bool IsAutocompleteEnabled() override; |
3631 | + void PropagateAutofillPredictions( |
3632 | + content::RenderFrameHost* rfh, |
3633 | + const std::vector<autofill::FormStructure*>& forms) override; |
3634 | + void DidFillOrPreviewField(const base::string16& autofilled_value, |
3635 | + const base::string16& profile_full_name) override; |
3636 | + void OnFirstUserGestureObserved() override; |
3637 | + bool IsContextSecure() override; |
3638 | + bool ShouldShowSigninPromo() override; |
3639 | + void StartSigninFlow() override; |
3640 | + void ShowHttpNotSecureExplanation() override; |
3641 | + |
3642 | + // content::WebContentsObserver implementation. |
3643 | + void MainFrameWasResized(bool width_changed) override; |
3644 | + void WebContentsDestroyed() override; |
3645 | + |
3646 | + private: |
3647 | + explicit AutofillClient(content::WebContents* web_contents); |
3648 | + friend class content::WebContentsUserData<AutofillClient>; |
3649 | + |
3650 | + void DidHideAutofillPopup(); |
3651 | + |
3652 | + std::unique_ptr<AutofillPopupController> popup_controller_; |
3653 | + |
3654 | + std::unique_ptr<DummyIdentityProvider> identity_provider_; |
3655 | + |
3656 | + DISALLOW_COPY_AND_ASSIGN(AutofillClient); |
3657 | +}; |
3658 | + |
3659 | +} // namespace oxide |
3660 | + |
3661 | +#endif // _OXIDE_SHARED_BROWSER_AUTOFILL_AUTOFILL_CLIENT_H_ |
3662 | diff --git a/shared/browser/autofill/autofill_popup_controller.cc b/shared/browser/autofill/autofill_popup_controller.cc |
3663 | new file mode 100644 |
3664 | index 0000000..a79fe61 |
3665 | --- /dev/null |
3666 | +++ b/shared/browser/autofill/autofill_popup_controller.cc |
3667 | @@ -0,0 +1,163 @@ |
3668 | +// vim:expandtab:shiftwidth=2:tabstop=2: |
3669 | +// Copyright (C) 2017 Canonical Ltd. |
3670 | + |
3671 | +// This library is free software; you can redistribute it and/or |
3672 | +// modify it under the terms of the GNU Lesser General Public |
3673 | +// License as published by the Free Software Foundation; either |
3674 | +// version 2.1 of the License, or (at your option) any later version. |
3675 | + |
3676 | +// This library is distributed in the hope that it will be useful, |
3677 | +// but WITHOUT ANY WARRANTY; without even the implied warranty of |
3678 | +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
3679 | +// Lesser General Public License for more details. |
3680 | + |
3681 | +// You should have received a copy of the GNU Lesser General Public |
3682 | +// License along with this library; if not, write to the Free Software |
3683 | +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
3684 | + |
3685 | +#include "autofill_popup_controller.h" |
3686 | + |
3687 | +#include "components/autofill/core/browser/autofill_popup_delegate.h" |
3688 | +#include "components/autofill/core/browser/suggestion.h" |
3689 | + |
3690 | +#include "shared/browser/chrome_controller.h" |
3691 | +#include "shared/browser/oxide_web_contents_view.h" |
3692 | +#include "shared/browser/oxide_web_contents_view_client.h" |
3693 | +#include "shared/browser/web_contents_client.h" |
3694 | +#include "shared/browser/web_contents_helper.h" |
3695 | + |
3696 | +#include "web_autofill_popup.h" |
3697 | + |
3698 | +namespace oxide { |
3699 | + |
3700 | +// static |
3701 | +AutofillPopupController* AutofillPopupController::GetOrCreate( |
3702 | + std::unique_ptr<AutofillPopupController>& previous, |
3703 | + base::WeakPtr<autofill::AutofillPopupDelegate> delegate, |
3704 | + content::WebContents* web_contents, |
3705 | + const gfx::RectF& element_bounds, |
3706 | + base::i18n::TextDirection text_direction, |
3707 | + const base::Closure& hidden_callback) { |
3708 | + if (previous.get() && previous->web_contents_ == web_contents && |
3709 | + previous->delegate_.get() == delegate.get() && |
3710 | + previous->element_bounds_ == element_bounds) { |
3711 | + previous->ClearState(); |
3712 | + return previous.release(); |
3713 | + } |
3714 | + |
3715 | + if (previous.get()) { |
3716 | + previous->Hide(); |
3717 | + } |
3718 | + |
3719 | + return new AutofillPopupController( |
3720 | + delegate, web_contents, element_bounds, text_direction, hidden_callback); |
3721 | +} |
3722 | + |
3723 | +AutofillPopupController::AutofillPopupController( |
3724 | + base::WeakPtr<autofill::AutofillPopupDelegate> delegate, |
3725 | + content::WebContents* web_contents, |
3726 | + const gfx::RectF& element_bounds, |
3727 | + base::i18n::TextDirection text_direction, |
3728 | + const base::Closure& hidden_callback) |
3729 | + : web_contents_(web_contents), |
3730 | + element_bounds_(element_bounds), |
3731 | + delegate_(delegate), |
3732 | + hidden_callback_(hidden_callback) { |
3733 | + ClearState(); |
3734 | +} |
3735 | + |
3736 | +AutofillPopupController::~AutofillPopupController() { |
3737 | + hidden_callback_.Reset(); |
3738 | +} |
3739 | + |
3740 | +void AutofillPopupController::Show( |
3741 | + const std::vector<autofill::Suggestion>& suggestions) { |
3742 | + suggestions_ = suggestions; |
3743 | + |
3744 | + WebContentsHelper* helper = |
3745 | + WebContentsHelper::FromWebContents(web_contents_); |
3746 | + if (!helper->client()) { |
3747 | + return; |
3748 | + } |
3749 | + |
3750 | + gfx::Vector2d top_content_offset; |
3751 | + ChromeController* chrome_controller = |
3752 | + ChromeController::FromWebContents(web_contents_); |
3753 | + if (chrome_controller) { |
3754 | + top_content_offset = |
3755 | + gfx::Vector2d(0, chrome_controller->GetTopContentOffset()); |
3756 | + } |
3757 | + |
3758 | + popup_ = helper->client()->CreateAutofillPopup( |
3759 | + suggestions, element_bounds_ + top_content_offset, this); |
3760 | + if (!popup_) { |
3761 | + return; |
3762 | + } |
3763 | + |
3764 | + popup_->Show(); |
3765 | + |
3766 | + delegate_->OnPopupShown(); |
3767 | +} |
3768 | + |
3769 | +void AutofillPopupController::UpdateDataListValues( |
3770 | + const std::vector<base::string16>& values, |
3771 | + const std::vector<base::string16>& labels) { |
3772 | + if (popup_) { |
3773 | + popup_->UpdateDataListValues(values, labels); |
3774 | + } |
3775 | +} |
3776 | + |
3777 | +void AutofillPopupController::Hide() { |
3778 | + if (hidden_callback_.is_null()) { |
3779 | + return; |
3780 | + } |
3781 | + base::Closure hidden_callback = std::move(hidden_callback_); |
3782 | + hidden_callback_.Reset(); |
3783 | + |
3784 | + if (delegate_) { |
3785 | + delegate_->OnPopupHidden(); |
3786 | + } |
3787 | + |
3788 | + if (popup_) { |
3789 | + popup_->Hide(); |
3790 | + } |
3791 | + |
3792 | + hidden_callback.Run(); |
3793 | +} |
3794 | + |
3795 | +void AutofillPopupController::Close() { |
3796 | + Hide(); |
3797 | +} |
3798 | + |
3799 | +void AutofillPopupController::SelectSuggestion(int frontend_id, |
3800 | + const base::string16& value) { |
3801 | + delegate_->DidSelectSuggestion(value, frontend_id); |
3802 | +} |
3803 | + |
3804 | +void AutofillPopupController::ClearSelection() { |
3805 | + delegate_->ClearPreviewedForm(); |
3806 | +} |
3807 | + |
3808 | +void AutofillPopupController::AcceptSuggestion(int frontend_id, |
3809 | + const base::string16& value) { |
3810 | + int position = 0; |
3811 | + for (size_t i = 0; i < suggestions_.size(); ++i) { |
3812 | + const autofill::Suggestion& suggestion = suggestions_[i]; |
3813 | + if (suggestion.frontend_id == frontend_id && suggestion.value == value) { |
3814 | + position = i; |
3815 | + break; |
3816 | + } |
3817 | + } |
3818 | + delegate_->DidAcceptSuggestion(value, frontend_id, position); |
3819 | +} |
3820 | + |
3821 | +bool AutofillPopupController::RemoveSuggestion(int frontend_id, |
3822 | + const base::string16& value) { |
3823 | + return delegate_->RemoveSuggestion(value, frontend_id); |
3824 | +} |
3825 | + |
3826 | +void AutofillPopupController::ClearState() { |
3827 | + suggestions_.clear(); |
3828 | +} |
3829 | + |
3830 | +} // namespace oxide |
3831 | diff --git a/shared/browser/autofill/autofill_popup_controller.h b/shared/browser/autofill/autofill_popup_controller.h |
3832 | new file mode 100644 |
3833 | index 0000000..e7d9be0 |
3834 | --- /dev/null |
3835 | +++ b/shared/browser/autofill/autofill_popup_controller.h |
3836 | @@ -0,0 +1,92 @@ |
3837 | +// vim:expandtab:shiftwidth=2:tabstop=2: |
3838 | +// Copyright (C) 2017 Canonical Ltd. |
3839 | + |
3840 | +// This library is free software; you can redistribute it and/or |
3841 | +// modify it under the terms of the GNU Lesser General Public |
3842 | +// License as published by the Free Software Foundation; either |
3843 | +// version 2.1 of the License, or (at your option) any later version. |
3844 | + |
3845 | +// This library is distributed in the hope that it will be useful, |
3846 | +// but WITHOUT ANY WARRANTY; without even the implied warranty of |
3847 | +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
3848 | +// Lesser General Public License for more details. |
3849 | + |
3850 | +// You should have received a copy of the GNU Lesser General Public |
3851 | +// License along with this library; if not, write to the Free Software |
3852 | +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
3853 | + |
3854 | +#ifndef _OXIDE_SHARED_BROWSER_AUTOFILL_AUTOFILL_POPUP_CONTROLLER_H_ |
3855 | +#define _OXIDE_SHARED_BROWSER_AUTOFILL_AUTOFILL_POPUP_CONTROLLER_H_ |
3856 | + |
3857 | +#include <vector> |
3858 | + |
3859 | +#include "base/callback.h" |
3860 | +#include "base/i18n/rtl.h" |
3861 | +#include "base/memory/weak_ptr.h" |
3862 | +#include "base/strings/string16.h" |
3863 | +#include "ui/gfx/geometry/rect_f.h" |
3864 | +#include "ui/gfx/native_widget_types.h" |
3865 | + |
3866 | +#include "web_autofill_popup_client.h" |
3867 | + |
3868 | +namespace autofill { |
3869 | +class AutofillPopupDelegate; |
3870 | +struct Suggestion; |
3871 | +} |
3872 | + |
3873 | +namespace content { |
3874 | +class WebContents; |
3875 | +} |
3876 | + |
3877 | +namespace oxide { |
3878 | + |
3879 | +class WebAutofillPopup; |
3880 | + |
3881 | +class AutofillPopupController : public WebAutofillPopupClient { |
3882 | + public: |
3883 | + ~AutofillPopupController(); |
3884 | + |
3885 | + static AutofillPopupController* GetOrCreate( |
3886 | + std::unique_ptr<AutofillPopupController>& previous, |
3887 | + base::WeakPtr<autofill::AutofillPopupDelegate> delegate, |
3888 | + content::WebContents* web_contents, |
3889 | + const gfx::RectF& element_bounds, |
3890 | + base::i18n::TextDirection text_direction, |
3891 | + const base::Closure& hidden_callback); |
3892 | + |
3893 | + void Show(const std::vector<autofill::Suggestion>& suggestions); |
3894 | + void UpdateDataListValues(const std::vector<base::string16>& values, |
3895 | + const std::vector<base::string16>& labels); |
3896 | + void Hide(); |
3897 | + |
3898 | + private: |
3899 | + AutofillPopupController( |
3900 | + base::WeakPtr<autofill::AutofillPopupDelegate> delegate, |
3901 | + content::WebContents* web_contents, |
3902 | + const gfx::RectF& element_bounds, |
3903 | + base::i18n::TextDirection text_direction, |
3904 | + const base::Closure& hidden_callback); |
3905 | + |
3906 | + void ClearState(); |
3907 | + |
3908 | + // WebAutofillPopupClient implementation |
3909 | + void Close() override; |
3910 | + void SelectSuggestion(int frontend_id, const base::string16& value) override; |
3911 | + void ClearSelection() override; |
3912 | + void AcceptSuggestion(int frontend_id, const base::string16& value) override; |
3913 | + bool RemoveSuggestion(int frontend_id, const base::string16& value) override; |
3914 | + |
3915 | + content::WebContents* web_contents_; |
3916 | + gfx::RectF element_bounds_; |
3917 | + base::WeakPtr<autofill::AutofillPopupDelegate> delegate_; |
3918 | + base::i18n::TextDirection text_direction_; |
3919 | + std::vector<autofill::Suggestion> suggestions_; |
3920 | + |
3921 | + std::unique_ptr<WebAutofillPopup> popup_; |
3922 | + |
3923 | + base::Closure hidden_callback_; |
3924 | +}; |
3925 | + |
3926 | +} // namespace oxide |
3927 | + |
3928 | +#endif // _OXIDE_SHARED_BROWSER_AUTOFILL_AUTOFILL_POPUP_CONTROLLER_H_ |
3929 | diff --git a/shared/browser/autofill/web_autofill_popup.h b/shared/browser/autofill/web_autofill_popup.h |
3930 | new file mode 100644 |
3931 | index 0000000..7d58fdc |
3932 | --- /dev/null |
3933 | +++ b/shared/browser/autofill/web_autofill_popup.h |
3934 | @@ -0,0 +1,42 @@ |
3935 | +// vim:expandtab:shiftwidth=2:tabstop=2: |
3936 | +// Copyright (C) 2017 Canonical Ltd. |
3937 | + |
3938 | +// This library is free software; you can redistribute it and/or |
3939 | +// modify it under the terms of the GNU Lesser General Public |
3940 | +// License as published by the Free Software Foundation; either |
3941 | +// version 2.1 of the License, or (at your option) any later version. |
3942 | + |
3943 | +// This library is distributed in the hope that it will be useful, |
3944 | +// but WITHOUT ANY WARRANTY; without even the implied warranty of |
3945 | +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
3946 | +// Lesser General Public License for more details. |
3947 | + |
3948 | +// You should have received a copy of the GNU Lesser General Public |
3949 | +// License along with this library; if not, write to the Free Software |
3950 | +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
3951 | + |
3952 | +#ifndef _OXIDE_SHARED_BROWSER_WEB_AUTOFILL_POPUP_H_ |
3953 | +#define _OXIDE_SHARED_BROWSER_WEB_AUTOFILL_POPUP_H_ |
3954 | + |
3955 | +#include <vector> |
3956 | + |
3957 | +#include "base/strings/string16.h" |
3958 | + |
3959 | +namespace oxide { |
3960 | + |
3961 | +class WebAutofillPopup { |
3962 | + public: |
3963 | + virtual ~WebAutofillPopup() {} |
3964 | + |
3965 | + virtual void Show() = 0; |
3966 | + |
3967 | + virtual void UpdateDataListValues( |
3968 | + const std::vector<base::string16>& values, |
3969 | + const std::vector<base::string16>& labels) = 0; |
3970 | + |
3971 | + virtual void Hide() = 0; |
3972 | +}; |
3973 | + |
3974 | +} // namespace oxide |
3975 | + |
3976 | +#endif // _OXIDE_SHARED_BROWSER_WEB_AUTOFILL_POPUP_H_ |
3977 | diff --git a/shared/browser/autofill/web_autofill_popup_client.h b/shared/browser/autofill/web_autofill_popup_client.h |
3978 | new file mode 100644 |
3979 | index 0000000..4eecc06 |
3980 | --- /dev/null |
3981 | +++ b/shared/browser/autofill/web_autofill_popup_client.h |
3982 | @@ -0,0 +1,41 @@ |
3983 | +// vim:expandtab:shiftwidth=2:tabstop=2: |
3984 | +// Copyright (C) 2017 Canonical Ltd. |
3985 | + |
3986 | +// This library is free software; you can redistribute it and/or |
3987 | +// modify it under the terms of the GNU Lesser General Public |
3988 | +// License as published by the Free Software Foundation; either |
3989 | +// version 2.1 of the License, or (at your option) any later version. |
3990 | + |
3991 | +// This library is distributed in the hope that it will be useful, |
3992 | +// but WITHOUT ANY WARRANTY; without even the implied warranty of |
3993 | +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
3994 | +// Lesser General Public License for more details. |
3995 | + |
3996 | +// You should have received a copy of the GNU Lesser General Public |
3997 | +// License along with this library; if not, write to the Free Software |
3998 | +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
3999 | + |
4000 | +#ifndef _OXIDE_SHARED_BROWSER_AUTOFILL_WEB_AUTOFILL_POPUP_CLIENT_H_ |
4001 | +#define _OXIDE_SHARED_BROWSER_AUTOFILL_WEB_AUTOFILL_POPUP_CLIENT_H_ |
4002 | + |
4003 | +#include "base/strings/string16.h" |
4004 | + |
4005 | +namespace oxide { |
4006 | + |
4007 | +class WebAutofillPopupClient { |
4008 | + public: |
4009 | + virtual ~WebAutofillPopupClient() {} |
4010 | + |
4011 | + virtual void Close() = 0; |
4012 | + virtual void SelectSuggestion(int frontend_id, |
4013 | + const base::string16& value) = 0; |
4014 | + virtual void ClearSelection() = 0; |
4015 | + virtual void AcceptSuggestion(int frontend_id, |
4016 | + const base::string16& value) = 0; |
4017 | + virtual bool RemoveSuggestion(int frontend_id, |
4018 | + const base::string16& value) = 0; |
4019 | +}; |
4020 | + |
4021 | +} // namespace oxide |
4022 | + |
4023 | +#endif // _OXIDE_SHARED_BROWSER_AUTOFILL_WEB_AUTOFILL_POPUP_CLIENT_H_ |
4024 | diff --git a/shared/browser/filtered_pref_store.cc b/shared/browser/filtered_pref_store.cc |
4025 | new file mode 100644 |
4026 | index 0000000..bfc7931 |
4027 | --- /dev/null |
4028 | +++ b/shared/browser/filtered_pref_store.cc |
4029 | @@ -0,0 +1,181 @@ |
4030 | +// vim:expandtab:shiftwidth=2:tabstop=2: |
4031 | +// Copyright (C) 2017 Canonical Ltd. |
4032 | + |
4033 | +// This library is free software; you can redistribute it and/or |
4034 | +// modify it under the terms of the GNU Lesser General Public |
4035 | +// License as published by the Free Software Foundation; either |
4036 | +// version 2.1 of the License, or (at your option) any later version. |
4037 | + |
4038 | +// This library is distributed in the hope that it will be useful, |
4039 | +// but WITHOUT ANY WARRANTY; without even the implied warranty of |
4040 | +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
4041 | +// Lesser General Public License for more details. |
4042 | + |
4043 | +// You should have received a copy of the GNU Lesser General Public |
4044 | +// License along with this library; if not, write to the Free Software |
4045 | +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
4046 | + |
4047 | +#include "filtered_pref_store.h" |
4048 | + |
4049 | +#include "base/stl_util.h" |
4050 | +#include "base/values.h" |
4051 | +#include "components/prefs/in_memory_pref_store.h" |
4052 | +#include "components/prefs/json_pref_store.h" |
4053 | + |
4054 | +namespace oxide { |
4055 | + |
4056 | +FilteredPrefStore::AggregatingObserver::AggregatingObserver( |
4057 | + FilteredPrefStore* outer) |
4058 | + : outer_(outer) {} |
4059 | + |
4060 | +void FilteredPrefStore::AggregatingObserver::OnPrefValueChanged( |
4061 | + const std::string& key) { |
4062 | + if (!outer_->IsInitializationComplete()) { |
4063 | + return; |
4064 | + } |
4065 | + |
4066 | + for (auto& observer : outer_->observers_) { |
4067 | + observer.OnPrefValueChanged(key); |
4068 | + } |
4069 | +} |
4070 | + |
4071 | +void FilteredPrefStore::AggregatingObserver::OnInitializationCompleted( |
4072 | + bool succeeded) { |
4073 | + // This always comes the persistent pref store. In-memory pref stores don't |
4074 | + // notify observers of their initialization status. |
4075 | + if (succeeded && outer_->read_error_delegate_) { |
4076 | + PersistentPrefStore::PrefReadError read_error = outer_->GetReadError(); |
4077 | + if (read_error != PersistentPrefStore::PREF_READ_ERROR_NONE) |
4078 | + outer_->read_error_delegate_->OnError(read_error); |
4079 | + } |
4080 | + |
4081 | + for (auto& observer : outer_->observers_) { |
4082 | + observer.OnInitializationCompleted(true); |
4083 | + } |
4084 | +} |
4085 | + |
4086 | +FilteredPrefStore::FilteredPrefStore( |
4087 | + const scoped_refptr<InMemoryPrefStore>& volatile_pref_store, |
4088 | + const scoped_refptr<JsonPrefStore>& persistent_pref_store, |
4089 | + const std::set<std::string>& persistent_pref_names) |
4090 | + : volatile_pref_store_(volatile_pref_store), |
4091 | + persistent_pref_store_(persistent_pref_store), |
4092 | + persistent_preference_names_(persistent_pref_names), |
4093 | + aggregating_observer_(this) { |
4094 | + volatile_pref_store_->AddObserver(&aggregating_observer_); |
4095 | + persistent_pref_store_->AddObserver(&aggregating_observer_); |
4096 | +} |
4097 | + |
4098 | +void FilteredPrefStore::AddObserver(Observer* observer) { |
4099 | + observers_.AddObserver(observer); |
4100 | +} |
4101 | + |
4102 | +void FilteredPrefStore::RemoveObserver(Observer* observer) { |
4103 | + observers_.RemoveObserver(observer); |
4104 | +} |
4105 | + |
4106 | +bool FilteredPrefStore::HasObservers() const { |
4107 | + return observers_.might_have_observers(); |
4108 | +} |
4109 | + |
4110 | +bool FilteredPrefStore::IsInitializationComplete() const { |
4111 | + return persistent_pref_store_->IsInitializationComplete(); |
4112 | +} |
4113 | + |
4114 | +bool FilteredPrefStore::GetValue(const std::string& key, |
4115 | + const base::Value** result) const { |
4116 | + return StoreForKey(key)->GetValue(key, result); |
4117 | +} |
4118 | + |
4119 | +std::unique_ptr<base::DictionaryValue> FilteredPrefStore::GetValues() const { |
4120 | + auto values = volatile_pref_store_->GetValues(); |
4121 | + auto persistent_pref_store_values = persistent_pref_store_->GetValues(); |
4122 | + for (const auto& key : persistent_preference_names_) { |
4123 | + const base::Value* value = nullptr; |
4124 | + if (persistent_pref_store_values->Get(key, &value)) { |
4125 | + values->Set(key, value->CreateDeepCopy()); |
4126 | + } else { |
4127 | + values->Remove(key, nullptr); |
4128 | + } |
4129 | + } |
4130 | + return values; |
4131 | +} |
4132 | + |
4133 | +void FilteredPrefStore::SetValue(const std::string& key, |
4134 | + std::unique_ptr<base::Value> value, |
4135 | + uint32_t flags) { |
4136 | + StoreForKey(key)->SetValue(key, std::move(value), flags); |
4137 | +} |
4138 | + |
4139 | +void FilteredPrefStore::RemoveValue(const std::string& key, uint32_t flags) { |
4140 | + StoreForKey(key)->RemoveValue(key, flags); |
4141 | +} |
4142 | + |
4143 | +bool FilteredPrefStore::GetMutableValue(const std::string& key, |
4144 | + base::Value** result) { |
4145 | + return StoreForKey(key)->GetMutableValue(key, result); |
4146 | +} |
4147 | + |
4148 | +void FilteredPrefStore::ReportValueChanged(const std::string& key, |
4149 | + uint32_t flags) { |
4150 | + StoreForKey(key)->ReportValueChanged(key, flags); |
4151 | +} |
4152 | + |
4153 | +void FilteredPrefStore::SetValueSilently(const std::string& key, |
4154 | + std::unique_ptr<base::Value> value, |
4155 | + uint32_t flags) { |
4156 | + StoreForKey(key)->SetValueSilently(key, std::move(value), flags); |
4157 | +} |
4158 | + |
4159 | +bool FilteredPrefStore::ReadOnly() const { |
4160 | + return persistent_pref_store_->ReadOnly(); |
4161 | +} |
4162 | + |
4163 | +PersistentPrefStore::PrefReadError FilteredPrefStore::GetReadError() const { |
4164 | + return persistent_pref_store_->GetReadError(); |
4165 | +} |
4166 | + |
4167 | +PersistentPrefStore::PrefReadError FilteredPrefStore::ReadPrefs() { |
4168 | + return persistent_pref_store_->ReadPrefs(); |
4169 | +} |
4170 | + |
4171 | +void FilteredPrefStore::ReadPrefsAsync(ReadErrorDelegate* error_delegate) { |
4172 | + read_error_delegate_.reset(error_delegate); |
4173 | + persistent_pref_store_->ReadPrefsAsync(nullptr); |
4174 | +} |
4175 | + |
4176 | +void FilteredPrefStore::CommitPendingWrite() { |
4177 | + persistent_pref_store_->CommitPendingWrite(); |
4178 | +} |
4179 | + |
4180 | +void FilteredPrefStore::SchedulePendingLossyWrites() { |
4181 | + persistent_pref_store_->SchedulePendingLossyWrites(); |
4182 | +} |
4183 | + |
4184 | +void FilteredPrefStore::ClearMutableValues() { |
4185 | + NOTIMPLEMENTED(); |
4186 | +} |
4187 | + |
4188 | +FilteredPrefStore::~FilteredPrefStore() { |
4189 | + volatile_pref_store_->RemoveObserver(&aggregating_observer_); |
4190 | + persistent_pref_store_->RemoveObserver(&aggregating_observer_); |
4191 | +} |
4192 | + |
4193 | +PersistentPrefStore* FilteredPrefStore::StoreForKey(const std::string& key) { |
4194 | + if (base::ContainsKey(persistent_preference_names_, key)) { |
4195 | + return persistent_pref_store_.get(); |
4196 | + } else { |
4197 | + return volatile_pref_store_.get(); |
4198 | + } |
4199 | +} |
4200 | + |
4201 | +const PersistentPrefStore* FilteredPrefStore::StoreForKey( |
4202 | + const std::string& key) const { |
4203 | + if (base::ContainsKey(persistent_preference_names_, key)) { |
4204 | + return persistent_pref_store_.get(); |
4205 | + } else { |
4206 | + return volatile_pref_store_.get(); |
4207 | + } |
4208 | +} |
4209 | + |
4210 | +} // namespace oxide |
4211 | diff --git a/shared/browser/filtered_pref_store.h b/shared/browser/filtered_pref_store.h |
4212 | new file mode 100644 |
4213 | index 0000000..07eee99 |
4214 | --- /dev/null |
4215 | +++ b/shared/browser/filtered_pref_store.h |
4216 | @@ -0,0 +1,107 @@ |
4217 | +// vim:expandtab:shiftwidth=2:tabstop=2: |
4218 | +// Copyright (C) 2017 Canonical Ltd. |
4219 | + |
4220 | +// This library is free software; you can redistribute it and/or |
4221 | +// modify it under the terms of the GNU Lesser General Public |
4222 | +// License as published by the Free Software Foundation; either |
4223 | +// version 2.1 of the License, or (at your option) any later version. |
4224 | + |
4225 | +// This library is distributed in the hope that it will be useful, |
4226 | +// but WITHOUT ANY WARRANTY; without even the implied warranty of |
4227 | +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
4228 | +// Lesser General Public License for more details. |
4229 | + |
4230 | +// You should have received a copy of the GNU Lesser General Public |
4231 | +// License along with this library; if not, write to the Free Software |
4232 | +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
4233 | + |
4234 | +#ifndef _OXIDE_SHARED_BROWSER_FILTERED_PREF_STORE_H_ |
4235 | +#define _OXIDE_SHARED_BROWSER_FILTERED_PREF_STORE_H_ |
4236 | + |
4237 | +#include <set> |
4238 | +#include <string> |
4239 | + |
4240 | +#include "base/macros.h" |
4241 | +#include "base/memory/ref_counted.h" |
4242 | +#include "base/observer_list.h" |
4243 | +#include "components/prefs/persistent_pref_store.h" |
4244 | + |
4245 | +class InMemoryPrefStore; |
4246 | +class JsonPrefStore; |
4247 | + |
4248 | +namespace oxide { |
4249 | + |
4250 | +// Inspired by chromium's SegregatedPrefStore:Â all preferences are stored |
4251 | +// in memory (and thus not persisted) except for a selected set which are |
4252 | +// persisted on disk. |
4253 | +class FilteredPrefStore : public PersistentPrefStore { |
4254 | + public: |
4255 | + FilteredPrefStore( |
4256 | + const scoped_refptr<InMemoryPrefStore>& volatile_pref_store, |
4257 | + const scoped_refptr<JsonPrefStore>& persistent_pref_store, |
4258 | + const std::set<std::string>& persistent_pref_names); |
4259 | + |
4260 | + // PrefStore: |
4261 | + void AddObserver(Observer* observer) override; |
4262 | + void RemoveObserver(Observer* observer) override; |
4263 | + bool HasObservers() const override; |
4264 | + bool IsInitializationComplete() const override; |
4265 | + bool GetValue(const std::string& key, |
4266 | + const base::Value** result) const override; |
4267 | + std::unique_ptr<base::DictionaryValue> GetValues() const override; |
4268 | + |
4269 | + // WriteablePrefStore: |
4270 | + void SetValue(const std::string& key, |
4271 | + std::unique_ptr<base::Value> value, |
4272 | + uint32_t flags) override; |
4273 | + void RemoveValue(const std::string& key, uint32_t flags) override; |
4274 | + |
4275 | + // PersistentPrefStore: |
4276 | + bool GetMutableValue(const std::string& key, base::Value** result) override; |
4277 | + void ReportValueChanged(const std::string& key, uint32_t flags) override; |
4278 | + void SetValueSilently(const std::string& key, |
4279 | + std::unique_ptr<base::Value> value, |
4280 | + uint32_t flags) override; |
4281 | + bool ReadOnly() const override; |
4282 | + PrefReadError GetReadError() const override; |
4283 | + PrefReadError ReadPrefs() override; |
4284 | + void ReadPrefsAsync(ReadErrorDelegate* error_delegate) override; |
4285 | + void CommitPendingWrite() override; |
4286 | + void SchedulePendingLossyWrites() override; |
4287 | + |
4288 | + void ClearMutableValues() override; |
4289 | + |
4290 | + private: |
4291 | + class AggregatingObserver : public PrefStore::Observer { |
4292 | + public: |
4293 | + explicit AggregatingObserver(FilteredPrefStore* outer); |
4294 | + |
4295 | + // PrefStore::Observer: |
4296 | + void OnPrefValueChanged(const std::string& key) override; |
4297 | + void OnInitializationCompleted(bool succeeded) override; |
4298 | + |
4299 | + private: |
4300 | + FilteredPrefStore* outer_; |
4301 | + |
4302 | + DISALLOW_COPY_AND_ASSIGN(AggregatingObserver); |
4303 | + }; |
4304 | + |
4305 | + ~FilteredPrefStore() override; |
4306 | + |
4307 | + PersistentPrefStore* StoreForKey(const std::string& key); |
4308 | + const PersistentPrefStore* StoreForKey(const std::string& key) const; |
4309 | + |
4310 | + scoped_refptr<InMemoryPrefStore> volatile_pref_store_; |
4311 | + scoped_refptr<JsonPrefStore> persistent_pref_store_; |
4312 | + std::set<std::string> persistent_preference_names_; |
4313 | + |
4314 | + std::unique_ptr<PersistentPrefStore::ReadErrorDelegate> read_error_delegate_; |
4315 | + base::ObserverList<PrefStore::Observer, true> observers_; |
4316 | + AggregatingObserver aggregating_observer_; |
4317 | + |
4318 | + DISALLOW_COPY_AND_ASSIGN(FilteredPrefStore); |
4319 | +}; |
4320 | + |
4321 | +} // namespace oxide |
4322 | + |
4323 | +#endif // _OXIDE_SHARED_BROWSER_FILTERED_PREF_STORE_H_ |
4324 | diff --git a/shared/browser/filtered_pref_store_unittest.cc b/shared/browser/filtered_pref_store_unittest.cc |
4325 | new file mode 100644 |
4326 | index 0000000..90e67d8 |
4327 | --- /dev/null |
4328 | +++ b/shared/browser/filtered_pref_store_unittest.cc |
4329 | @@ -0,0 +1,209 @@ |
4330 | +// vim:expandtab:shiftwidth=2:tabstop=2: |
4331 | +// Copyright (C) 2017 Canonical Ltd. |
4332 | + |
4333 | +// This library is free software; you can redistribute it and/or |
4334 | +// modify it under the terms of the GNU Lesser General Public |
4335 | +// License as published by the Free Software Foundation; either |
4336 | +// version 2.1 of the License, or (at your option) any later version. |
4337 | + |
4338 | +// This library is distributed in the hope that it will be useful, |
4339 | +// but WITHOUT ANY WARRANTY; without even the implied warranty of |
4340 | +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
4341 | +// Lesser General Public License for more details. |
4342 | + |
4343 | +// You should have received a copy of the GNU Lesser General Public |
4344 | +// License along with this library; if not, write to the Free Software |
4345 | +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
4346 | + |
4347 | +#include "base/files/file_util.h" |
4348 | +#include "base/files/scoped_temp_dir.h" |
4349 | +#include "base/macros.h" |
4350 | +#include "base/memory/ptr_util.h" |
4351 | +#include "base/message_loop/message_loop.h" |
4352 | +#include "base/run_loop.h" |
4353 | +#include "base/values.h" |
4354 | +#include "components/prefs/in_memory_pref_store.h" |
4355 | +#include "components/prefs/json_pref_store.h" |
4356 | +#include "components/prefs/pref_filter.h" |
4357 | +#include "components/prefs/pref_store_observer_mock.h" |
4358 | +#include "testing/gtest/include/gtest/gtest.h" |
4359 | + |
4360 | +#include "filtered_pref_store.h" |
4361 | + |
4362 | +namespace { |
4363 | + |
4364 | +const char kPersistentStoreFileName[] = "store.json"; |
4365 | +const char kEmptyJson[] = "{}"; |
4366 | +const char kInvalidJson[] = "invalid"; |
4367 | + |
4368 | +const char kPersistentPref[] = "persistent_pref"; |
4369 | +const char kVolatilePref[] = "volatile_pref"; |
4370 | +const char kSharedPref[] = "shared_pref"; |
4371 | + |
4372 | +} // namespace |
4373 | + |
4374 | +namespace oxide { |
4375 | + |
4376 | +class FilteredPrefStoreTest : public testing::Test { |
4377 | + public: |
4378 | + FilteredPrefStoreTest() = default; |
4379 | + |
4380 | + protected: |
4381 | + void SetUp() override { |
4382 | + volatile_store_ = new InMemoryPrefStore; |
4383 | + |
4384 | + ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); |
4385 | + persistent_store_filepath_ = |
4386 | + temp_dir_.GetPath().AppendASCII(kPersistentStoreFileName); |
4387 | + persistent_store_ = new JsonPrefStore(persistent_store_filepath_, |
4388 | + message_loop_.task_runner(), |
4389 | + std::unique_ptr<PrefFilter>()); |
4390 | + std::set<std::string> persistent_pref_names; |
4391 | + persistent_pref_names.insert(kPersistentPref); |
4392 | + persistent_pref_names.insert(kSharedPref); |
4393 | + |
4394 | + filtered_store_ = new FilteredPrefStore(volatile_store_, persistent_store_, |
4395 | + persistent_pref_names); |
4396 | + |
4397 | + filtered_store_->AddObserver(&observer_); |
4398 | + } |
4399 | + |
4400 | + void TearDown() override { |
4401 | + filtered_store_->RemoveObserver(&observer_); |
4402 | + base::RunLoop().RunUntilIdle(); |
4403 | + } |
4404 | + |
4405 | + base::ScopedTempDir temp_dir_; |
4406 | + base::FilePath persistent_store_filepath_; |
4407 | + base::MessageLoop message_loop_; |
4408 | + |
4409 | + PrefStoreObserverMock observer_; |
4410 | + |
4411 | + scoped_refptr<InMemoryPrefStore> volatile_store_; |
4412 | + scoped_refptr<JsonPrefStore> persistent_store_; |
4413 | + scoped_refptr<FilteredPrefStore> filtered_store_; |
4414 | + |
4415 | + DISALLOW_COPY_AND_ASSIGN(FilteredPrefStoreTest); |
4416 | +}; |
4417 | + |
4418 | +TEST_F(FilteredPrefStoreTest, ReadPrefsNoFile) { |
4419 | + ASSERT_FALSE(base::PathExists(persistent_store_filepath_)); |
4420 | + EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_NO_FILE, |
4421 | + filtered_store_->ReadPrefs()); |
4422 | +} |
4423 | + |
4424 | +TEST_F(FilteredPrefStoreTest, ReadPrefsParseError) { |
4425 | + ASSERT_LT(0, base::WriteFile(persistent_store_filepath_, |
4426 | + kInvalidJson, arraysize(kInvalidJson) - 1)); |
4427 | + ASSERT_TRUE(base::PathExists(persistent_store_filepath_)); |
4428 | + EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_JSON_PARSE, |
4429 | + filtered_store_->ReadPrefs()); |
4430 | +} |
4431 | + |
4432 | +TEST_F(FilteredPrefStoreTest, ReadPrefsSuccess) { |
4433 | + ASSERT_LT(0, base::WriteFile(persistent_store_filepath_, |
4434 | + kEmptyJson, arraysize(kEmptyJson) - 1)); |
4435 | + ASSERT_TRUE(base::PathExists(persistent_store_filepath_)); |
4436 | + EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE, |
4437 | + filtered_store_->ReadPrefs()); |
4438 | +} |
4439 | + |
4440 | +TEST_F(FilteredPrefStoreTest, IsInitializationComplete) { |
4441 | + EXPECT_FALSE(filtered_store_->IsInitializationComplete()); |
4442 | + filtered_store_->ReadPrefs(); |
4443 | + EXPECT_TRUE(filtered_store_->IsInitializationComplete()); |
4444 | +} |
4445 | + |
4446 | +TEST_F(FilteredPrefStoreTest, Observer) { |
4447 | + EXPECT_FALSE(observer_.initialized); |
4448 | + filtered_store_->ReadPrefs(); |
4449 | + EXPECT_TRUE(observer_.initialized); |
4450 | + EXPECT_TRUE(observer_.initialization_success); |
4451 | + EXPECT_TRUE(observer_.changed_keys.empty()); |
4452 | + filtered_store_->SetValue(kPersistentPref, |
4453 | + base::MakeUnique<base::Value>(1), |
4454 | + WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS); |
4455 | + observer_.VerifyAndResetChangedKey(kPersistentPref); |
4456 | + filtered_store_->SetValue(kVolatilePref, |
4457 | + base::MakeUnique<base::Value>(2), |
4458 | + WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS); |
4459 | + observer_.VerifyAndResetChangedKey(kVolatilePref); |
4460 | +} |
4461 | + |
4462 | +TEST_F(FilteredPrefStoreTest, StoreValues) { |
4463 | + PrefStoreObserverMock volatile_observer; |
4464 | + volatile_store_->AddObserver(&volatile_observer); |
4465 | + |
4466 | + PrefStoreObserverMock persistent_observer; |
4467 | + persistent_store_->AddObserver(&persistent_observer); |
4468 | + |
4469 | + filtered_store_->ReadPrefs(); |
4470 | + EXPECT_TRUE(persistent_observer.initialized); |
4471 | + EXPECT_TRUE(persistent_observer.initialization_success); |
4472 | + |
4473 | + filtered_store_->SetValue(kPersistentPref, |
4474 | + base::MakeUnique<base::Value>(3), |
4475 | + WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS); |
4476 | + persistent_observer.VerifyAndResetChangedKey(kPersistentPref); |
4477 | + EXPECT_TRUE(persistent_store_->GetValue(kPersistentPref, nullptr)); |
4478 | + EXPECT_FALSE(volatile_store_->GetValue(kPersistentPref, nullptr)); |
4479 | + EXPECT_TRUE(filtered_store_->GetValue(kPersistentPref, nullptr)); |
4480 | + |
4481 | + filtered_store_->SetValue(kVolatilePref, |
4482 | + base::MakeUnique<base::Value>(4), |
4483 | + WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS); |
4484 | + volatile_observer.VerifyAndResetChangedKey(kVolatilePref); |
4485 | + EXPECT_TRUE(volatile_store_->GetValue(kVolatilePref, nullptr)); |
4486 | + EXPECT_FALSE(persistent_store_->GetValue(kVolatilePref, nullptr)); |
4487 | + EXPECT_TRUE(filtered_store_->GetValue(kVolatilePref, nullptr)); |
4488 | +} |
4489 | + |
4490 | +TEST_F(FilteredPrefStoreTest, ReadValues) { |
4491 | + filtered_store_->ReadPrefs(); |
4492 | + persistent_store_->SetValue(kPersistentPref, |
4493 | + base::MakeUnique<base::Value>(5), |
4494 | + WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS); |
4495 | + volatile_store_->SetValue(kVolatilePref, |
4496 | + base::MakeUnique<base::Value>(6), |
4497 | + WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS); |
4498 | + |
4499 | + EXPECT_TRUE(persistent_store_->GetValue(kPersistentPref, nullptr)); |
4500 | + EXPECT_FALSE(persistent_store_->GetValue(kVolatilePref, nullptr)); |
4501 | + |
4502 | + EXPECT_TRUE(volatile_store_->GetValue(kVolatilePref, nullptr)); |
4503 | + EXPECT_FALSE(volatile_store_->GetValue(kPersistentPref, nullptr)); |
4504 | + |
4505 | + EXPECT_TRUE(filtered_store_->GetValue(kPersistentPref, nullptr)); |
4506 | + EXPECT_TRUE(filtered_store_->GetValue(kVolatilePref, nullptr)); |
4507 | +} |
4508 | + |
4509 | +TEST_F(FilteredPrefStoreTest, GetValues) { |
4510 | + filtered_store_->ReadPrefs(); |
4511 | + persistent_store_->SetValue(kPersistentPref, |
4512 | + base::MakeUnique<base::Value>(7), |
4513 | + WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS); |
4514 | + volatile_store_->SetValue(kVolatilePref, |
4515 | + base::MakeUnique<base::Value>(8), |
4516 | + WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS); |
4517 | + |
4518 | + persistent_store_->SetValue(kSharedPref, |
4519 | + base::MakeUnique<base::Value>(9), |
4520 | + WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS); |
4521 | + volatile_store_->SetValue(kSharedPref, |
4522 | + base::MakeUnique<base::Value>(10), |
4523 | + WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS); |
4524 | + |
4525 | + auto values = filtered_store_->GetValues(); |
4526 | + const base::Value* value = nullptr; |
4527 | + |
4528 | + EXPECT_TRUE(values->Get(kPersistentPref, &value)); |
4529 | + EXPECT_TRUE(base::Value(7).Equals(value)); |
4530 | + |
4531 | + EXPECT_TRUE(values->Get(kVolatilePref, &value)); |
4532 | + EXPECT_TRUE(base::Value(8).Equals(value)); |
4533 | + |
4534 | + EXPECT_TRUE(values->Get(kSharedPref, &value)); |
4535 | + EXPECT_TRUE(base::Value(9).Equals(value)); |
4536 | +} |
4537 | + |
4538 | +} // namespace oxide |
4539 | diff --git a/shared/browser/oxide_browser_context.cc b/shared/browser/oxide_browser_context.cc |
4540 | index 5652924..265efc5 100644 |
4541 | --- a/shared/browser/oxide_browser_context.cc |
4542 | +++ b/shared/browser/oxide_browser_context.cc |
4543 | @@ -1,5 +1,5 @@ |
4544 | // vim:expandtab:shiftwidth=2:tabstop=2: |
4545 | -// Copyright (C) 2013-2016 Canonical Ltd. |
4546 | +// Copyright (C) 2013-2017 Canonical Ltd. |
4547 | |
4548 | // This library is free software; you can redistribute it and/or |
4549 | // modify it under the terms of the GNU Lesser General Public |
4550 | @@ -35,7 +35,16 @@ |
4551 | #include "base/threading/sequenced_worker_pool.h" |
4552 | #include "base/threading/thread_restrictions.h" |
4553 | #include "base/threading/worker_pool.h" |
4554 | +#include "components/autofill/core/browser/autofill_manager.h" |
4555 | +#include "components/autofill/core/common/autofill_pref_names.h" |
4556 | #include "components/keyed_service/content/browser_context_dependency_manager.h" |
4557 | +#include "components/pref_registry/pref_registry_syncable.h" |
4558 | +#include "components/prefs/in_memory_pref_store.h" |
4559 | +#include "components/prefs/json_pref_store.h" |
4560 | +#include "components/prefs/overlay_user_pref_store.h" |
4561 | +#include "components/prefs/pref_filter.h" |
4562 | +#include "components/prefs/pref_notifier_impl.h" |
4563 | +#include "components/prefs/pref_value_store.h" |
4564 | #include "content/browser/loader/resource_dispatcher_host_impl.h" // nogncheck |
4565 | #include "content/public/browser/browser_thread.h" |
4566 | #include "content/public/browser/render_process_host.h" |
4567 | @@ -67,6 +76,7 @@ |
4568 | #include "shared/common/oxide_constants.h" |
4569 | #include "shared/common/oxide_content_client.h" |
4570 | |
4571 | +#include "filtered_pref_store.h" |
4572 | #include "oxide_browser_context_delegate.h" |
4573 | #include "oxide_browser_context_destroyer.h" |
4574 | #include "oxide_browser_process_main.h" |
4575 | @@ -123,6 +133,8 @@ void CleanupOldCacheDir(const base::FilePath& path) { |
4576 | base::DeleteFile(path, true); |
4577 | } |
4578 | |
4579 | +void DoNothingHandleReadError(PersistentPrefStore::PrefReadError error) {} |
4580 | + |
4581 | } // namespace |
4582 | |
4583 | class MainURLRequestContextGetter : public URLRequestContextGetter { |
4584 | @@ -527,6 +539,41 @@ net::CookieStore* BrowserContextIOData::GetCookieStore() const { |
4585 | return cookie_store_owner_->store(); |
4586 | } |
4587 | |
4588 | +ClonablePrefService::ClonablePrefService( |
4589 | + PrefNotifierImpl* pref_notifier, |
4590 | + PrefValueStore* pref_value_store, |
4591 | + PersistentPrefStore* user_prefs, |
4592 | + PrefRegistry* pref_registry, |
4593 | + base::Callback<void(PersistentPrefStore::PrefReadError)> |
4594 | + read_error_callback, |
4595 | + bool async) |
4596 | + : PrefService(pref_notifier, |
4597 | + pref_value_store, |
4598 | + user_prefs, |
4599 | + pref_registry, |
4600 | + read_error_callback, |
4601 | + async) { |
4602 | +} |
4603 | + |
4604 | +ClonablePrefService::~ClonablePrefService() {} |
4605 | + |
4606 | +ClonablePrefService* ClonablePrefService::CreateIncognitoPrefService() { |
4607 | + PrefNotifierImpl* pref_notifier = new PrefNotifierImpl(); |
4608 | + OverlayUserPrefStore* incognito_pref_store = |
4609 | + new OverlayUserPrefStore(user_pref_store_.get()); |
4610 | + return new ClonablePrefService( |
4611 | + pref_notifier, |
4612 | + pref_value_store_->CloneAndSpecialize(nullptr, |
4613 | + nullptr, |
4614 | + nullptr, |
4615 | + nullptr, |
4616 | + incognito_pref_store, |
4617 | + nullptr, |
4618 | + pref_registry_->defaults().get(), |
4619 | + pref_notifier), |
4620 | + incognito_pref_store, pref_registry_.get(), read_error_callback_, false); |
4621 | +} |
4622 | + |
4623 | class BrowserContextImpl; |
4624 | |
4625 | class OTRBrowserContextImpl : public BrowserContext { |
4626 | @@ -578,6 +625,9 @@ OTRBrowserContextImpl::OTRBrowserContextImpl( |
4627 | original_context_(original) { |
4628 | BrowserContextDependencyManager::GetInstance() |
4629 | ->CreateBrowserContextServices(this); |
4630 | + |
4631 | + prefs_.reset(static_cast<ClonablePrefService*>(original->GetPrefs()) |
4632 | + ->CreateIncognitoPrefService()); |
4633 | } |
4634 | |
4635 | BrowserContext* BrowserContextImpl::GetOffTheRecordContext() { |
4636 | @@ -597,8 +647,15 @@ BrowserContextImpl::~BrowserContextImpl() { |
4637 | |
4638 | BrowserContextImpl::BrowserContextImpl(const BrowserContext::Params& params) |
4639 | : BrowserContext(new BrowserContextIODataImpl(params)) { |
4640 | - if (!GetPath().empty()) { |
4641 | - base::FilePath gpu_cache = GetPath().Append(FILE_PATH_LITERAL("GPUCache")); |
4642 | + base::FilePath path = GetPath(); |
4643 | + if (!path.empty()) { |
4644 | + if (!base::PathExists(path)) { |
4645 | + if (!base::CreateDirectory(path)) { |
4646 | + LOG(ERROR) << "Failed to create profile data path: " << path.value(); |
4647 | + } |
4648 | + } |
4649 | + |
4650 | + base::FilePath gpu_cache = path.Append(FILE_PATH_LITERAL("GPUCache")); |
4651 | content::BrowserThread::PostTask( |
4652 | content::BrowserThread::FILE, |
4653 | FROM_HERE, |
4654 | @@ -607,6 +664,44 @@ BrowserContextImpl::BrowserContextImpl(const BrowserContext::Params& params) |
4655 | |
4656 | BrowserContextDependencyManager::GetInstance() |
4657 | ->CreateBrowserContextServices(this); |
4658 | + |
4659 | + autofill::AutofillManager::RegisterProfilePrefs(pref_registry_.get()); |
4660 | + pref_registry_->SetDefaultPrefValue( |
4661 | + autofill::prefs::kAutofillEnabled, |
4662 | + new base::Value(false)); |
4663 | + PrefNotifierImpl* pref_notifier = new PrefNotifierImpl(); |
4664 | + scoped_refptr<PersistentPrefStore> user_prefs; |
4665 | + if (!path.empty()) { |
4666 | + base::FilePath pref_store_path = |
4667 | + path.Append(FILE_PATH_LITERAL("Preferences")); |
4668 | + scoped_refptr<base::SequencedTaskRunner> task_runner = |
4669 | + JsonPrefStore::GetTaskRunnerForFile( |
4670 | + pref_store_path, content::BrowserThread::GetBlockingPool()); |
4671 | + // Persist only selected preferences on disk |
4672 | + scoped_refptr<InMemoryPrefStore> volatile_pref_store(new InMemoryPrefStore); |
4673 | + scoped_refptr<JsonPrefStore> persistent_pref_store(new JsonPrefStore( |
4674 | + pref_store_path, task_runner, std::unique_ptr<PrefFilter>())); |
4675 | + std::set<std::string> persistent_pref_names; |
4676 | + persistent_pref_names.insert(autofill::prefs::kAutofillLastVersionDeduped); |
4677 | + user_prefs = make_scoped_refptr(new FilteredPrefStore( |
4678 | + volatile_pref_store, persistent_pref_store, persistent_pref_names)); |
4679 | + } else { |
4680 | + user_prefs = make_scoped_refptr(new InMemoryPrefStore); |
4681 | + } |
4682 | + prefs_.reset(new ClonablePrefService( |
4683 | + pref_notifier, |
4684 | + new PrefValueStore(nullptr, |
4685 | + nullptr, |
4686 | + nullptr, |
4687 | + nullptr, |
4688 | + user_prefs.get(), |
4689 | + nullptr, |
4690 | + pref_registry_->defaults().get(), |
4691 | + pref_notifier), |
4692 | + user_prefs.get(), |
4693 | + pref_registry_.get(), |
4694 | + base::Bind(&DoNothingHandleReadError), |
4695 | + true)); |
4696 | } |
4697 | |
4698 | void BrowserContext::Deleter::operator()(BrowserContext* context) { |
4699 | @@ -702,7 +797,8 @@ BrowserContext::CreateMediaRequestContextForStoragePartition( |
4700 | } |
4701 | |
4702 | BrowserContext::BrowserContext(BrowserContextIOData* io_data) |
4703 | - : io_data_(io_data) { |
4704 | + : pref_registry_(new user_prefs::PrefRegistrySyncable), |
4705 | + io_data_(io_data) { |
4706 | CHECK(BrowserProcessMain::GetInstance()->IsRunning()) << |
4707 | "The main browser process components must be started before " << |
4708 | "creating a context"; |
4709 | diff --git a/shared/browser/oxide_browser_context.h b/shared/browser/oxide_browser_context.h |
4710 | index e7f30d5..de32778 100644 |
4711 | --- a/shared/browser/oxide_browser_context.h |
4712 | +++ b/shared/browser/oxide_browser_context.h |
4713 | @@ -1,5 +1,5 @@ |
4714 | // vim:expandtab:shiftwidth=2:tabstop=2: |
4715 | -// Copyright (C) 2013-2016 Canonical Ltd. |
4716 | +// Copyright (C) 2013-2017 Canonical Ltd. |
4717 | |
4718 | // This library is free software; you can redistribute it and/or |
4719 | // modify it under the terms of the GNU Lesser General Public |
4720 | @@ -25,6 +25,7 @@ |
4721 | #include "base/memory/ref_counted.h" |
4722 | #include "base/synchronization/lock.h" |
4723 | #include "base/threading/non_thread_safe.h" |
4724 | +#include "components/prefs/pref_service.h" |
4725 | #include "content/public/browser/browser_context.h" |
4726 | #include "content/public/browser/content_browser_client.h" |
4727 | #include "content/public/browser/cookie_store_factory.h" |
4728 | @@ -49,6 +50,10 @@ class TransportSecurityState; |
4729 | |
4730 | } |
4731 | |
4732 | +namespace user_prefs { |
4733 | +class PrefRegistrySyncable; |
4734 | +} |
4735 | + |
4736 | namespace oxide { |
4737 | |
4738 | class BrowserContext; |
4739 | @@ -58,6 +63,7 @@ class BrowserContextDelegate; |
4740 | class BrowserContextImpl; |
4741 | class BrowserContextSharedData; |
4742 | class BrowserContextSharedIOData; |
4743 | +class ClonablePrefService; |
4744 | class CookieStoreOwner; |
4745 | class CookieStoreProxy; |
4746 | class GeolocationPermissionContext; |
4747 | @@ -136,7 +142,20 @@ class BrowserContextIOData { |
4748 | temporary_saved_permission_context_; |
4749 | }; |
4750 | |
4751 | -class BrowserContext; |
4752 | +class ClonablePrefService : public PrefService { |
4753 | + public: |
4754 | + ClonablePrefService( |
4755 | + PrefNotifierImpl* pref_notifier, |
4756 | + PrefValueStore* pref_value_store, |
4757 | + PersistentPrefStore* user_prefs, |
4758 | + PrefRegistry* pref_registry, |
4759 | + base::Callback<void(PersistentPrefStore::PrefReadError)> |
4760 | + read_error_callback, |
4761 | + bool async); |
4762 | + ~ClonablePrefService() override; |
4763 | + |
4764 | + ClonablePrefService* CreateIncognitoPrefService(); |
4765 | +}; |
4766 | |
4767 | // This class holds the context needed for a browsing session. It lives on |
4768 | // and must only be accessed on the UI thread |
4769 | @@ -230,11 +249,16 @@ class OXIDE_SHARED_EXPORT BrowserContext : public content::BrowserContext, |
4770 | |
4771 | BrowserContextIOData* GetIOData() const; |
4772 | |
4773 | + PrefService* GetPrefs() { return prefs_.get(); } |
4774 | + |
4775 | protected: |
4776 | BrowserContext(BrowserContextIOData* io_data); |
4777 | |
4778 | BrowserContextIOData* io_data() const { return io_data_; } |
4779 | |
4780 | + scoped_refptr<user_prefs::PrefRegistrySyncable> pref_registry_; |
4781 | + std::unique_ptr<ClonablePrefService> prefs_; |
4782 | + |
4783 | private: |
4784 | // content::BrowserContext implementation |
4785 | std::unique_ptr<content::ZoomLevelDelegate> CreateZoomLevelDelegate( |
4786 | diff --git a/shared/browser/oxide_browser_platform_integration.cc b/shared/browser/oxide_browser_platform_integration.cc |
4787 | index e30abbe..10340a8 100644 |
4788 | --- a/shared/browser/oxide_browser_platform_integration.cc |
4789 | +++ b/shared/browser/oxide_browser_platform_integration.cc |
4790 | @@ -1,5 +1,5 @@ |
4791 | // vim:expandtab:shiftwidth=2:tabstop=2: |
4792 | -// Copyright (C) 2014-2015 Canonical Ltd. |
4793 | +// Copyright (C) 2014-2017 Canonical Ltd. |
4794 | |
4795 | // This library is free software; you can redistribute it and/or |
4796 | // modify it under the terms of the GNU Lesser General Public |
4797 | @@ -30,6 +30,7 @@ namespace oxide { |
4798 | namespace { |
4799 | |
4800 | const char kDefaultApplicationName[] = "Oxide"; |
4801 | +const char kDefaultApplicationLocale[] = "C"; |
4802 | |
4803 | BrowserPlatformIntegration* g_instance; |
4804 | |
4805 | @@ -88,6 +89,10 @@ std::string BrowserPlatformIntegration::GetApplicationName() { |
4806 | return kDefaultApplicationName; |
4807 | } |
4808 | |
4809 | +std::string BrowserPlatformIntegration::GetApplicationLocale() { |
4810 | + return kDefaultApplicationLocale; |
4811 | +} |
4812 | + |
4813 | std::unique_ptr<DragSource> BrowserPlatformIntegration::CreateDragSource( |
4814 | DragSourceClient* client) { |
4815 | return nullptr; |
4816 | diff --git a/shared/browser/oxide_browser_platform_integration.h b/shared/browser/oxide_browser_platform_integration.h |
4817 | index 57f8568..18c6f93 100644 |
4818 | --- a/shared/browser/oxide_browser_platform_integration.h |
4819 | +++ b/shared/browser/oxide_browser_platform_integration.h |
4820 | @@ -1,5 +1,5 @@ |
4821 | // vim:expandtab:shiftwidth=2:tabstop=2: |
4822 | -// Copyright (C) 2014-2015 Canonical Ltd. |
4823 | +// Copyright (C) 2014-2017 Canonical Ltd. |
4824 | |
4825 | // This library is free software; you can redistribute it and/or |
4826 | // modify it under the terms of the GNU Lesser General Public |
4827 | @@ -116,6 +116,9 @@ class OXIDE_SHARED_EXPORT BrowserPlatformIntegration { |
4828 | // Get the application name. Can be called on any thread |
4829 | virtual std::string GetApplicationName(); |
4830 | |
4831 | + // Get the application locale. Can be called on any thread |
4832 | + virtual std::string GetApplicationLocale(); |
4833 | + |
4834 | // Create a new DragSource implementation. Ownership of |client| is not |
4835 | // transferred, and |client| will outlive the returned DragSource. |
4836 | // Called on the UI thread |
4837 | diff --git a/shared/browser/oxide_content_browser_client.cc b/shared/browser/oxide_content_browser_client.cc |
4838 | index c5b627a..b26fa9e 100644 |
4839 | --- a/shared/browser/oxide_content_browser_client.cc |
4840 | +++ b/shared/browser/oxide_content_browser_client.cc |
4841 | @@ -22,9 +22,12 @@ |
4842 | #include <vector> |
4843 | |
4844 | #include "base/command_line.h" |
4845 | +#include "base/json/json_reader.h" |
4846 | #include "base/logging.h" |
4847 | #include "base/memory/ptr_util.h" |
4848 | #include "base/memory/ref_counted.h" |
4849 | +#include "components/autofill/content/browser/content_autofill_driver_factory.h" |
4850 | +#include "components/password_manager/content/browser/content_password_manager_driver_factory.h" |
4851 | #include "content/public/browser/certificate_request_result_type.h" |
4852 | #include "content/public/browser/interstitial_page.h" |
4853 | #include "content/public/browser/permission_type.h" |
4854 | @@ -34,10 +37,12 @@ |
4855 | #include "content/public/browser/resource_dispatcher_host.h" |
4856 | #include "content/public/common/content_switches.h" |
4857 | #include "content/public/common/service_info.h" |
4858 | +#include "content/public/common/service_names.mojom.h" |
4859 | #include "content/public/common/web_preferences.h" |
4860 | #include "ppapi/features/features.h" |
4861 | #include "services/device/public/interfaces/constants.mojom.h" |
4862 | #include "services/service_manager/public/cpp/interface_registry.h" |
4863 | +#include "ui/base/resource/resource_bundle.h" |
4864 | #include "ui/display/display.h" |
4865 | #include "ui/native_theme/native_theme_switches.h" |
4866 | |
4867 | @@ -79,6 +84,8 @@ |
4868 | #include "pepper/oxide_pepper_host_factory_browser.h" |
4869 | #endif |
4870 | |
4871 | +#include "shared/grit/oxide_resources.h" |
4872 | + |
4873 | namespace oxide { |
4874 | |
4875 | content::BrowserMainParts* ContentBrowserClient::CreateBrowserMainParts( |
4876 | @@ -316,6 +323,23 @@ ContentBrowserClient::GetDevToolsManagerDelegate() { |
4877 | return new DevToolsManagerDelegate(); |
4878 | } |
4879 | |
4880 | +void ContentBrowserClient::RegisterRenderFrameMojoInterfaces( |
4881 | + service_manager::InterfaceRegistry* registry, |
4882 | + content::RenderFrameHost* render_frame_host) { |
4883 | + DCHECK(registry); |
4884 | + registry->AddInterface( |
4885 | + base::Bind(&autofill::ContentAutofillDriverFactory::BindAutofillDriver, |
4886 | + render_frame_host)); |
4887 | + registry->AddInterface( |
4888 | + base::Bind(&password_manager::ContentPasswordManagerDriverFactory:: |
4889 | + BindPasswordManagerDriver, |
4890 | + render_frame_host)); |
4891 | + registry->AddInterface( |
4892 | + base::Bind(&password_manager::ContentPasswordManagerDriverFactory:: |
4893 | + BindSensitiveInputVisibilityService, |
4894 | + render_frame_host)); |
4895 | +} |
4896 | + |
4897 | void ContentBrowserClient::RegisterInProcessServices( |
4898 | StaticServiceMap* services) { |
4899 | content::ServiceInfo device_info; |
4900 | @@ -330,6 +354,23 @@ void ContentBrowserClient::RegisterInProcessServices( |
4901 | services->insert(std::make_pair(device::mojom::kServiceName, device_info)); |
4902 | } |
4903 | |
4904 | +std::unique_ptr<base::Value> ContentBrowserClient::GetServiceManifestOverlay( |
4905 | + base::StringPiece name) { |
4906 | + int id = -1; |
4907 | + if (name == content::mojom::kBrowserServiceName) { |
4908 | + id = IDR_OXIDE_BROWSER_MANIFEST_OVERLAY; |
4909 | + } else if (name == content::mojom::kRendererServiceName) { |
4910 | + id = IDR_OXIDE_RENDERER_MANIFEST_OVERLAY; |
4911 | + } |
4912 | + if (id == -1) { |
4913 | + return nullptr; |
4914 | + } |
4915 | + |
4916 | + base::StringPiece manifest_contents = |
4917 | + ui::ResourceBundle::GetSharedInstance().GetRawDataResource(id); |
4918 | + return base::JSONReader::Read(manifest_contents); |
4919 | +} |
4920 | + |
4921 | void ContentBrowserClient::DidCreatePpapiPlugin(content::BrowserPpapiHost* host) { |
4922 | #if BUILDFLAG(ENABLE_PLUGINS) |
4923 | host->GetPpapiHost()->AddHostFactoryFilter( |
4924 | diff --git a/shared/browser/oxide_content_browser_client.h b/shared/browser/oxide_content_browser_client.h |
4925 | index a55285a..2a963dc 100644 |
4926 | --- a/shared/browser/oxide_content_browser_client.h |
4927 | +++ b/shared/browser/oxide_content_browser_client.h |
4928 | @@ -1,5 +1,5 @@ |
4929 | // vim:expandtab:shiftwidth=2:tabstop=2: |
4930 | -// Copyright (C) 2013 Canonical Ltd. |
4931 | +// Copyright (C) 2013-2016 Canonical Ltd. |
4932 | |
4933 | // This library is free software; you can redistribute it and/or |
4934 | // modify it under the terms of the GNU Lesser General Public |
4935 | @@ -35,7 +35,6 @@ class ResourceDispatcherHostDelegate; |
4936 | namespace oxide { |
4937 | |
4938 | class BrowserPlatformIntegration; |
4939 | -class ContentMainDelegate; |
4940 | class ResourceDispatcherHostDelegate; |
4941 | |
4942 | class ContentBrowserClient final : public content::ContentBrowserClient { |
4943 | @@ -104,7 +103,12 @@ class ContentBrowserClient final : public content::ContentBrowserClient { |
4944 | void OverrideWebkitPrefs(content::RenderViewHost* render_view_host, |
4945 | content::WebPreferences* prefs) override; |
4946 | content::DevToolsManagerDelegate* GetDevToolsManagerDelegate() override; |
4947 | + void RegisterRenderFrameMojoInterfaces( |
4948 | + service_manager::InterfaceRegistry* registry, |
4949 | + content::RenderFrameHost* render_frame_host) override; |
4950 | void RegisterInProcessServices(StaticServiceMap* services) override; |
4951 | + std::unique_ptr<base::Value> GetServiceManifestOverlay( |
4952 | + base::StringPiece name) override; |
4953 | void DidCreatePpapiPlugin(content::BrowserPpapiHost* browser_host) override; |
4954 | gpu::GpuControlList::OsType GetOsTypeOverrideForGpuDataManager( |
4955 | std::string* os_version) override; |
4956 | diff --git a/shared/browser/oxide_user_agent_settings.cc b/shared/browser/oxide_user_agent_settings.cc |
4957 | index a1fe391..2a8550f 100644 |
4958 | --- a/shared/browser/oxide_user_agent_settings.cc |
4959 | +++ b/shared/browser/oxide_user_agent_settings.cc |
4960 | @@ -1,5 +1,5 @@ |
4961 | // vim:expandtab:shiftwidth=2:tabstop=2: |
4962 | -// Copyright (C) 2013-2016 Canonical Ltd. |
4963 | +// Copyright (C) 2013-2017 Canonical Ltd. |
4964 | |
4965 | // This library is free software; you can redistribute it and/or |
4966 | // modify it under the terms of the GNU Lesser General Public |
4967 | @@ -22,6 +22,7 @@ |
4968 | #include "base/logging.h" |
4969 | #include "base/memory/singleton.h" |
4970 | #include "base/strings/stringprintf.h" |
4971 | +#include "components/autofill/core/common/autofill_pref_names.h" |
4972 | #include "components/keyed_service/content/browser_context_dependency_manager.h" |
4973 | #include "components/keyed_service/content/browser_context_keyed_service_factory.h" |
4974 | #include "content/public/browser/browser_thread.h" |
4975 | @@ -151,6 +152,10 @@ bool UserAgentSettingsIOData::GetDoNotTrack() const { |
4976 | return do_not_track_; |
4977 | } |
4978 | |
4979 | +struct UserAgentSettings::DelayedPrefs { |
4980 | + bool autofill_enabled = false; |
4981 | +}; |
4982 | + |
4983 | UserAgentSettings::UserAgentSettings(BrowserContext* context) |
4984 | : context_(context), |
4985 | product_(base::StringPrintf("Chrome/%s", CHROME_VERSION_STRING)), |
4986 | @@ -159,6 +164,13 @@ UserAgentSettings::UserAgentSettings(BrowserContext* context) |
4987 | UserAgentSettingsIOData* io_data = |
4988 | context_->GetIOData()->GetUserAgentSettings(); |
4989 | io_data->user_agent_ = content::BuildUserAgentFromProduct(product_); |
4990 | + |
4991 | + PrefService* prefs = context->GetPrefs(); |
4992 | + if (prefs->GetInitializationStatus() == |
4993 | + PrefService::INITIALIZATION_STATUS_WAITING) { |
4994 | + prefs->AddPrefInitObserver( |
4995 | + base::Bind(&UserAgentSettings::OnPrefsLoaded, base::Unretained(this))); |
4996 | + } |
4997 | } |
4998 | |
4999 | UserAgentSettings::~UserAgentSettings() {} |
5000 | @@ -207,6 +219,13 @@ void UserAgentSettings::RemoveObserver(UserAgentSettingsObserver* observer) { |
I haven't had time to complete the review of this yet, so I've left you a few comments in the meantime to unblock you :)