1 // Copyright 2013 Samsung Electronics. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #if defined(TIZEN_AUTOFILL_SUPPORT)
7 #include "autofill_popup_view_efl.h"
8 #include "base/files/file_path.h"
9 #include "base/path_service.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "components/autofill/core/browser/ui/popup_item_ids.h"
12 #include "content/browser/renderer_host/render_widget_host_view_aura.h"
13 #include "content/browser/web_contents/web_contents_impl.h"
14 #include "content/common/paths_efl.h"
15 #include "eweb_view.h"
16 #include "tizen/system_info.h"
17 #include "ui/display/screen.h"
18 #include "ui/gfx/geometry/rect_f.h"
20 #define AUTOFILL_POPUP_LABEL_COUNT 6 // Autofill component send 6 at max
21 #define AUTOFILL_POPUP_LABEL_LEN 100
23 using namespace password_manager;
27 // const values taken from webkit2-efl
28 constexpr int bg_color_red = 200, bg_color_green = 200, bg_color_blue = 200;
29 constexpr int border_size = 3;
30 std::vector<std::string> labels_(AUTOFILL_POPUP_LABEL_COUNT);
33 enum AutofillSavePassword {
34 AUTOFILL_SAVE_PASS_NEVER = 0,
35 AUTOFILL_SAVE_PASS_YES = 1,
36 AUTOFILL_SAVE_PASS_NOTNOW = 2,
39 AutofillPopupViewEfl::AutofillPopupViewEfl(EWebView* view)
41 autofill_popup_(nullptr),
42 autofill_list_(nullptr),
43 password_popup_(nullptr),
46 static_cast<content::WebContentsImpl*>(&(webview_->web_contents()))
51 auto smart_parent = evas_object_smart_parent_get(native_view);
53 LOG(ERROR) << "Unable to get smart parent from native view";
54 evas_object_del(autofill_popup_);
55 autofill_popup_ = nullptr;
58 evas_object_smart_member_add(autofill_popup_, smart_parent);
59 elm_object_part_content_set(smart_parent, "autofill_popup", autofill_popup_);
60 base::FilePath edj_dir;
61 base::FilePath autofill_edj;
62 base::PathService::Get(PathsEfl::EDJE_RESOURCE_DIR, &edj_dir);
63 autofill_edj = edj_dir.Append(FILE_PATH_LITERAL("AutofillPopup.edj"));
64 elm_layout_file_set(autofill_popup_,
65 autofill_edj.AsUTF8Unsafe().c_str(),
67 autofill_list_ = elm_genlist_add(autofill_popup_);
70 AutofillPopupViewEfl::~AutofillPopupViewEfl()
72 if (autofill_popup_) {
73 evas_object_smart_member_del(autofill_popup_);
74 evas_object_del(autofill_popup_);
77 evas_object_del(password_popup_);
80 void AutofillPopupViewEfl::Show()
83 evas_object_show(autofill_popup_);
85 delegate_->OnPopupShown();
88 void AutofillPopupViewEfl::Hide()
91 evas_object_hide(autofill_popup_);
93 delegate_->OnPopupHidden();
96 void AutofillPopupViewEfl::ShowSavePasswordPopup(
97 std::unique_ptr<PasswordFormManagerForUI> form_to_save) {
98 if (password_popup_) {
99 evas_object_del(password_popup_);
100 password_popup_ = NULL;
102 form_manager_ = std::move(form_to_save);
103 password_popup_ = elm_popup_add(webview_->evas_object());
104 elm_popup_content_text_wrap_type_set(password_popup_, ELM_WRAP_CHAR);
105 elm_object_domain_translatable_part_text_set(
106 password_popup_, "title,text", "WebKit",
107 "IDS_WEBVIEW_HEADER_SAVE_SIGN_IN_INFO");
109 #if BUILDFLAG(IS_EFL) && !BUILDFLAG(IS_TIZEN)
110 // Fix the positioning of the password popup on desktop build
111 auto* rwhv = webview_->web_contents().GetRenderWidgetHostView();
112 auto* rwhva = static_cast<content::RenderWidgetHostViewAura*>(rwhv);
115 evas_object_geometry_get(password_popup_, 0, 0, &w, &h);
116 gfx::Size size = rwhva->offscreen_helper()->GetVisibleViewportSize();
117 evas_object_move(password_popup_, (size.width() - w) / 2,
118 (size.height() - h) / 2);
122 evas_object_show(password_popup_);
124 Evas_Object* btn_never = elm_button_add(password_popup_);
125 elm_object_domain_translatable_part_text_set(btn_never, NULL, "WebKit",
126 "IDS_WEBVIEW_BUTTON2_NEVER");
127 elm_object_part_content_set(password_popup_, "button1", btn_never);
128 evas_object_smart_callback_add(btn_never,
133 Evas_Object* btn_not_now = elm_button_add(password_popup_);
134 elm_object_domain_translatable_part_text_set(btn_not_now, NULL, "WebKit",
135 "IDS_WEBVIEW_BUTTON_LATER_ABB");
136 elm_object_part_content_set(password_popup_, "button2", btn_not_now);
137 evas_object_smart_callback_add(btn_not_now, "clicked", savePasswordNotNowCb,
140 Evas_Object* btn_yes = elm_button_add(password_popup_);
141 elm_object_domain_translatable_part_text_set(btn_yes, NULL, "WebKit",
142 "IDS_WEBVIEW_BUTTON_SAVE");
143 elm_object_part_content_set(password_popup_, "button3", btn_yes);
144 evas_object_smart_callback_add(btn_yes, "clicked", savePasswordYesCb, this);
147 void AutofillPopupViewEfl::UpdateFormDataPopup(const gfx::RectF& bounds) {
148 if (bounds.IsEmpty())
151 Elm_Genlist_Item_Class* list_Items = NULL;
152 double scale_factor = 1.0;
155 Evas_Object* border_up = elm_bg_add(autofill_popup_);
156 Evas_Object* border_down = elm_bg_add(autofill_popup_);
157 Evas_Object* border_left = elm_bg_add(autofill_popup_);
158 Evas_Object* border_right = elm_bg_add(autofill_popup_);
160 elm_genlist_clear(autofill_list_);
161 list_Items = elm_genlist_item_class_new();
162 list_Items->item_style = "default";
163 list_Items->func.text_get = getItemLabel;
164 list_Items->func.content_get = NULL;
165 list_Items->func.state_get = NULL;
166 list_Items->func.del = NULL;
167 for (size_t i = 0; i < values_.size(); ++i) {
168 elm_genlist_item_append(autofill_list_,
170 reinterpret_cast<void*>(static_cast<long>(i)),
172 ELM_GENLIST_ITEM_NONE,
174 static_cast<void*>(this));
176 if (IsMobileProfile() || IsWearableProfile()) {
178 display::Screen::GetScreen()->GetPrimaryDisplay().device_scale_factor();
179 } else if (IsTvProfile()) {
180 scale_factor = webview_->GetScale();
182 #if BUILDFLAG(IS_TIZEN)
183 elm_object_scale_set(autofill_list_, webview_->GetScale() / 2);
185 elm_object_scale_set(autofill_list_, scale_factor);
187 evas_object_show(autofill_list_);
188 int list_height = bounds.height() * scale_factor;
189 // Show at max 3 item for mobile device
190 if (IsMobileProfile() || IsWearableProfile()) {
191 if (values_.size() > 3) {
192 list_height = 3 * list_height;
194 list_height = values_.size() * list_height;
197 list_height = values_.size() * list_height;
200 // const values are taken from webkit2-efl
201 elm_bg_color_set(border_up, bg_color_red, bg_color_green, bg_color_blue);
202 evas_object_size_hint_min_set(border_up, bounds.width(), border_size);
203 evas_object_show(border_up);
205 elm_bg_color_set(border_down, bg_color_red, bg_color_green, bg_color_blue);
206 evas_object_size_hint_min_set(border_down, bounds.width(), border_size);
207 evas_object_show(border_down);
209 elm_bg_color_set(border_left, bg_color_red, bg_color_green, bg_color_blue);
210 evas_object_size_hint_min_set(border_left, border_size, list_height);
211 evas_object_show(border_left);
213 elm_bg_color_set(border_right, bg_color_red, bg_color_green, bg_color_blue);
214 evas_object_size_hint_min_set(border_right, border_size, list_height);
215 evas_object_show(border_right);
217 elm_object_part_content_set(autofill_popup_, "list_container", autofill_list_);
218 elm_object_part_content_set(autofill_popup_, "border_up", border_up);
219 elm_object_part_content_set(autofill_popup_, "border_down", border_down);
220 elm_object_part_content_set(autofill_popup_, "border_left", border_left);
221 elm_object_part_content_set(autofill_popup_, "border_right", border_right);
223 evas_object_size_hint_min_set(autofill_popup_, bounds.width(), list_height);
224 evas_object_move(autofill_popup_, bounds.x() * scale_factor, (bounds.y() + bounds.height()) * scale_factor);
225 evas_object_resize(autofill_popup_, bounds.width() * scale_factor, list_height);
226 evas_object_propagate_events_set(autofill_popup_, false);
229 void AutofillPopupViewEfl::UpdateLocation(const gfx::RectF& bounds) {
230 if (bounds.IsEmpty())
233 double scale_factor =
234 display::Screen::GetScreen()->GetPrimaryDisplay().device_scale_factor();
236 evas_object_move(autofill_popup_, bounds.x() * scale_factor,
237 (bounds.y() + bounds.height()) * scale_factor);
240 bool isAutofillSpecial(const autofill::Suggestion& suggestion) {
241 return suggestion.frontend_id <= 0 &&
242 suggestion.frontend_id != POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY &&
243 suggestion.frontend_id != POPUP_ITEM_ID_DATALIST_ENTRY;
246 void AutofillPopupViewEfl::InitFormData(
247 const std::vector<autofill::Suggestion>& suggestions,
248 base::WeakPtr<AutofillPopupDelegate> delegate){
249 values_ = suggestions;
250 // m42 adds some "special" autofill sugesstions.
251 // This suggestions, like list separator is not useful for us
252 // so, let's delete them.
254 std::remove_if(values_.begin(), values_.end(), isAutofillSpecial),
257 for (size_t i = 0; i < values_.size() && i < AUTOFILL_POPUP_LABEL_COUNT;
259 labels_[i] = base::UTF16ToUTF8(values_[i].main_text.value);
260 if (!values_[i].labels.empty() && !values_[i].labels[0][0].value.empty())
261 labels_[i].append(" (" +
262 base::UTF16ToUTF8(values_[i].labels[0][0].value) + ")");
263 // To keep compatibility with webkit2-efl
264 if (AUTOFILL_POPUP_LABEL_LEN < labels_[i].length())
265 labels_[i].resize(AUTOFILL_POPUP_LABEL_LEN);
267 delegate_ = delegate;
270 void AutofillPopupViewEfl::AcceptSuggestion(size_t index) {
271 if (delegate_ && index < values_.size()) {
272 delegate_->DidAcceptSuggestion(values_[index], index);
276 void AutofillPopupViewEfl::AcceptPasswordSuggestion(int option) {
277 if (password_popup_) {
278 evas_object_del(password_popup_);
279 password_popup_ = NULL;
283 switch (static_cast<AutofillSavePassword>(option)) {
284 case AUTOFILL_SAVE_PASS_NEVER: {
285 form_manager_->Blocklist();
288 case AUTOFILL_SAVE_PASS_YES: {
289 form_manager_->Save();
292 case AUTOFILL_SAVE_PASS_NOTNOW:
299 void AutofillPopupViewEfl::SetSelectedLine(size_t selected_line)
301 if (selected_line_ == selected_line)
303 selected_line_ = selected_line;
305 if (selected_line_ < values_.size()) {
306 delegate_->DidSelectSuggestion(values_[selected_line].main_text.value,
308 autofill::Suggestion::BackendId());
311 delegate_->ClearPreviewedForm();
317 char* AutofillPopupViewEfl::getItemLabel(void* data, Evas_Object* obj, const char* part)
319 size_t index = (size_t)data;
320 if (AUTOFILL_POPUP_LABEL_COUNT > index)
321 return strdup(labels_[index].c_str());
326 void AutofillPopupViewEfl::itemSelectCb(void* data, Evas_Object* obj, void* event_info)
328 size_t index = (size_t)elm_object_item_data_get(static_cast<Elm_Object_Item*>(event_info));
329 AutofillPopupViewEfl* autofill_popup = static_cast<AutofillPopupViewEfl*>(data);
331 autofill_popup->AcceptSuggestion(index);
334 void AutofillPopupViewEfl::savePasswordNeverCb(void* data,
337 AutofillPopupViewEfl* autofill_popup =
338 static_cast<AutofillPopupViewEfl*>(data);
340 autofill_popup->AcceptPasswordSuggestion(AUTOFILL_SAVE_PASS_NEVER);
343 void AutofillPopupViewEfl::savePasswordYesCb(void* data,
346 AutofillPopupViewEfl* autofill_popup =
347 static_cast<AutofillPopupViewEfl*>(data);
349 autofill_popup->AcceptPasswordSuggestion(AUTOFILL_SAVE_PASS_YES);
352 void AutofillPopupViewEfl::savePasswordNotNowCb(void* data,
355 AutofillPopupViewEfl* autofill_popup =
356 static_cast<AutofillPopupViewEfl*>(data);
358 autofill_popup->AcceptPasswordSuggestion(AUTOFILL_SAVE_PASS_NOTNOW);
361 } // namespace autofill
363 #endif // TIZEN_AUTOFILL_SUPPORT