[M47_2526] Chromium upversion to m47_2526 branch
[platform/framework/web/chromium-efl.git] / tizen_src / ewk / efl_integration / context_menu_controller_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 #include <Elementary.h>
6 #include <stdio.h>
7 #include <stdlib.h>
8
9 #include "base/files/file_path.h"
10 #include "base/path_service.h"
11 #include "ui/base/clipboard/clipboard_helper_efl.h"
12 #include "common/web_contents_utils.h"
13 #include "context_menu_controller_efl.h"
14 #include "content/browser/renderer_host/render_widget_host_view_efl.h"
15 #include "content/browser/selection/selection_controller_efl.h"
16 #include "content/public/browser/browser_thread.h"
17 #include "content/public/browser/download_manager.h"
18 #include "content/public/browser/navigation_entry.h"
19 #include "eweb_view.h"
20 #include "net/base/net_util.h"
21 #include "net/base/filename_util.h"
22 #include "content/common/paths_efl.h"
23 #include "third_party/WebKit/public/platform/WebReferrerPolicy.h"
24 #include "ui/base/clipboard/clipboard.h"
25 #include "private/ewk_context_menu_private.h"
26
27 #if defined(OS_TIZEN_MOBILE)
28 #include <efl_extension.h>
29 #endif
30
31 using web_contents_utils::WebViewFromWebContents;
32
33 namespace {
34 static const int kMaxHeightVertical = 680;
35 static const int kMaxHeightHorizontal = 360;
36 }
37
38 namespace content {
39
40 unsigned int ContextMenuControllerEfl::_appended_item_size = 0;
41 int ContextMenuControllerEfl::_popup_item_height = 96;
42 bool ContextMenuControllerEfl::_context_menu_resized = false;
43 std::vector<ContextMenuItemEfl> ContextMenuControllerEfl::_context_menu_listdata;
44
45 ContextMenuControllerEfl::~ContextMenuControllerEfl() {
46   for (std::set<DownloadItem*>::iterator it = clipboard_download_items_.begin();
47       it != clipboard_download_items_.end(); ++it) {
48     (*it)->RemoveObserver(this);
49   }
50   for (std::set<DownloadItem*>::iterator it = disk_download_items_.begin();
51       it != disk_download_items_.end(); ++it) {
52     (*it)->RemoveObserver(this);
53   }
54   _context_menu_listdata.clear();
55   DeletePopup();
56 }
57
58 bool ContextMenuControllerEfl::PopulateAndShowContextMenu(const ContextMenuParams &params) {
59   if (!webview_)
60     return false;
61
62   DCHECK(menu_items_ == NULL);
63   if (menu_items_)
64     return false;
65
66   params_ = params;
67   GetProposedContextMenu();
68    _Ewk_Context_Menu new_menu(menu_items_);
69    webview_->SmartCallback<EWebViewCallbacks::ContextMenuCustomize>().call(&new_menu);
70    menu_items_ = new_menu.TakeMenuList();
71
72   if (!CreateContextMenu())
73     return false;
74
75   return ShowContextMenu();
76 }
77
78 void ContextMenuControllerEfl::AddItemToProposedList(ContextMenuOptionType item,
79                                                      ContextMenuOption option,
80                                                      const std::string& title,
81                                                      const std::string& image_url,
82                                                      const std::string& link_url,
83                                                      const std::string& icon_path) {
84   ContextMenuItemEfl* new_menu_item = new ContextMenuItemEfl(
85       item, option, title, image_url, link_url, icon_path);
86   _Ewk_Context_Menu_Item* new_item = new _Ewk_Context_Menu_Item(new_menu_item);
87   menu_items_ = eina_list_append(menu_items_, new_item);
88 }
89
90 void ContextMenuControllerEfl::GetProposedContextMenu() {
91   if (!params_.link_url.is_empty()) {
92     AddItemToProposedList(MENU_ITEM_TYPE_ACTION,
93         MENU_ITEM_OPEN_LINK_IN_NEW_WINDOW,
94         std::string(dgettext("WebKit",
95             "IDS_WEBVIEW_OPT_OPEN_LINK_IN_NEW_TAB_ABB")),
96         params_.link_url.spec(),
97         params_.link_url.spec());
98     AddItemToProposedList(MENU_ITEM_TYPE_ACTION,
99         MENU_ITEM_COPY_LINK_TO_CLIPBOARD,
100         std::string(dgettext("WebKit", "IDS_WEBVIEW_OPT_COPY_LINK_URL_ABB")),
101         std::string(),
102         params_.link_url.spec());
103     AddItemToProposedList(MENU_ITEM_TYPE_ACTION,
104         MENU_ITEM_DOWNLOAD_LINK_TO_DISK,
105         std::string(dgettext("WebKit", "IDS_BR_BODY_SAVE_LINK")),
106         std::string(),
107         params_.link_url.spec());
108   }
109 #if !defined(WAYLAND_BRINGUP)
110   if (params_.is_editable && ClipboardHelperEfl::NumberOfItems() > 0) {
111     AddItemToProposedList(MENU_ITEM_TYPE_ACTION, MENU_ITEM_PASTE,
112         std::string(dgettext("WebKit", "IDS_WEBVIEW_OPT_PASTE")));
113   }
114 #else
115   NOTIMPLEMENTED();
116 #endif
117   if (!params_.selection_text.empty() && params_.is_editable) {
118     AddItemToProposedList(MENU_ITEM_TYPE_ACTION, MENU_ITEM_CUT,
119         std::string(dgettext("WebKit", "IDS_WEBVIEW_OPT_CUT_ABB")));
120   }
121   if (!params_.selection_text.empty()) {
122     AddItemToProposedList(MENU_ITEM_TYPE_ACTION, MENU_ITEM_COPY,
123         std::string(dgettext("WebKit", "IDS_WEBVIEW_OPT_COPY")));
124     if (!params_.is_editable) {
125       AddItemToProposedList(MENU_ITEM_TYPE_ACTION, MENU_ITEM_SEARCH_WEB,
126           std::string(dgettext("WebKit", "IDS_WEBVIEW_OPT_WEB_SEARCH")));
127 #if !defined(OS_TIZEN_MOBILE)
128       AddItemToProposedList(MENU_ITEM_TYPE_ACTION, MENU_ITEM_SEARCH_IN_SPOTLIGHT,
129           std::string());
130 #endif
131     }
132   }
133
134  if (params_.has_image_contents && !params_.src_url.is_empty()) {
135     AddItemToProposedList(MENU_ITEM_TYPE_ACTION,
136         MENU_ITEM_OPEN_IMAGE_IN_NEW_WINDOW,
137         std::string(dgettext("WebKit",
138             "IDS_WEBVIEW_OPT_OPEN_IMAGE_IN_NEW_TAB_ABB")),
139         params_.src_url.spec(),
140         params_.src_url.spec());
141     AddItemToProposedList(MENU_ITEM_TYPE_ACTION,
142         MENU_ITEM_DOWNLOAD_IMAGE_TO_DISK,
143         std::string(dgettext("WebKit", "IDS_WEBVIEW_OPT_SAVE_IMAGE_ABB")),
144         params_.src_url.spec(),
145         params_.src_url.spec());
146     AddItemToProposedList(MENU_ITEM_TYPE_ACTION,
147         MENU_ITEM_COPY_IMAGE_TO_CLIPBOARD,
148         std::string(dgettext("WebKit", "IDS_WEBVIEW_OPT_COPY_IMAGE")),
149         params_.src_url.spec(),
150         params_.src_url.spec());
151   } else if (!params_.link_url.is_empty()) {
152     AddItemToProposedList(MENU_ITEM_TYPE_ACTION,
153         MENU_ITEM_TEXT_SELECTION_MODE,
154         std::string(dgettext("WebKit", "IDS_WEBVIEW_OPT_SELECTION_MODE_ABB")),
155         params_.link_url.spec(),
156         params_.link_url.spec());
157   }
158
159   RenderWidgetHostViewEfl* rwhv = static_cast<RenderWidgetHostViewEfl*>(web_contents_.GetRenderWidgetHostView());
160   if (!params_.selection_text.empty()
161       || (params_.is_editable && (rwhv && !rwhv->IsLastAvailableTextEmpty()))) {
162     AddItemToProposedList(MENU_ITEM_TYPE_ACTION, MENU_ITEM_SELECT_WORD,
163         std::string(dgettext("WebKit", "IDS_WEBVIEW_OPT_SELECT_ABB")));
164     AddItemToProposedList(MENU_ITEM_TYPE_ACTION, MENU_ITEM_SELECT_ALL,
165         std::string(dgettext("WebKit", "IDS_WEBVIEW_OPT_SELECT_ALL_ABB")));
166   }
167 #if !defined(EWK_BRINGUP)
168   if (params_.is_draggable) {
169     AddItemToProposedList(MENU_ITEM_TYPE_ACTION, MENU_ITEM_DRAG,
170         std::string(dgettext("WebKit", "IDS_WEBVIEW_OPT_DRAG_AND_DROP")));
171   }
172 #endif
173 #if !defined(WAYLAND_BRINGUP)
174   if (params_.is_editable && ClipboardHelperEfl::NumberOfItems() > 0) {
175     AddItemToProposedList(MENU_ITEM_TYPE_ACTION, MENU_ITEM_CLIPBOARD,
176         std::string(dgettext("WebKit", "IDS_WEBVIEW_OPT_CLIPBOARD")));
177   }
178 #else
179   NOTIMPLEMENTED();
180 #endif
181 }
182
183 bool ContextMenuControllerEfl::CreateContextMenu() {
184   is_text_selection_ = false;
185   Eina_List* ittr;
186   void* data;
187   EINA_LIST_FOREACH(menu_items_, ittr, data) {
188     _Ewk_Context_Menu_Item* item = static_cast<_Ewk_Context_Menu_Item*> (data);
189     ContextMenuItemEfl* context_item = item->GetMenuItem();
190     switch (context_item->GetContextMenuOption()) {
191       case MENU_ITEM_COPY:
192       case MENU_ITEM_SELECT_ALL:
193       case MENU_ITEM_SELECT_WORD:
194       case MENU_ITEM_PASTE:
195         is_text_selection_ = true;
196         break;
197       default:
198         break;
199     }
200   }
201
202   if (is_text_selection_) {
203     popup_ = elm_ctxpopup_add(native_view_);
204     elm_ctxpopup_horizontal_set(popup_, EINA_TRUE);
205     elm_object_tree_focus_allow_set(popup_, false);
206   } else {
207     evas_object_data_set(native_view_, "ContextMenuContollerEfl", this);
208     popup_ = elm_popup_add(native_view_);
209   }
210
211   if (!popup_)
212     return false;
213
214   evas_object_data_set(popup_, "ContextMenuContollerEfl", this);
215
216   _appended_item_size = 0;
217   if (is_text_selection_) {
218     EINA_LIST_FOREACH(menu_items_, ittr, data) {
219       _Ewk_Context_Menu_Item* item = static_cast<_Ewk_Context_Menu_Item*> (data);
220       ContextMenuItemEfl* context_item = item->GetMenuItem();
221       Elm_Object_Item* appended_item = 0;
222
223       if (!context_item->Title().empty()) {
224         appended_item = elm_ctxpopup_item_append(popup_,
225             context_item->Title().c_str(), 0, ContextMenuItemSelectedCallback,
226             context_item);
227       } else {
228         appended_item = elm_ctxpopup_item_append(popup_, 0, 0,
229             ContextMenuItemSelectedCallback,
230             context_item);
231       }
232
233       if (appended_item)
234         _appended_item_size++;
235     }
236 #if defined(OS_TIZEN)
237     // Workaround
238     // Need to set "copypaste" style, to let moving handles
239     // when ctxpopup is visible
240     // http://107.108.218.239/bugzilla/show_bug.cgi?id=11613
241     elm_object_style_set(popup_, "copypaste");
242 #endif
243   } else {
244     GURL url = web_contents_.GetVisibleURL();
245     std::string selected_link (url.host().c_str());
246     if (!selected_link.empty()) {
247       if (base::StartsWith(selected_link,
248                            std::string("mailto:"),
249                            base::CompareCase::INSENSITIVE_ASCII)
250           || base::StartsWith(selected_link,
251                               std::string("tel:"),
252                               base::CompareCase::INSENSITIVE_ASCII)) {
253         std::vector<std::string> link_split;
254         size_t current_pos = 0;
255         size_t next_delimiter = 0;
256         while ((next_delimiter = selected_link.find(":", current_pos))
257                != std::string::npos) {
258           std::string part = selected_link.substr(current_pos,
259                                                   next_delimiter - current_pos);
260           link_split.push_back(part);
261           current_pos = next_delimiter + 1;
262         }
263         std::string last_part = selected_link.substr(current_pos);
264         if (!last_part.empty())
265           link_split.push_back(last_part);
266
267         if (!link_split[1].size()) {
268           std::vector<std::string> real_link_split;
269           size_t current_pos = 0;
270           size_t next_delimiter = 0;
271           while ((next_delimiter = link_split[1].find("?", current_pos)) != std::string::npos) {
272             std::string part = link_split[1].substr(current_pos, next_delimiter - current_pos);
273             real_link_split.push_back(part);
274             current_pos = next_delimiter + 1;
275           }
276           std::string last_part = link_split[1].substr(current_pos);
277           if (!last_part.empty())
278             real_link_split.push_back(last_part);
279
280           elm_object_part_text_set(popup_, "title,text", real_link_split[0].c_str());
281         }
282       } else {
283         elm_object_part_text_set(popup_, "title,text", selected_link.c_str());
284       }
285     } else {
286       std::string selected_image (url.host().c_str());
287       if (!selected_image.empty()) {
288         if (base::StartsWith(selected_image,
289             std::string("data:"),
290             base::CompareCase::INSENSITIVE_ASCII))
291           elm_object_part_text_set(popup_, "title,text", "data:");
292         else
293           elm_object_part_text_set(popup_, "title,text", selected_image.c_str());
294       }
295     }
296
297     evas_object_size_hint_weight_set(popup_, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
298
299     Evas_Object* list = elm_list_add(popup_);
300     elm_list_mode_set(list, ELM_LIST_EXPAND);
301     evas_object_data_set(list, "ContextMenuContollerEfl", this);
302
303     _context_menu_listdata.clear();
304
305     Eina_List* ittr;
306     void* data;
307     EINA_LIST_FOREACH(menu_items_, ittr, data) {
308       _Ewk_Context_Menu_Item* item = static_cast<_Ewk_Context_Menu_Item*> (data);
309       ContextMenuItemEfl* context_item = item->GetMenuItem();
310       if (!context_item->Title().empty()) {
311         Elm_Object_Item* appended_item = elm_list_item_append(list,
312             context_item->Title().c_str(),
313             NULL,
314             NULL,
315             ContextMenuItemSelectedCallback,
316             context_item);
317
318         if (appended_item) {
319           _context_menu_listdata.push_back(*context_item);
320           _appended_item_size++;
321         }
322       }
323     }
324     evas_object_show(list);
325     elm_object_content_set(popup_, list);
326     evas_object_event_callback_add(popup_, EVAS_CALLBACK_RESIZE,
327         ContextMenuPopupResize, list);
328   }
329
330   if (!_appended_item_size) {
331     DeletePopup();
332     return false;
333   }
334   return true;
335 }
336
337 void ContextMenuControllerEfl::ContextMenuHWBackKey(void* data, Evas_Object* obj,
338                                                     void* event_info) {
339   ContextMenuControllerEfl* menu_controller = static_cast<ContextMenuControllerEfl*>(data);
340   if (menu_controller) {
341     menu_controller->HideContextMenu();
342     evas_object_data_del(obj, "ContextEfl");
343   }
344 }
345
346 void ContextMenuControllerEfl::ContextMenuCancelCallback(void* data, Evas_Object* obj,
347                                                          void* event_info) {
348   ContextMenuControllerEfl* menu_controller = static_cast<ContextMenuControllerEfl*>(evas_object_data_get(obj, "ContextEfl"));
349   if (menu_controller) {
350     menu_controller->HideContextMenu();
351     menu_controller->HideSelectionHandle();
352     evas_object_data_del(obj, "ContextEfl");
353   }
354 }
355
356 void ContextMenuControllerEfl::ContextMenuItemSelectedCallback(void* data,
357     Evas_Object* obj, void* event_info) {
358   Evas_Object* pop_up = obj;
359   ContextMenuControllerEfl* menu_controller =
360       static_cast<ContextMenuControllerEfl*>
361       (evas_object_data_get(pop_up, "ContextMenuContollerEfl"));
362
363   if (menu_controller) {
364     ContextMenuItemEfl* selected_menu_item = static_cast<ContextMenuItemEfl*>(data);
365     if (selected_menu_item)
366        menu_controller->MenuItemSelected(selected_menu_item);
367   }
368 }
369
370 bool ContextMenuControllerEfl::ShowContextMenu() {
371   if (!popup_)
372     return false;
373
374   if (is_text_selection_) {
375     int webview_x, webview_y, webview_width, webview_height;
376     Evas_Point point;
377
378     gfx::Point popup_position = gfx::Point(params_.x, params_.y);
379
380     if (!webview_)
381       return false;
382
383     Evas_Object* wv_evas_obj = WebViewFromWebContents(&web_contents_)->evas_object();
384     evas_object_geometry_get(wv_evas_obj, &webview_x, &webview_y, &webview_width, &webview_height);
385     popup_position.set_x(popup_position.x() + webview_x);
386     popup_position.set_y(popup_position.y() + webview_y);
387
388     point.x = popup_position.x();
389     point.y = popup_position.y();
390
391     evas_object_smart_callback_call(wv_evas_obj, "contextmenu,willshow", &point);
392
393     bool allowed = true;
394     evas_object_smart_callback_call(wv_evas_obj, "contextmenu,allowed", &allowed);
395     if (!allowed) {
396       DeletePopup();
397       return false;
398     }
399
400     SelectionControllerEfl* controller = webview_->GetSelectionController();
401     if (!controller) {
402       DeletePopup();
403       return false;
404     }
405
406     int draw_direction;
407     controller->ChangeContextMenuPosition(popup_position, draw_direction);
408
409     if ((popup_position.y() > webview_height) || (popup_position.x() > webview_width))
410         return false;
411
412     switch(draw_direction) {
413       case 0:
414         elm_ctxpopup_direction_priority_set(popup_,
415                                             ELM_CTXPOPUP_DIRECTION_DOWN,
416                                             ELM_CTXPOPUP_DIRECTION_DOWN,
417                                             ELM_CTXPOPUP_DIRECTION_DOWN,
418                                             ELM_CTXPOPUP_DIRECTION_DOWN);
419         break;
420       case 1:
421         elm_ctxpopup_direction_priority_set(popup_,
422                                             ELM_CTXPOPUP_DIRECTION_UP,
423                                             ELM_CTXPOPUP_DIRECTION_UP,
424                                             ELM_CTXPOPUP_DIRECTION_UP,
425                                             ELM_CTXPOPUP_DIRECTION_UP);
426         break;
427       case 2:
428         elm_ctxpopup_direction_priority_set(popup_,
429                                             ELM_CTXPOPUP_DIRECTION_LEFT,
430                                             ELM_CTXPOPUP_DIRECTION_LEFT,
431                                             ELM_CTXPOPUP_DIRECTION_LEFT,
432                                             ELM_CTXPOPUP_DIRECTION_LEFT);
433         break;
434       case 3:
435         elm_ctxpopup_direction_priority_set(popup_,
436                                             ELM_CTXPOPUP_DIRECTION_RIGHT,
437                                             ELM_CTXPOPUP_DIRECTION_RIGHT,
438                                             ELM_CTXPOPUP_DIRECTION_RIGHT,
439                                             ELM_CTXPOPUP_DIRECTION_RIGHT);
440         break;
441       default:
442         elm_ctxpopup_direction_priority_set(popup_,
443                                             ELM_CTXPOPUP_DIRECTION_UP,
444                                             ELM_CTXPOPUP_DIRECTION_DOWN,
445                                             ELM_CTXPOPUP_DIRECTION_LEFT,
446                                             ELM_CTXPOPUP_DIRECTION_RIGHT);
447     };
448     evas_object_move(popup_, popup_position.x(), popup_position.y());
449     evas_object_smart_callback_add(popup_, "dismissed", ContextMenuCancelCallback, this);
450 #if defined(OS_TIZEN_MOBILE)
451     elm_ctxpopup_auto_hide_disabled_set(popup_, EINA_TRUE);
452 #endif
453     web_contents_.Focus();
454   } else {
455 #if defined(OS_TIZEN_MOBILE)
456     eext_object_event_callback_add(popup_, EEXT_CALLBACK_BACK, ContextMenuHWBackKey, this);
457     // Workaround. After context menu shows up, there is "unfocused" event fired.
458     // evas_object_smart_callback_add(popup_, "unfocused", ContextMenuHWBackKey, this);
459     evas_object_focus_set(popup_, EINA_TRUE);
460 #endif
461     evas_object_smart_callback_add(popup_, "block,clicked", BlockClickedCallback, this);
462   }
463   evas_object_show(popup_);
464   return true;
465 }
466
467 void ContextMenuControllerEfl::HideSelectionHandle() {
468   SelectionControllerEfl* controller = webview_->GetSelectionController();
469   if (controller)
470     controller->HideHandles();
471 }
472
473 void ContextMenuControllerEfl::RequestShowSelectionHandleAndContextMenu() {
474   SelectionControllerEfl* controller = webview_->GetSelectionController();
475   if (controller) {
476     controller->SetSelectionStatus(true);
477     controller->SetWaitsForRendererSelectionChanges(true);
478   }
479 }
480
481 void ContextMenuControllerEfl::OnClipboardDownload(
482     content::DownloadItem* item,
483     content::DownloadInterruptReason interrupt_reason) {
484   item->AddObserver(this);
485   clipboard_download_items_.insert(item);
486 }
487
488 void EmptyDialogClosedCallback(
489     bool /* success */,
490     const base::string16& /* user_input */) {
491 }
492
493 void ContextMenuControllerEfl::OnDiskDownload(
494     content::DownloadItem* item,
495     content::DownloadInterruptReason interrupt_reason) {
496   if (!item) {
497     save_fail_dialog_.reset(JavaScriptModalDialogEfl::CreateDialog(
498         &web_contents_,
499         GURL(),
500         std::string(),
501         JavaScriptModalDialogEfl::ALERT,
502         base::UTF8ToUTF16(std::string(dgettext("WebKit", "IDS_WEBVIEW_POP_FAIL"))),
503         base::string16(),
504         base::Bind(&EmptyDialogClosedCallback)));
505     return;
506   }
507   item->AddObserver(this);
508   disk_download_items_.insert(item);
509 }
510
511 void ContextMenuControllerEfl::OnDownloadUpdated(content::DownloadItem* download) {
512   if(download && download->AllDataSaved()) {
513     if (clipboard_download_items_.find(download) != clipboard_download_items_.end()) {
514       const std::string& DownloadPath = download->GetForcedFilePath().value();
515 #if !defined(WAYLAND_BRINGUP)
516       ClipboardHelperEfl::GetInstance()->SetData(DownloadPath,
517                                                  ClipboardHelperEfl::CLIPBOARD_DATA_TYPE_IMAGE);
518 #else
519       NOTIMPLEMENTED();
520 #endif
521       download->RemoveObserver(this);
522       clipboard_download_items_.erase(download);
523     }
524     if (disk_download_items_.find(download) != disk_download_items_.end()) {
525       file_saved_dialog_.reset(JavaScriptModalDialogEfl::CreateDialog(
526           &web_contents_,
527           GURL(),
528           std::string(),
529           JavaScriptModalDialogEfl::ALERT,
530           base::UTF8ToUTF16(std::string(dgettext("WebKit", "IDS_WEBVIEW_POP_SAVED"))),
531           base::string16(),
532           base::Bind(&EmptyDialogClosedCallback)));
533       download->RemoveObserver(this);
534       disk_download_items_.erase(download);
535     }
536   }
537 }
538
539 base::FilePath ContextMenuControllerEfl::DownloadFile(const GURL url,
540     const base::FilePath outputDir,
541     const DownloadUrlParameters::OnStartedCallback &callback =
542         DownloadUrlParameters::OnStartedCallback()) {
543   LOG(INFO) << "Downloading file: " << url << "to: "<< outputDir.value();
544   const GURL referrer = web_contents_.GetVisibleURL();
545   DownloadManager* dlm = BrowserContext::GetDownloadManager(
546       web_contents_.GetBrowserContext());
547
548   scoped_ptr<DownloadUrlParameters> dl_params(
549       DownloadUrlParameters::FromWebContents(&web_contents_, url));
550   dl_params->set_post_id(-1);
551   dl_params->set_referrer(
552       content::Referrer(referrer, blink::WebReferrerPolicyAlways));
553   dl_params->set_referrer_encoding("utf8");
554   base::FilePath fileName = net::GenerateFileName(url,"","","","","");
555   base::FilePath fullPath = outputDir.Append(fileName);
556
557   while (PathExists(fullPath)) {
558     unsigned int i;
559     base::FilePath fileNameTmp;
560     for (i = 0; PathExists(fullPath) && i <= 999; i++) {
561       char buffer[6];
562       snprintf(buffer, sizeof(buffer), "(%d)", i);
563       fileNameTmp = fileName.InsertBeforeExtension(std::string(buffer));
564       fullPath = outputDir.Append(fileNameTmp);
565     }
566   }
567
568   dl_params->set_file_path(fullPath);
569   dl_params->set_prompt(true);
570   dl_params->set_callback(callback);
571   dlm->DownloadUrl(dl_params.Pass());
572   return fullPath;
573 }
574
575 bool ContextMenuControllerEfl::TriggerDownloadCb(const GURL url) {
576   BrowserContextEfl* browser_context =
577       static_cast<BrowserContextEfl*>(web_contents_.GetBrowserContext());
578   if (browser_context) {
579     EwkDidStartDownloadCallback* start_download_callback =
580         browser_context->WebContext()->DidStartDownloadCallback();
581     if (start_download_callback) {
582       DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
583       start_download_callback->TriggerCallback(url.spec());
584       return true;
585     }
586   }
587   return false;
588 }
589
590 void ContextMenuControllerEfl::OpenInNewTab(const GURL url) {
591   if (!url.is_valid())
592     return;
593   const GURL referrer = web_contents_.GetVisibleURL();
594   content::OpenURLParams params(url,
595                                 content::Referrer(referrer,
596                                                   blink::WebReferrerPolicyAlways),
597                                                   -1,
598                                                   NEW_FOREGROUND_TAB,
599                                                   ui::PAGE_TRANSITION_LINK,
600                                                   false);
601   web_contents_.GetDelegate()->OpenURLFromTab(&web_contents_, params);
602 }
603
604 void ContextMenuControllerEfl::ContextMenuListTrackResize(void* data, Evas* e,
605                                                           Evas_Object* obj, void* event_info)
606 {
607   int height;
608   evas_object_geometry_get(obj, 0, 0, 0, &height);
609
610   if (_popup_item_height == height)
611     return;
612
613   _popup_item_height = height;
614   ContextMenuPopupBoxResize(elm_object_top_widget_get(static_cast<Evas_Object*>(data)), data);
615 }
616
617 void ContextMenuControllerEfl::ContextMenuListRealized(void* data,
618                                                        Evas_Object* obj, void* event_info)
619 {
620   if (!event_info)
621     return;
622
623   Elm_Object_Item* item = static_cast<Elm_Object_Item*>(event_info);
624   size_t index = reinterpret_cast<size_t>(elm_object_item_data_get(item));
625
626 #if defined(OS_TIZEN)
627   Evas_Object* track = elm_object_item_track(item);
628   evas_object_event_callback_add(track, EVAS_CALLBACK_RESIZE, ContextMenuListTrackResize, obj);
629 #endif
630
631   if (index == _appended_item_size - 1)
632     elm_object_item_signal_emit(item, "elm,state,bottomline,hide", "");
633 }
634
635 char* ContextMenuControllerEfl::ContextMenuGenlistTextSet(void* data,
636                                                           Evas_Object* obj, const char* part)
637 {
638   size_t index = reinterpret_cast<size_t>(data);
639   if (index >= _appended_item_size)
640     return 0;
641
642   if (_context_menu_listdata.at(index).Title().empty())
643     return 0;
644
645   return strdup(_context_menu_listdata.at(index).Title().c_str());
646 }
647
648 void ContextMenuControllerEfl::ContextMenuPopupBoxResize(Evas_Object* top_widget, void* data)
649 {
650   _context_menu_resized = true;
651
652   Evas_Object* box = elm_object_parent_widget_get(static_cast<Evas_Object*>(data));
653
654   int rotation = elm_win_rotation_get(top_widget);
655   if ((rotation == 90 || rotation == 270) && _appended_item_size > 3)
656     evas_object_size_hint_min_set(box, 0, kMaxHeightHorizontal);
657   else if ((rotation == 0 || rotation == 180) && _appended_item_size > 7)
658     evas_object_size_hint_min_set(box, 0, kMaxHeightVertical);
659   else
660     evas_object_size_hint_min_set(box, 0, _appended_item_size * _popup_item_height);
661
662   evas_object_show(box);
663 }
664
665 void ContextMenuControllerEfl::ContextMenuPopupResize(void* data,
666                                                       Evas* e,
667                                                       Evas_Object* obj,
668                                                       void* event_info)
669 {
670    if (!_context_menu_resized)
671     ContextMenuPopupBoxResize(elm_object_top_widget_get(obj), data);
672 }
673
674 void ContextMenuControllerEfl::ContextMenuPopupRotationCallback(void* data,
675                                                                 Evas_Object* obj,
676                                                                 void* event_info)
677 {
678   ContextMenuPopupBoxResize(obj, data);
679 }
680
681 void ContextMenuControllerEfl::BlockClickedCallback(void* data, Evas_Object*, void*)
682 {
683   ContextMenuControllerEfl* menu_controller = static_cast<ContextMenuControllerEfl*>(data);
684
685   if (!menu_controller)
686     return;
687
688   menu_controller->HideContextMenu();
689 }
690
691 void ContextMenuControllerEfl::CustomMenuItemSelected(ContextMenuItemEfl* menu_item) {
692   _Ewk_Context_Menu_Item item(new ContextMenuItemEfl(menu_item->GetContextMenuOptionType(),
693                                                      menu_item->GetContextMenuOption(),
694                                                      menu_item->Title(),
695                                                      params_.src_url.spec(),
696                                                      params_.link_url.spec(),
697                                                      std::string()));
698   webview_->SmartCallback<EWebViewCallbacks::ContextMenuItemSelected>().call(&item);
699 }
700
701 void ContextMenuControllerEfl::MenuItemSelected(ContextMenuItemEfl* menu_item)
702 {
703   if (!menu_item)
704     return;
705
706   if (!webview_)
707     return;
708
709   if (popup_)
710     evas_object_hide(popup_);
711   // FIXME: Add cases as and when required
712   switch(menu_item->GetContextMenuOption())
713   {
714     case MENU_ITEM_OPEN_LINK_IN_NEW_WINDOW: {
715       OpenInNewTab(GURL(params_.link_url.spec()));
716       break;
717     }
718     case MENU_ITEM_GO_BACK: {
719       webview_->GoBack();
720       break;
721     }
722     case MENU_ITEM_GO_FORWARD: {
723       webview_->GoForward();
724       break;
725     }
726     case MENU_ITEM_RELOAD: {
727       webview_->ReloadIgnoringCache();
728       break;
729     }
730     case MENU_ITEM_COPY: {
731       webview_->ExecuteEditCommand("copy", NULL);
732       if (params_.is_editable) {
733         HideSelectionHandle();
734         Eina_Rectangle left_rect, right_rect;
735         webview_->GetSelectionRange(&left_rect, &right_rect);
736         webview_->MoveCaret(gfx::Point(right_rect.x, right_rect.y));
737       } else {
738         webview_->ExecuteEditCommand("Unselect", NULL);
739       }
740       break;
741     }
742     case MENU_ITEM_TEXT_SELECTION_MODE: {
743       Evas_Coord x, y;
744       evas_object_geometry_get(webview_->evas_object(), &x, &y, 0, 0);
745       webview_->SelectLinkText(gfx::Point(params_.x - x, params_.y - y));
746       RequestShowSelectionHandleAndContextMenu();
747       break;
748     }
749     case MENU_ITEM_COPY_IMAGE_TO_CLIPBOARD: {
750       DownloadFile(GURL(params_.src_url.spec()),
751           base::FilePath("/tmp/"),
752           base::Bind(&ContextMenuControllerEfl::OnClipboardDownload,
753               weak_ptr_factory_.GetWeakPtr()));
754       break;
755     }
756     case MENU_ITEM_COPY_LINK_TO_CLIPBOARD: {
757 #if !defined(WAYLAND_BRINGUP)
758       ClipboardHelperEfl::GetInstance()->SetData(params_.link_url.spec(),
759           ClipboardHelperEfl::CLIPBOARD_DATA_TYPE_URL);
760 #else
761       NOTIMPLEMENTED();
762 #endif
763       break;
764     }
765     case MENU_ITEM_DOWNLOAD_LINK_TO_DISK: {
766       if (!TriggerDownloadCb(GURL(params_.link_url.spec()))) {
767         base::FilePath path;
768         if (!PathService::Get(PathsEfl::DIR_DOWNLOADS, &path)) {
769           LOG(ERROR) << "Could not get downloads directory.";
770           break;
771         }
772         DownloadFile(GURL(params_.link_url.spec()),
773             path,
774             base::Bind(&ContextMenuControllerEfl::OnDiskDownload,
775                 weak_ptr_factory_.GetWeakPtr()));
776       }
777       break;
778     }
779     case MENU_ITEM_DOWNLOAD_IMAGE_TO_DISK: {
780       if (!TriggerDownloadCb(GURL(params_.src_url.spec()))) {
781         base::FilePath path;
782         if (!PathService::Get(PathsEfl::DIR_DOWNLOAD_IMAGE, &path)) {
783           LOG(ERROR) << "Could not get image downloads directory.";
784           break;
785         }
786         DownloadFile(GURL(params_.src_url.spec()),
787             path,
788             base::Bind(&ContextMenuControllerEfl::OnDiskDownload,
789                 weak_ptr_factory_.GetWeakPtr()));
790       }
791       break;
792     }
793     case MENU_ITEM_OPEN_IMAGE_IN_NEW_WINDOW: {
794       OpenInNewTab(GURL(params_.src_url.spec()));
795       break;
796     }
797     case MENU_ITEM_SELECT_WORD: {
798       webview_->ExecuteEditCommand("SelectWord", NULL);
799       RequestShowSelectionHandleAndContextMenu();
800       break;
801     }
802     case MENU_ITEM_SELECT_ALL: {
803       webview_->ExecuteEditCommand("SelectAll", NULL);
804       RequestShowSelectionHandleAndContextMenu();
805       break;
806     }
807     case MENU_ITEM_PASTE: {
808       webview_->ExecuteEditCommand("paste", NULL);
809       HideSelectionHandle();
810       break;
811     }
812     case MENU_ITEM_CUT: {
813       webview_->ExecuteEditCommand("cut", NULL);
814       HideSelectionHandle();
815       break;
816     }
817     case MENU_ITEM_CLIPBOARD: {
818       // TODO: set true for richly editable.
819       // Paste operations are blocked by Editor if content is not richly editible.
820       // Need to find if webview_ has rich editor.
821 #if !defined(WAYLAND_BRINGUP)
822       ClipboardHelperEfl::GetInstance()->OpenClipboardWindow(webview_, true);
823 #else
824       NOTIMPLEMENTED();
825 #endif
826       break;
827     }
828     case MENU_ITEM_DRAG: {
829 #if !defined(EWK_BRINGUP)
830       RenderViewHost* rvh = web_contents_.GetRenderViewHost();
831       rvh->StartDragging();
832       context_menu_show_pos_.SetPoint(params_.x, params_.y);
833 #else
834       NOTIMPLEMENTED();
835 #endif
836       break;
837     }
838     default:
839       CustomMenuItemSelected(menu_item);
840   }
841 }
842
843 void ContextMenuControllerEfl::HideContextMenu() {
844   if (popup_) {
845     evas_object_del(popup_);
846     popup_ = NULL;
847   }
848
849   _context_menu_resized = false;
850
851   if (menu_items_) {
852     void* data;
853     EINA_LIST_FREE(menu_items_, data) {
854       _Ewk_Context_Menu_Item *item = static_cast<_Ewk_Context_Menu_Item*> (data);
855       delete item;
856     }
857     menu_items_ = NULL;
858   }
859 }
860
861
862 void ContextMenuControllerEfl::SetPopupSize(int width, int height) {
863   if (save_fail_dialog_)
864     save_fail_dialog_->SetPopupSize(width, height);
865   if (file_saved_dialog_)
866     file_saved_dialog_->SetPopupSize(width, height);
867
868   if (!popup_)
869     return;
870
871   evas_object_resize(popup_, width, height);
872   evas_object_move(popup_, 0, 0);
873 }
874
875 void ContextMenuControllerEfl::DeletePopup() {
876   if (native_view_)
877     evas_object_data_set(native_view_, "ContextMenuContollerEfl", 0);
878
879   if (popup_) {
880     evas_object_data_set(popup_, "ContextMenuContollerEfl", 0);
881     evas_object_del(popup_);
882     popup_ = 0;
883   }
884
885   if (menu_items_) {
886     void* data;
887     EINA_LIST_FREE(menu_items_, data) {
888       _Ewk_Context_Menu_Item *item = static_cast<_Ewk_Context_Menu_Item*> (data);
889       delete item;
890     }
891     menu_items_ = NULL;
892   }
893 }
894 }