[M108 Migration][Text Selection] Selection handles & Caret Selection
[platform/framework/web/chromium-efl.git] / tizen_src / ewk / efl_integration / browser / autofill_popup_view_efl.cc
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.
4
5 #if defined(TIZEN_AUTOFILL_SUPPORT)
6
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"
19
20 #define AUTOFILL_POPUP_LABEL_COUNT  6 // Autofill component send 6 at max
21 #define AUTOFILL_POPUP_LABEL_LEN    100
22
23 using namespace password_manager;
24
25 namespace autofill {
26 namespace {
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);
31 } // namespace
32
33 enum AutofillSavePassword {
34   AUTOFILL_SAVE_PASS_NEVER  = 0,
35   AUTOFILL_SAVE_PASS_YES    = 1,
36   AUTOFILL_SAVE_PASS_NOTNOW = 2,
37 };
38
39 AutofillPopupViewEfl::AutofillPopupViewEfl(EWebView* view)
40     : webview_(view),
41       autofill_popup_(nullptr),
42       autofill_list_(nullptr),
43       password_popup_(nullptr),
44       selected_line_(-1) {
45   auto native_view =
46       static_cast<content::WebContentsImpl*>(&(webview_->web_contents()))
47           ->GetEflNativeView();
48
49   if (!autofill_popup_)
50     return;
51   auto smart_parent = evas_object_smart_parent_get(native_view);
52   if (!smart_parent) {
53     LOG(ERROR) << "Unable to get smart parent from native view";
54     evas_object_del(autofill_popup_);
55     autofill_popup_ = nullptr;
56     return;
57   }
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(),
66       "formdata_list");
67   autofill_list_ = elm_genlist_add(autofill_popup_);
68 }
69
70 AutofillPopupViewEfl::~AutofillPopupViewEfl()
71 {
72   if (autofill_popup_) {
73     evas_object_smart_member_del(autofill_popup_);
74     evas_object_del(autofill_popup_);
75   }
76   if (password_popup_)
77     evas_object_del(password_popup_);
78 }
79
80 void AutofillPopupViewEfl::Show()
81 {
82   if (autofill_popup_)
83     evas_object_show(autofill_popup_);
84   if (delegate_)
85     delegate_->OnPopupShown();
86 }
87
88 void AutofillPopupViewEfl::Hide()
89 {
90   if (autofill_popup_)
91     evas_object_hide(autofill_popup_);
92   if (delegate_)
93     delegate_->OnPopupHidden();
94 }
95
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;
101   }
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");
108
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);
113   if (rwhva) {
114     int w = 0, h = 0;
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);
119   }
120 #endif
121
122   evas_object_show(password_popup_);
123
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,
129       "clicked",
130       savePasswordNeverCb,
131       this);
132
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,
138                                  this);
139
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);
145 }
146
147 void AutofillPopupViewEfl::UpdateFormDataPopup(const gfx::RectF& bounds) {
148   if (bounds.IsEmpty())
149     return;
150
151   Elm_Genlist_Item_Class* list_Items = NULL;
152   double scale_factor = 1.0;
153   if (!autofill_list_)
154     return;
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_);
159
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_,
169         list_Items,
170         reinterpret_cast<void*>(static_cast<long>(i)),
171         NULL,
172         ELM_GENLIST_ITEM_NONE,
173         itemSelectCb,
174         static_cast<void*>(this));
175   }
176   if (IsMobileProfile() || IsWearableProfile()) {
177     scale_factor =
178         display::Screen::GetScreen()->GetPrimaryDisplay().device_scale_factor();
179   } else if (IsTvProfile()) {
180     scale_factor = webview_->GetScale();
181   }
182 #if BUILDFLAG(IS_TIZEN)
183   elm_object_scale_set(autofill_list_, webview_->GetScale() / 2);
184 #else
185   elm_object_scale_set(autofill_list_, scale_factor);
186 #endif
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;
193     } else {
194       list_height = values_.size() * list_height;
195     }
196   } else {
197     list_height = values_.size() * list_height;
198   }
199
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);
204
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);
208
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);
212
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);
216
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);
222
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);
227 }
228
229 void AutofillPopupViewEfl::UpdateLocation(const gfx::RectF& bounds) {
230   if (bounds.IsEmpty())
231     return;
232
233   double scale_factor =
234       display::Screen::GetScreen()->GetPrimaryDisplay().device_scale_factor();
235
236   evas_object_move(autofill_popup_, bounds.x() * scale_factor,
237                    (bounds.y() + bounds.height()) * scale_factor);
238 }
239
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;
244 }
245
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.
253   values_.erase(
254     std::remove_if(values_.begin(), values_.end(), isAutofillSpecial),
255     values_.end());
256
257   for (size_t i = 0; i < values_.size() && i < AUTOFILL_POPUP_LABEL_COUNT;
258        ++i) {
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);
266   }
267   delegate_ = delegate;
268 }
269
270 void AutofillPopupViewEfl::AcceptSuggestion(size_t index) {
271   if (delegate_ && index < values_.size()) {
272     delegate_->DidAcceptSuggestion(values_[index], index);
273   }
274 }
275
276 void AutofillPopupViewEfl::AcceptPasswordSuggestion(int option) {
277   if (password_popup_) {
278     evas_object_del(password_popup_);
279     password_popup_ = NULL;
280   }
281   if (!form_manager_)
282     return;
283   switch (static_cast<AutofillSavePassword>(option)) {
284     case AUTOFILL_SAVE_PASS_NEVER: {
285       form_manager_->Blocklist();
286       break;
287     }
288     case AUTOFILL_SAVE_PASS_YES: {
289       form_manager_->Save();
290       break;
291     }
292     case AUTOFILL_SAVE_PASS_NOTNOW:
293     default: {
294       break;
295     }
296   }
297 }
298
299 void AutofillPopupViewEfl::SetSelectedLine(size_t selected_line)
300 {
301   if (selected_line_ == selected_line)
302     return;
303   selected_line_ = selected_line;
304   if (delegate_) {
305     if (selected_line_ < values_.size()) {
306       delegate_->DidSelectSuggestion(values_[selected_line].main_text.value,
307                                      selected_line,
308                                      autofill::Suggestion::BackendId());
309     }
310     else {
311       delegate_->ClearPreviewedForm();
312     }
313   }
314 }
315
316 // Static
317 char* AutofillPopupViewEfl::getItemLabel(void* data, Evas_Object* obj, const char* part)
318 {
319   size_t index = (size_t)data;
320   if (AUTOFILL_POPUP_LABEL_COUNT > index)
321     return strdup(labels_[index].c_str());
322   else
323     return strdup("");
324 }
325
326 void AutofillPopupViewEfl::itemSelectCb(void* data, Evas_Object* obj, void* event_info)
327 {
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);
330   if (autofill_popup)
331     autofill_popup->AcceptSuggestion(index);
332 }
333
334 void AutofillPopupViewEfl::savePasswordNeverCb(void* data,
335                                                Evas_Object* obj,
336                                                void* event_info) {
337   AutofillPopupViewEfl* autofill_popup =
338       static_cast<AutofillPopupViewEfl*>(data);
339   if (autofill_popup)
340     autofill_popup->AcceptPasswordSuggestion(AUTOFILL_SAVE_PASS_NEVER);
341 }
342
343 void AutofillPopupViewEfl::savePasswordYesCb(void* data,
344                                              Evas_Object* obj,
345                                              void* event_info) {
346   AutofillPopupViewEfl* autofill_popup =
347       static_cast<AutofillPopupViewEfl*>(data);
348   if (autofill_popup)
349     autofill_popup->AcceptPasswordSuggestion(AUTOFILL_SAVE_PASS_YES);
350 }
351
352 void AutofillPopupViewEfl::savePasswordNotNowCb(void* data,
353                                                 Evas_Object* obj,
354                                                 void* event_info) {
355   AutofillPopupViewEfl* autofill_popup =
356       static_cast<AutofillPopupViewEfl*>(data);
357   if (autofill_popup)
358     autofill_popup->AcceptPasswordSuggestion(AUTOFILL_SAVE_PASS_NOTNOW);
359 }
360
361 } // namespace autofill
362
363 #endif // TIZEN_AUTOFILL_SUPPORT