}
#endif
+#if BUILDFLAG(IS_TIZEN)
+ int GetOrientation() { return orientation_; }
+#endif
+
private:
// Just the metadata from DropTargetEvent that's safe and cheap to copy to
// help locate drop events in the callback.
std::unique_ptr<WebContentsViewAuraHelperEfl> wcva_helper_;
#endif
+#if BUILDFLAG(IS_TIZEN)
+ int orientation_ = 0;
+#endif
+
base::WeakPtrFactory<WebContentsViewAura> weak_ptr_factory_{this};
};
# Source
##############################################################################
external_content_browser_efl_sources = [
+ "//tizen_src/chromium_impl/content/browser/context_menu/context_menu_controller_base.cc",
+ "//tizen_src/chromium_impl/content/browser/context_menu/context_menu_controller_base.h",
"//tizen_src/chromium_impl/content/browser/date_time_chooser_efl.cc",
"//tizen_src/chromium_impl/content/browser/date_time_chooser_efl.h",
"//tizen_src/chromium_impl/content/browser/input_picker/input_picker_base.cc",
--- /dev/null
+// Copyright 2022 Samsung Electronics. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "context_menu_controller_base.h"
+
+#include <Elementary.h>
+
+#include "content/browser/renderer_host/render_widget_host_view_aura.h"
+#include "content/browser/web_contents/web_contents_impl.h"
+#include "content/browser/web_contents/web_contents_view_aura.h"
+#include "tizen_src/chromium_impl/tizen/system_info.h"
+#include "tizen_src/ewk/efl_integration/private/ewk_context_menu_item_private.h"
+#include "ui/display/screen.h"
+#include "ui/gfx/geometry/dip_util.h"
+#include "ui/gfx/geometry/rect.h"
+
+#if BUILDFLAG(IS_TIZEN)
+#include <app_control.h>
+#include <efl_extension.h>
+#endif
+
+namespace content {
+
+namespace {
+// The height of the selection menu.
+static const int kMenuHeight = 64;
+
+// Popup will be restored after kRestoreTime if it is dismissed unexpectedly.
+static const float kRestoreTime = 0.5f;
+
+const int kMinHeightVertical = 840;
+const int kMinHeightHorizontal = 420;
+} // namespace
+
+int ContextMenuControllerBase::_popup_item_height = 96;
+std::vector<ContextMenuItemEfl>
+ ContextMenuControllerBase::_context_menu_listdata;
+
+ContextMenuControllerBase::ContextMenuControllerBase(WebContents& web_contents)
+ : web_contents_(web_contents) {
+ native_view_ =
+ static_cast<WebContentsImpl*>(&web_contents_)->GetEflNativeView();
+}
+
+ContextMenuControllerBase::~ContextMenuControllerBase() {
+ _context_menu_listdata.clear();
+ DeletePopup();
+}
+
+void ContextMenuControllerBase::Move(int x, int y) {
+ if (popup_ && is_text_selection_)
+ evas_object_move(popup_, x, y);
+}
+
+bool ContextMenuControllerBase::CreateContextMenu(
+ const ContextMenuParams& params) {
+ is_text_selection_ = false;
+ Eina_List* ittr;
+ void* data;
+ EINA_LIST_FOREACH(menu_items_, ittr, data) {
+ _Ewk_Context_Menu_Item* item = static_cast<_Ewk_Context_Menu_Item*>(data);
+ ContextMenuItemEfl* context_item = item->GetMenuItem();
+ switch (context_item->GetContextMenuOption()) {
+ case EWK_CONTEXT_MENU_ITEM_TAG_COPY:
+ case EWK_CONTEXT_MENU_ITEM_TAG_SELECT_ALL:
+ case EWK_CONTEXT_MENU_ITEM_TAG_SELECT_WORD:
+ case EWK_CONTEXT_MENU_ITEM_TAG_PASTE:
+ is_text_selection_ = true;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (is_text_selection_) {
+ popup_ = elm_ctxpopup_add(native_view_);
+#if BUILDFLAG(IS_TIZEN)
+ elm_ctxpopup_horizontal_set(popup_, EINA_TRUE);
+#endif
+ elm_object_tree_focus_allow_set(popup_, false);
+ } else {
+ top_widget_ =
+ elm_object_top_widget_get(elm_object_parent_widget_get(evas_object()));
+ evas_object_data_set(top_widget_, "ContextMenuContollerEfl", this);
+ popup_ = elm_popup_add(top_widget_);
+
+ if (IsMobileProfile())
+ elm_popup_align_set(popup_, ELM_NOTIFY_ALIGN_FILL, 1.0);
+ else
+ elm_popup_align_set(popup_, 0.5, 0.5);
+ }
+
+ if (!popup_)
+ return false;
+
+ if (!IsMobileProfile())
+ evas_object_smart_member_add(popup_, evas_object());
+
+ elm_object_tree_focus_allow_set(popup_, EINA_FALSE);
+
+ evas_object_data_set(popup_, "ContextMenuContollerEfl", this);
+
+ _context_menu_listdata.clear();
+ if (is_text_selection_) {
+ EINA_LIST_FOREACH(menu_items_, ittr, data) {
+ _Ewk_Context_Menu_Item* item = static_cast<_Ewk_Context_Menu_Item*>(data);
+ ContextMenuItemEfl* context_item = item->GetMenuItem();
+ Elm_Object_Item* appended_item = 0;
+
+ if (!context_item->Title().empty()) {
+ appended_item = elm_ctxpopup_item_append(
+ popup_, context_item->Title().c_str(), 0,
+ ContextMenuItemSelectedCallback, context_item);
+ } else {
+ appended_item = elm_ctxpopup_item_append(
+ popup_, 0, 0, ContextMenuItemSelectedCallback, context_item);
+ }
+
+ if (appended_item)
+ _context_menu_listdata.push_back(*context_item);
+ }
+#if BUILDFLAG(IS_TIZEN)
+ // Workaround
+ // Need to set "copypaste" style, to let moving handles
+ // when ctxpopup is visible
+ // http://107.108.218.239/bugzilla/show_bug.cgi?id=11613
+ elm_object_style_set(popup_, "copypaste");
+#endif
+
+ evas_object_size_hint_weight_set(popup_, EVAS_HINT_EXPAND,
+ EVAS_HINT_EXPAND);
+ evas_object_size_hint_max_set(popup_, -1, _popup_item_height);
+ evas_object_size_hint_min_set(popup_, 0, _popup_item_height);
+ } else {
+ std::string selected_link(params_.link_url.spec());
+ if (!selected_link.empty()) {
+ if (base::StartsWith(selected_link, std::string("mailto:"),
+ base::CompareCase::INSENSITIVE_ASCII) ||
+ base::StartsWith(selected_link, std::string("tel:"),
+ base::CompareCase::INSENSITIVE_ASCII)) {
+ size_t current_pos = 0;
+ size_t next_delimiter = 0;
+ // Remove the First part and Extract actual URL or title
+ // (mailto:abc@d.com?id=345 ==> abc@d.com?id=345)
+ if ((next_delimiter = selected_link.find(":", current_pos)) !=
+ std::string::npos) {
+ current_pos = next_delimiter + 1;
+ }
+
+ std::string last_part = selected_link.substr(current_pos);
+ std::string core_part = selected_link.substr(current_pos);
+ current_pos = 0;
+ next_delimiter = 0;
+ // Trim the core by removing ? at the end (abc@d.com?id=345 ==>
+ // abc@d.com)
+ if ((next_delimiter = core_part.find("?", current_pos)) !=
+ std::string::npos) {
+ last_part =
+ core_part.substr(current_pos, next_delimiter - current_pos);
+ }
+ } else {
+ elm_object_part_text_set(popup_, "title,text", selected_link.c_str());
+ }
+ } else {
+ std::string selected_image(params_.src_url.spec());
+ if (!selected_image.empty())
+ elm_object_part_text_set(popup_, "title,text", selected_image.c_str());
+ }
+
+ evas_object_size_hint_weight_set(popup_, EVAS_HINT_EXPAND,
+ EVAS_HINT_EXPAND);
+
+ list_ = elm_list_add(popup_);
+ elm_list_mode_set(list_, ELM_LIST_EXPAND);
+ evas_object_data_set(list_, "ContextMenuContollerEfl", this);
+
+ Eina_List* ittr;
+ void* data;
+ EINA_LIST_FOREACH(menu_items_, ittr, data) {
+ _Ewk_Context_Menu_Item* item = static_cast<_Ewk_Context_Menu_Item*>(data);
+ ContextMenuItemEfl* context_item = item->GetMenuItem();
+ if (!context_item->Title().empty()) {
+ Elm_Object_Item* appended_item = elm_list_item_append(
+ list_, context_item->Title().c_str(), NULL, NULL,
+ ContextMenuItemSelectedCallback, context_item);
+
+ if (appended_item)
+ _context_menu_listdata.push_back(*context_item);
+ }
+ }
+
+ ContextMenuPopupListResize();
+
+ evas_object_show(list_);
+ elm_object_content_set(popup_, list_);
+ evas_object_event_callback_add(popup_, EVAS_CALLBACK_RESIZE,
+ ContextMenuPopupResize, this);
+ }
+
+ if (_context_menu_listdata.empty()) {
+ DeletePopup();
+ return false;
+ }
+ return true;
+}
+
+// static
+void ContextMenuControllerBase::ContextMenuHWBackKey(void* data,
+ Evas_Object* obj,
+ void* event_info) {
+ auto menu_controller = static_cast<ContextMenuControllerBase*>(data);
+ if (menu_controller) {
+ auto selection_controller = menu_controller->GetSelectionController();
+ if (selection_controller)
+ selection_controller->ToggleCaretAfterSelection();
+
+ menu_controller->HideContextMenu();
+ evas_object_data_del(obj, "ContextEfl");
+ }
+}
+
+// static
+Eina_Bool ContextMenuControllerBase::RestoreTimerCallback(void* data) {
+ auto* menu_controller = static_cast<ContextMenuControllerBase*>(data);
+ if (!menu_controller)
+ return ECORE_CALLBACK_CANCEL;
+
+ auto selection_controller = menu_controller->GetSelectionController();
+
+ if (menu_controller->popup_ && selection_controller &&
+ selection_controller->GetSelectionStatus() &&
+ !selection_controller->IsCaretMode()) {
+ evas_object_show(menu_controller->popup_);
+ }
+
+ menu_controller->restore_timer_ = nullptr;
+
+ return ECORE_CALLBACK_CANCEL;
+}
+
+// static
+void ContextMenuControllerBase::ContextMenuCancelCallback(void* data,
+ Evas_Object* obj,
+ void* event_info) {
+ ContextMenuControllerBase* menu_controller =
+ static_cast<ContextMenuControllerBase*>(
+ evas_object_data_get(obj, "ContextMenuContollerEfl"));
+ if (!menu_controller)
+ return;
+
+ RenderWidgetHostViewAura* rwhva = menu_controller->rwhva();
+ if (!rwhva)
+ return;
+
+ // context_menu is dismissed when we touch outside of popup.
+ // It is policy of elm_ctxpopup by EFL team.
+ // But according to wcs TC(21~23) context_menu should be displayed,
+ // when touchevent is consumed. So we should show context_menu again when
+ // touchevent is consumed.
+ if (rwhva->offscreen_helper()->IsTouchstartConsumed() ||
+ rwhva->offscreen_helper()->IsTouchendConsumed()) {
+ evas_object_show(menu_controller->popup_);
+ return;
+ }
+
+ // TODO: If |elm_ctxpopup_auto_hide_disabled_set| is works properly,
+ // We should remove this timer.
+ // Bug: http://suprem.sec.samsung.net/jira/browse/TNEXT-67
+ menu_controller->restore_timer_ =
+ ecore_timer_add(kRestoreTime, RestoreTimerCallback, menu_controller);
+}
+
+// static
+void ContextMenuControllerBase::ContextMenuItemSelectedCallback(
+ void* data,
+ Evas_Object* obj,
+ void* event_info) {
+ Evas_Object* pop_up = obj;
+ ContextMenuControllerBase* menu_controller =
+ static_cast<ContextMenuControllerBase*>(
+ evas_object_data_get(pop_up, "ContextMenuContollerEfl"));
+
+ if (menu_controller) {
+ ContextMenuItemEfl* selected_menu_item =
+ static_cast<ContextMenuItemEfl*>(data);
+ if (selected_menu_item)
+ menu_controller->MenuItemSelected(selected_menu_item);
+ }
+}
+
+void ContextMenuControllerBase::RequestSelectionRect() const {
+ CHECK(rwhva());
+ rwhva()->host()->RequestSelectionRect();
+}
+
+gfx::Point ContextMenuControllerBase::CalculateSelectionMenuPosition(
+ const gfx::Rect& selection_rect) {
+ auto* selection_controller = GetSelectionController();
+ if (!selection_controller)
+ return gfx::Point();
+
+ auto visible_viewport_rect = selection_controller->GetVisibleViewportRect();
+ auto forbidden_rect =
+ selection_controller->GetForbiddenRegionRect(selection_rect);
+
+ gfx::Point position;
+ // Selection menu should always be placed at the centre of visible selection
+ // area horizontally.
+ position.set_x(forbidden_rect.CenterPoint().x());
+ // If possible, selection menu should always be placed above forbidden
+ // region.
+
+ if (forbidden_rect.y() > visible_viewport_rect.y() + kMenuHeight) {
+ // If possible, selection menu should always be placed above forbidden
+ // region.
+ position.set_y(forbidden_rect.y());
+ } else if (forbidden_rect.bottom() + kMenuHeight <
+ visible_viewport_rect.bottom()) {
+ // If there is no sufficient space above, we're trying to place selection
+ // menu below forbidden region.
+ position.set_y(forbidden_rect.bottom() + kMenuHeight);
+ } else {
+ // If there is no sufficient space above and below, selection menu will be
+ // shown at the centre of visible selection area vertically.
+ position.set_y(forbidden_rect.CenterPoint().y());
+ }
+
+ return position;
+}
+
+void ContextMenuControllerBase::OnSelectionRectReceived(
+ gfx::Rect selection_rect) {
+ auto controller = GetSelectionController();
+
+ if (IsMobileProfile() && (context_menu_status_ != INPROGRESS))
+ return;
+
+ if (!popup_ || !rwhva() || !controller)
+ return;
+
+ float device_scale =
+ display::Screen::GetScreen()->GetPrimaryDisplay().device_scale_factor();
+ gfx::Rect selection_rect_dip = gfx::ToEnclosingRect(
+ ConvertRectToPixels(gfx::Rect(selection_rect), device_scale));
+
+ // Consider a webview offset.
+ selection_rect_dip.Offset(
+ rwhva()->offscreen_helper()->GetViewBoundsInPix().OffsetFromOrigin());
+
+ auto visible_viewport_rect = controller->GetVisibleViewportRect();
+
+ // In case of the caret mode selection_rect is empty
+ if (!controller->IsCaretMode() &&
+ gfx::IntersectRects(visible_viewport_rect, selection_rect_dip)
+ .IsEmpty()) {
+ return;
+ }
+
+ gfx::Point selection_menu_position =
+ CalculateSelectionMenuPosition(selection_rect_dip);
+ if (!visible_viewport_rect.Contains(selection_menu_position))
+ return;
+
+ evas_object_smart_callback_add(popup_, "dismissed", ContextMenuCancelCallback,
+ this);
+
+ if (IsMobileProfile())
+ elm_ctxpopup_auto_hide_disabled_set(popup_, EINA_TRUE);
+
+#if BUILDFLAG(IS_TIZEN)
+ eext_object_event_callback_add(popup_, EEXT_CALLBACK_BACK,
+ ContextMenuHWBackKey, this);
+#endif
+ evas_object_move(popup_, selection_menu_position.x(),
+ selection_menu_position.y());
+
+ controller->ContextMenuStatusVisible();
+
+ evas_object_show(popup_);
+ evas_object_raise(popup_);
+ if (IsMobileProfile())
+ context_menu_status_ = VISIBLE;
+}
+
+bool ContextMenuControllerBase::ShowContextMenu() {
+ if (!popup_)
+ return false;
+
+ if (IsMobileProfile())
+ context_menu_status_ = INPROGRESS;
+
+ if (is_text_selection_) {
+ // Selection menu will be shown in OnSelectionRectReceived after receiving
+ // selection rectangle form the renderer.
+ RequestSelectionRect();
+ } else {
+ evas_object_smart_callback_add(popup_, "block,clicked",
+ BlockClickedCallback, this);
+#if BUILDFLAG(IS_TIZEN)
+ eext_object_event_callback_add(popup_, EEXT_CALLBACK_BACK,
+ ContextMenuHWBackKey, this);
+ eext_object_event_callback_add(popup_, EEXT_CALLBACK_MORE,
+ ContextMenuHWBackKey, this);
+#endif
+ evas_object_show(popup_);
+ evas_object_raise(popup_);
+ if (IsMobileProfile())
+ context_menu_status_ = VISIBLE;
+ }
+ return true;
+}
+
+void ContextMenuControllerBase::HideSelectionHandle() {
+ auto* controller = GetSelectionController();
+ if (controller)
+ controller->HideHandles();
+}
+
+void ContextMenuControllerBase::ClearSelection() {
+ auto controller = GetSelectionController();
+ if (controller)
+ controller->ClearSelection();
+}
+
+void ContextMenuControllerBase::RequestShowSelectionHandleAndContextMenu(
+ bool trigger_selection_change) {
+ auto* controller = GetSelectionController();
+ if (controller) {
+ controller->SetSelectionStatus(true);
+ controller->SetWaitsForRendererSelectionChanges(
+ SelectionControllerEfl::Reason::RequestedByContextMenu);
+ if (trigger_selection_change)
+ controller->TriggerOnSelectionChange();
+ }
+}
+
+#if BUILDFLAG(IS_TIZEN)
+static void destroy_app_handle(app_control_h* handle) {
+ std::ignore = app_control_destroy(*handle);
+}
+
+void ContextMenuControllerBase::LaunchShareApp(const std::string& text) {
+ app_control_h handle = nullptr;
+ int error_code = app_control_create(&handle);
+ if (error_code < 0 || !handle) {
+ LOG(ERROR) << __PRETTY_FUNCTION__
+ << " : Failed to create share service. Error code: "
+ << error_code;
+ return;
+ }
+
+ std::unique_ptr<app_control_h, decltype(&destroy_app_handle)> handle_ptr(
+ &handle, destroy_app_handle);
+
+ error_code =
+ app_control_set_operation(handle, APP_CONTROL_OPERATION_SHARE_TEXT);
+ if (error_code < 0) {
+ LOG(ERROR) << __PRETTY_FUNCTION__
+ << ": Failed to set share text operation. Error code: "
+ << error_code;
+ return;
+ }
+
+ error_code =
+ app_control_add_extra_data(handle, APP_CONTROL_DATA_TEXT, text.c_str());
+ if (error_code < 0) {
+ LOG(ERROR) << __PRETTY_FUNCTION__
+ << ": Failed to add data for share application. Error code: "
+ << error_code;
+ return;
+ }
+
+ error_code = app_control_send_launch_request(handle, nullptr, nullptr);
+ if (error_code < 0) {
+ LOG(ERROR) << __PRETTY_FUNCTION__
+ << ": Failed to send launch request for share application. "
+ << "Error code: " << error_code;
+ return;
+ }
+}
+#endif
+
+// static
+void ContextMenuControllerBase::ContextMenuPopupResize(void* data,
+ Evas* e,
+ Evas_Object* obj,
+ void* event_info) {
+ auto* thiz = static_cast<ContextMenuControllerBase*>(data);
+ if (thiz)
+ thiz->ContextMenuPopupListResize();
+}
+
+// static
+void ContextMenuControllerBase::BlockClickedCallback(void* data,
+ Evas_Object*,
+ void*) {
+ ContextMenuControllerBase* menu_controller =
+ static_cast<ContextMenuControllerBase*>(data);
+ if (!menu_controller)
+ return;
+
+ menu_controller->HideContextMenu();
+}
+
+void ContextMenuControllerBase::ContextMenuPopupListResize() {
+ if (!IsMobileProfile())
+ return;
+
+ int orientation = GetOrientation();
+ if ((orientation == 90 || orientation == 270) &&
+ _context_menu_listdata.size() > 3)
+ evas_object_size_hint_min_set(list_, 0, kMinHeightHorizontal);
+ else if ((orientation == 0 || orientation == 180) &&
+ _context_menu_listdata.size() > 7)
+ evas_object_size_hint_min_set(list_, 0, kMinHeightVertical);
+ else
+ evas_object_size_hint_min_set(
+ list_, 0, _context_menu_listdata.size() * _popup_item_height);
+
+ evas_object_show(list_);
+}
+
+void ContextMenuControllerBase::HideContextMenu() {
+ if (IsMobileProfile() &&
+ (context_menu_status_ == HIDDEN || context_menu_status_ == NONE))
+ return;
+
+ if (is_text_selection_) {
+ SelectionControllerEfl* controller = GetSelectionController();
+ if (controller)
+ controller->ContextMenuStatusHidden();
+ }
+
+ if (popup_) {
+ if (IsMobileProfile()) {
+ evas_object_hide(popup_);
+ } else {
+ evas_object_event_callback_del(popup_, EVAS_CALLBACK_RESIZE,
+ ContextMenuPopupResize);
+ evas_object_del(popup_);
+ popup_ = nullptr;
+ }
+ }
+
+ if (restore_timer_) {
+ ecore_timer_del(restore_timer_);
+ restore_timer_ = nullptr;
+ }
+
+ if (IsMobileProfile()) {
+ context_menu_status_ = HIDDEN;
+ } else if (menu_items_) {
+ void* data;
+ EINA_LIST_FREE(menu_items_, data) {
+ _Ewk_Context_Menu_Item* item = static_cast<_Ewk_Context_Menu_Item*>(data);
+ delete item;
+ }
+ menu_items_ = nullptr;
+ }
+}
+
+void ContextMenuControllerBase::Resize(const gfx::Rect& webview_rect) {
+ if (!popup_)
+ return;
+
+ if (IsMobileProfile() && context_menu_status_ != VISIBLE)
+ return;
+
+ if (is_text_selection_) {
+ RequestSelectionRect();
+ } else {
+ evas_object_resize(popup_, webview_rect.width(), webview_rect.height());
+ }
+}
+
+void ContextMenuControllerBase::DeletePopup() {
+ if (top_widget_)
+ evas_object_data_set(top_widget_, "ContextMenuContollerEfl", 0);
+
+ if (is_text_selection_) {
+ SelectionControllerEfl* controller = GetSelectionController();
+ if (controller)
+ controller->ContextMenuStatusHidden();
+ }
+
+ if (popup_) {
+ evas_object_data_set(popup_, "ContextMenuContollerEfl", 0);
+ if (!IsMobileProfile())
+ evas_object_smart_member_del(popup_);
+ evas_object_del(popup_);
+ popup_ = nullptr;
+ list_ = nullptr;
+ }
+
+ if (menu_items_) {
+ void* data;
+ EINA_LIST_FREE(menu_items_, data) {
+ _Ewk_Context_Menu_Item* item = static_cast<_Ewk_Context_Menu_Item*>(data);
+ delete item;
+ }
+ menu_items_ = nullptr;
+ }
+ if (IsMobileProfile())
+ context_menu_status_ = NONE;
+}
+
+RenderWidgetHostViewAura* ContextMenuControllerBase::rwhva() const {
+ return static_cast<RenderWidgetHostViewAura*>(
+ web_contents_.GetRenderWidgetHostView());
+}
+
+WebContentsViewAura* ContextMenuControllerBase::GetWebContentsViewAura() const {
+ WebContentsImpl* wc = static_cast<WebContentsImpl*>(&web_contents_);
+ return static_cast<WebContentsViewAura*>(wc->GetView());
+}
+
+int ContextMenuControllerBase::GetOrientation() {
+#if BUILDFLAG(IS_TIZEN)
+ return GetWebContentsViewAura()->GetOrientation();
+#else
+ return 0;
+#endif
+}
+
+SelectionControllerEfl* ContextMenuControllerBase::GetSelectionController() {
+ RenderViewHost* render_view_host = web_contents_.GetRenderViewHost();
+ RenderWidgetHostViewAura* view = static_cast<RenderWidgetHostViewAura*>(
+ render_view_host->GetWidget()->GetView());
+ return view ? view->offscreen_helper()->GetSelectionController() : 0;
+}
+
+const char* ContextMenuControllerBase::GetSelectedText() {
+ if (!rwhva())
+ return "";
+
+ std::string selected_text = base::UTF16ToUTF8(rwhva()->GetSelectedText());
+ return selected_text.c_str();
+}
+
+} // namespace content
--- /dev/null
+// Copyright 2022 Samsung Electronics. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef context_menu_controller_base_h
+#define context_menu_controller_base_h
+
+#include <Ecore.h>
+#include <Evas.h>
+
+#include "content/public/browser/context_menu_params.h"
+#include "content/public/browser/web_contents.h"
+#include "tizen_src/ewk/efl_integration/public/ewk_context_menu_internal.h"
+
+namespace gfx {
+class Rect;
+}
+
+namespace content {
+class RenderWidgetHostViewAura;
+class SelectionControllerEfl;
+class WebContents;
+class WebContentsViewAura;
+
+class ContextMenuItemEfl {
+ public:
+ ContextMenuItemEfl(Ewk_Context_Menu_Item_Type item,
+ Ewk_Context_Menu_Item_Tag option,
+ const std::string& title,
+ const std::string& image_url = std::string(),
+ const std::string& link_url = std::string(),
+ const std::string& icon_path = std::string())
+ : menu_type_(item),
+ menu_option_(option),
+ title_(title),
+ is_enabled_(true),
+ image_url_(image_url),
+ link_url_(link_url),
+ icon_path_(icon_path) {}
+
+ ~ContextMenuItemEfl() {}
+
+ const std::string& Title() const { return title_; }
+ void SetTitle(const std::string& title) { title_ = title; }
+
+ bool IsEnabled() const { return is_enabled_; }
+ void SetEnabled(bool status) { is_enabled_ = status; }
+ Ewk_Context_Menu_Item_Tag GetContextMenuOption() const {
+ return menu_option_;
+ }
+ Ewk_Context_Menu_Item_Type GetContextMenuOptionType() const {
+ return menu_type_;
+ }
+ const std::string& LinkURL() const { return link_url_; }
+ const std::string& ImageURL() const { return image_url_; }
+ const std::string& IconPath() const { return icon_path_; }
+
+ private:
+ Ewk_Context_Menu_Item_Type menu_type_;
+ Ewk_Context_Menu_Item_Tag menu_option_;
+ std::string title_;
+ bool is_enabled_;
+ std::string image_url_;
+ std::string link_url_;
+ std::string icon_path_;
+};
+
+class ContextMenuControllerBase {
+ public:
+ ContextMenuControllerBase(WebContents& web_contents);
+ virtual ~ContextMenuControllerBase();
+
+ ContextMenuControllerBase(const ContextMenuControllerBase&) = delete;
+ ContextMenuControllerBase& operator=(const ContextMenuControllerBase&) =
+ delete;
+
+ static void ContextMenuCancelCallback(void* data,
+ Evas_Object* obj,
+ void* event_info);
+ static void ContextMenuItemSelectedCallback(void* data,
+ Evas_Object* obj,
+ void* event_info);
+ static void ContextMenuHWBackKey(void* data,
+ Evas_Object* obj,
+ void* event_info);
+
+ void Move(int x, int y);
+ void HideContextMenu();
+
+ void RequestSelectionRect() const;
+ void OnSelectionRectReceived(gfx::Rect selection_rect);
+ gfx::Point CalculateSelectionMenuPosition(const gfx::Rect& selection_rect);
+
+ virtual void Resize(const gfx::Rect& webview_rect);
+ virtual void MenuItemSelected(ContextMenuItemEfl* menu_item) = 0;
+
+ protected:
+ bool CreateContextMenu(const ContextMenuParams& params);
+ bool ShowContextMenu();
+ void HideSelectionHandle();
+ void ClearSelection();
+ void RequestShowSelectionHandleAndContextMenu(
+ bool trigger_selection_change = false);
+#if BUILDFLAG(IS_TIZEN)
+ void LaunchShareApp(const std::string& text);
+#endif
+ RenderWidgetHostViewAura* rwhva() const;
+ SelectionControllerEfl* GetSelectionController();
+
+ Eina_List* menu_items_ = nullptr;
+ ContextMenuParams params_;
+ WebContents& web_contents_;
+ bool is_text_selection_ = false;
+
+ private:
+ virtual Evas_Object* evas_object() = 0;
+
+ enum ContextMenuStatusTag { NONE = 0, HIDDEN, INPROGRESS, VISIBLE };
+ static void ContextMenuPopupResize(void* data,
+ Evas* e,
+ Evas_Object* obj,
+ void* event_info);
+ static void BlockClickedCallback(void*, Evas_Object*, void*);
+ void ContextMenuPopupListResize();
+ static Eina_Bool RestoreTimerCallback(void* data);
+
+ void DeletePopup();
+ int GetOrientation();
+ virtual const char* GetSelectedText();
+ WebContentsViewAura* GetWebContentsViewAura() const;
+
+ static std::vector<ContextMenuItemEfl> _context_menu_listdata;
+ static int _popup_item_height;
+
+ Evas_Object* native_view_;
+ Evas_Object* top_widget_ = nullptr;
+ Evas_Object* popup_ = nullptr;
+ Evas_Object* list_ = nullptr;
+ Ecore_Timer* restore_timer_ = nullptr;
+ ContextMenuStatusTag context_menu_status_ = NONE;
+};
+
+} // namespace content
+
+#endif // context_menu_controller_base_h
"private/ewk_console_message_private.h",
"private/ewk_context_form_autofill_profile_private.cc",
"private/ewk_context_form_autofill_profile_private.h",
+ "private/ewk_context_menu_item_private.h",
"private/ewk_context_menu_private.h",
"private/ewk_context_private.cc",
"private/ewk_context_private.h",
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include <Elementary.h>
-#include <stdio.h>
-#include <stdlib.h>
+#include "context_menu_controller_efl.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/strings/escape.h"
#include "base/strings/utf_string_conversions.h"
#include "browser_context_efl.h"
-#include "common/web_contents_utils.h"
#include "content/browser/renderer_host/render_widget_host_view_aura.h"
#include "content/browser/selection/selection_controller_efl.h"
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/common/paths_efl.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/download_manager.h"
-#include "content/public/browser/navigation_entry.h"
-#include "content/public/browser/render_process_host.h"
-#include "context_menu_controller_efl.h"
+#include "content/public/browser/render_view_host.h"
#include "eweb_view.h"
#include "net/base/filename_util.h"
-#include "net/traffic_annotation/network_traffic_annotation.h"
#include "private/ewk_context_menu_private.h"
#include "public/ewk_context_menu_product.h"
#include "third_party/blink/public/mojom/context_menu/context_menu.mojom.h"
#include "tizen/system_info.h"
-#include "ui/base/clipboard/clipboard.h"
#include "ui/base/clipboard/clipboard_helper_efl.h"
-#include "ui/display/screen.h"
#include "ui/gfx/geometry/dip_util.h"
-#include "ui/gfx/geometry/rect.h"
#if BUILDFLAG(IS_TIZEN)
#include <app_control.h>
-#include <efl_extension.h>
-#include <memory>
#endif
using blink::mojom::ContextMenuDataMediaType;
-using web_contents_utils::WebViewFromWebContents;
namespace {
-#define VERTICAL true
-#define HORIZONTAL false
-
-// The height of the selection menu.
-static const int kMenuHeight = 64;
-
-// Popup will be restored after kRestoreTime if it is dismissed unexpectedly.
-static const float kRestoreTime = 0.5f;
-
-const int kMinHeightVertical = 840;
-const int kMinHeightHorizontal = 420;
-
const std::string kWebSearchLink("https://www.google.com/search?q=");
const char* const kEditCommandUnselect = "Unselect";
const char* const kDefaultImageExtension = "jpg";
-}
+} // namespace
namespace content {
-int ContextMenuControllerEfl::_popup_item_height = 96;
-std::vector<ContextMenuItemEfl> ContextMenuControllerEfl::_context_menu_listdata;
-
ContextMenuControllerEfl::ContextMenuControllerEfl(EWebView* wv,
WebContents& web_contents)
- : webview_(wv), web_contents_(web_contents), weak_ptr_factory_(this) {
- native_view_ =
- static_cast<WebContentsImpl*>(&web_contents_)->GetEflNativeView();
-}
+ : ContextMenuControllerBase(web_contents),
+ webview_(wv),
+ weak_ptr_factory_(this) {}
ContextMenuControllerEfl::~ContextMenuControllerEfl() {
for (std::set<download::DownloadItem*>::iterator it =
it != disk_download_items_.end(); ++it) {
(*it)->RemoveObserver(this);
}
- _context_menu_listdata.clear();
- DeletePopup();
+}
+
+// ContextMenuControllerBase override methods
+Evas_Object* ContextMenuControllerEfl::evas_object() {
+ return webview_->evas_object();
+}
+const char* ContextMenuControllerEfl::GetSelectedText() {
+ return webview_->CacheSelectedText();
}
bool ContextMenuControllerEfl::PopulateAndShowContextMenu(const ContextMenuParams ¶ms) {
return ShowContextMenu();
}
-void ContextMenuControllerEfl::Move(int x, int y) {
- if (popup_ && is_text_selection_)
- evas_object_move(popup_, x, y);
-}
-
void ContextMenuControllerEfl::AddItemToProposedList(Ewk_Context_Menu_Item_Type item,
Ewk_Context_Menu_Item_Tag option,
const std::string& title,
}
}
-bool ContextMenuControllerEfl::CreateContextMenu(
- const ContextMenuParams& params) {
- is_text_selection_ = false;
- Eina_List* ittr;
- void* data;
- EINA_LIST_FOREACH(menu_items_, ittr, data) {
- _Ewk_Context_Menu_Item* item = static_cast<_Ewk_Context_Menu_Item*> (data);
- ContextMenuItemEfl* context_item = item->GetMenuItem();
- switch (context_item->GetContextMenuOption()) {
- case EWK_CONTEXT_MENU_ITEM_TAG_COPY:
- case EWK_CONTEXT_MENU_ITEM_TAG_SELECT_ALL:
- case EWK_CONTEXT_MENU_ITEM_TAG_SELECT_WORD:
- case EWK_CONTEXT_MENU_ITEM_TAG_PASTE:
- is_text_selection_ = true;
- break;
- default:
- break;
- }
- }
-
- if (is_text_selection_) {
- popup_ = elm_ctxpopup_add(native_view_);
-#if BUILDFLAG(IS_TIZEN)
- elm_ctxpopup_horizontal_set(popup_, EINA_TRUE);
-#endif
- elm_object_tree_focus_allow_set(popup_, false);
- } else {
- top_widget_ = elm_object_top_widget_get(
- elm_object_parent_widget_get(webview_->evas_object()));
- evas_object_data_set(top_widget_, "ContextMenuContollerEfl", this);
- popup_ = elm_popup_add(top_widget_);
-
- if (IsMobileProfile())
- elm_popup_align_set(popup_, ELM_NOTIFY_ALIGN_FILL, 1.0);
- else
- elm_popup_align_set(popup_, 0.5, 0.5);
- }
-
- if (!popup_)
- return false;
-
- if (!IsMobileProfile())
- evas_object_smart_member_add(popup_, webview_->evas_object());
-
- elm_object_tree_focus_allow_set(popup_, EINA_FALSE);
-
- evas_object_data_set(popup_, "ContextMenuContollerEfl", this);
-
- _context_menu_listdata.clear();
- if (is_text_selection_) {
- EINA_LIST_FOREACH(menu_items_, ittr, data) {
- _Ewk_Context_Menu_Item* item = static_cast<_Ewk_Context_Menu_Item*> (data);
- ContextMenuItemEfl* context_item = item->GetMenuItem();
- Elm_Object_Item* appended_item = 0;
-
- if (!context_item->Title().empty()) {
- appended_item = elm_ctxpopup_item_append(popup_,
- context_item->Title().c_str(), 0, ContextMenuItemSelectedCallback,
- context_item);
- } else {
- appended_item = elm_ctxpopup_item_append(popup_, 0, 0,
- ContextMenuItemSelectedCallback,
- context_item);
- }
-
- if (appended_item)
- _context_menu_listdata.push_back(*context_item);
- }
-#if BUILDFLAG(IS_TIZEN)
- // Workaround
- // Need to set "copypaste" style, to let moving handles
- // when ctxpopup is visible
- // http://107.108.218.239/bugzilla/show_bug.cgi?id=11613
- elm_object_style_set(popup_, "copypaste");
-#endif
-
- evas_object_size_hint_weight_set(popup_, EVAS_HINT_EXPAND,
- EVAS_HINT_EXPAND);
- evas_object_size_hint_max_set(popup_, -1, _popup_item_height);
- evas_object_size_hint_min_set(popup_, 0, _popup_item_height);
- } else {
- std::string selected_link(params_.link_url.spec());
- if (!selected_link.empty()) {
- if (base::StartsWith(selected_link, std::string("mailto:"),
- base::CompareCase::INSENSITIVE_ASCII) ||
- base::StartsWith(selected_link, std::string("tel:"),
- base::CompareCase::INSENSITIVE_ASCII)) {
- size_t current_pos = 0;
- size_t next_delimiter = 0;
- // Remove the First part and Extract actual URL or title
- // (mailto:abc@d.com?id=345 ==> abc@d.com?id=345)
- if ((next_delimiter = selected_link.find(":", current_pos)) !=
- std::string::npos) {
- current_pos = next_delimiter + 1;
- }
-
- std::string last_part = selected_link.substr(current_pos);
- std::string core_part = selected_link.substr(current_pos);
- current_pos = 0;
- next_delimiter = 0;
- // Trim the core by removing ? at the end (abc@d.com?id=345 ==>
- // abc@d.com)
- if ((next_delimiter = core_part.find("?", current_pos)) !=
- std::string::npos) {
- last_part =
- core_part.substr(current_pos, next_delimiter - current_pos);
- }
- } else {
- elm_object_part_text_set(popup_, "title,text", selected_link.c_str());
- }
- } else {
- std::string selected_image(params_.src_url.spec());
- if (!selected_image.empty())
- elm_object_part_text_set(popup_, "title,text", selected_image.c_str());
- }
-
- evas_object_size_hint_weight_set(popup_, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
-
- list_ = elm_list_add(popup_);
- elm_list_mode_set(list_, ELM_LIST_EXPAND);
- evas_object_data_set(list_, "ContextMenuContollerEfl", this);
-
- Eina_List* ittr;
- void* data;
- EINA_LIST_FOREACH(menu_items_, ittr, data) {
- _Ewk_Context_Menu_Item* item = static_cast<_Ewk_Context_Menu_Item*> (data);
- ContextMenuItemEfl* context_item = item->GetMenuItem();
- if (!context_item->Title().empty()) {
- Elm_Object_Item* appended_item = elm_list_item_append(
- list_, context_item->Title().c_str(), NULL, NULL,
- ContextMenuItemSelectedCallback, context_item);
-
- if (appended_item)
- _context_menu_listdata.push_back(*context_item);
- }
- }
-
- ContextMenuPopupListResize();
-
- evas_object_show(list_);
- elm_object_content_set(popup_, list_);
- evas_object_event_callback_add(popup_, EVAS_CALLBACK_RESIZE,
- ContextMenuPopupResize, this);
- }
-
- if (_context_menu_listdata.empty()) {
- DeletePopup();
- return false;
- }
- return true;
-}
-
-void ContextMenuControllerEfl::ContextMenuHWBackKey(void* data, Evas_Object* obj,
- void* event_info) {
- auto menu_controller = static_cast<ContextMenuControllerEfl*>(data);
- if (menu_controller) {
- auto selection_controller =
- menu_controller->webview_->GetSelectionController();
-
- if (selection_controller)
- selection_controller->ToggleCaretAfterSelection();
-
- menu_controller->HideContextMenu();
- evas_object_data_del(obj, "ContextEfl");
- }
-}
-
-// static
-Eina_Bool ContextMenuControllerEfl::RestoreTimerCallback(void* data) {
- auto* menu_controller = static_cast<ContextMenuControllerEfl*>(data);
- if (!menu_controller)
- return ECORE_CALLBACK_CANCEL;
-
- auto selection_controller =
- menu_controller->webview_->GetSelectionController();
-
- if (menu_controller->popup_ && selection_controller &&
- selection_controller->GetSelectionStatus() &&
- !selection_controller->IsCaretMode()) {
- evas_object_show(menu_controller->popup_);
- }
-
- menu_controller->restore_timer_ = nullptr;
-
- return ECORE_CALLBACK_CANCEL;
-}
-
-void ContextMenuControllerEfl::ContextMenuCancelCallback(void* data, Evas_Object* obj,
- void* event_info) {
- ContextMenuControllerEfl* menu_controller =
- static_cast<ContextMenuControllerEfl*>(
- evas_object_data_get(obj, "ContextMenuContollerEfl"));
- if (!menu_controller)
- return;
-
- RenderWidgetHostViewAura* rwhva = static_cast<RenderWidgetHostViewAura*>(
- menu_controller->web_contents_.GetRenderWidgetHostView());
- if (!rwhva)
- return;
-
- // context_menu is dismissed when we touch outside of popup.
- // It is policy of elm_ctxpopup by EFL team.
- // But according to wcs TC(21~23) context_menu should be displayed,
- // when touchevent is consumed. So we should show context_menu again when
- // touchevent is consumed.
- if (rwhva->offscreen_helper()->IsTouchstartConsumed() ||
- rwhva->offscreen_helper()->IsTouchendConsumed()) {
- evas_object_show(menu_controller->popup_);
- return;
- }
-
- // TODO: If |elm_ctxpopup_auto_hide_disabled_set| is works properly,
- // We should remove this timer.
- // Bug: http://suprem.sec.samsung.net/jira/browse/TNEXT-67
- menu_controller->restore_timer_ =
- ecore_timer_add(kRestoreTime, RestoreTimerCallback, menu_controller);
-}
-
-void ContextMenuControllerEfl::ContextMenuItemSelectedCallback(void* data,
- Evas_Object* obj, void* event_info) {
- Evas_Object* pop_up = obj;
- ContextMenuControllerEfl* menu_controller =
- static_cast<ContextMenuControllerEfl*>
- (evas_object_data_get(pop_up, "ContextMenuContollerEfl"));
-
- if (menu_controller) {
- ContextMenuItemEfl* selected_menu_item = static_cast<ContextMenuItemEfl*>(data);
- if (selected_menu_item)
- menu_controller->MenuItemSelected(selected_menu_item);
- }
-}
-
-void ContextMenuControllerEfl::RequestSelectionRect() const {
- auto rwhva = static_cast<RenderWidgetHostViewAura*>(
- web_contents_.GetRenderWidgetHostView());
- CHECK(rwhva);
- rwhva->host()->RequestSelectionRect();
-}
-
-gfx::Point ContextMenuControllerEfl::CalculateSelectionMenuPosition(
- const gfx::Rect& selection_rect) {
- auto* selection_controller = webview_->GetSelectionController();
- if (!selection_controller)
- return gfx::Point();
-
- auto visible_viewport_rect = selection_controller->GetVisibleViewportRect();
- auto forbidden_rect =
- selection_controller->GetForbiddenRegionRect(selection_rect);
- gfx::Point position;
- // Selection menu should always be placed at the centre of visible selection
- // area horizontally.
- position.set_x(forbidden_rect.CenterPoint().x());
-
- if (forbidden_rect.y() > visible_viewport_rect.y() + kMenuHeight) {
- // If possible, selection menu should always be placed above forbidden
- // region.
- position.set_y(forbidden_rect.y());
- } else if (forbidden_rect.bottom() + kMenuHeight <
- visible_viewport_rect.bottom()) {
- // If there is no sufficient space above, we're trying to place selection
- // menu below forbidden region.
- position.set_y(forbidden_rect.bottom() + kMenuHeight);
- } else {
- // If there is no sufficient space above and below, selection menu will be
- // shown at the centre of visible selection area vertically.
- position.set_y(forbidden_rect.CenterPoint().y());
- }
-
- return position;
-}
-
-void ContextMenuControllerEfl::OnSelectionRectReceived(
- gfx::Rect selection_rect) {
- auto rwhva = static_cast<RenderWidgetHostViewAura*>(
- web_contents_.GetRenderWidgetHostView());
- auto controller = webview_->GetSelectionController();
-
- if (IsMobileProfile() && (context_menu_status_ != INPROGRESS))
- return;
- if (!popup_ || !rwhva || !controller)
- return;
-
- float device_scale =
- display::Screen::GetScreen()->GetPrimaryDisplay().device_scale_factor();
- gfx::Rect selection_rect_dip = gfx::ToEnclosingRect(
- ConvertRectToPixels(gfx::Rect(selection_rect), device_scale));
-
- // Consider a webview offset.
- selection_rect_dip.Offset(
- rwhva->offscreen_helper()->GetViewBoundsInPix().OffsetFromOrigin());
-
- auto visible_viewport_rect = controller->GetVisibleViewportRect();
-
- // In case of the caret mode selection_rect is empty
- if (!webview_->GetSelectionController()->IsCaretMode() &&
- gfx::IntersectRects(visible_viewport_rect, selection_rect_dip)
- .IsEmpty()) {
- return;
- }
-
- gfx::Point selection_menu_position =
- CalculateSelectionMenuPosition(selection_rect_dip);
- if (!visible_viewport_rect.Contains(selection_menu_position))
- return;
-
- evas_object_smart_callback_add(popup_, "dismissed", ContextMenuCancelCallback,
- this);
-
- if (IsMobileProfile())
- elm_ctxpopup_auto_hide_disabled_set(popup_, EINA_TRUE);
-
-#if BUILDFLAG(IS_TIZEN)
- eext_object_event_callback_add(popup_, EEXT_CALLBACK_BACK,
- ContextMenuHWBackKey, this);
-#endif
- evas_object_move(popup_, selection_menu_position.x(),
- selection_menu_position.y());
-
- controller->ContextMenuStatusVisible();
-
- evas_object_show(popup_);
- evas_object_raise(popup_);
- if (IsMobileProfile())
- context_menu_status_ = VISIBLE;
-}
-
-bool ContextMenuControllerEfl::ShowContextMenu() {
- if (!popup_)
- return false;
-
- if (IsMobileProfile())
- context_menu_status_ = INPROGRESS;
-
- if (is_text_selection_) {
- // Selection menu will be shown in OnSelectionRectReceived after receiving
- // selection rectangle form the renderer.
- RequestSelectionRect();
- } else {
- evas_object_smart_callback_add(popup_, "block,clicked",
- BlockClickedCallback, this);
-
-#if BUILDFLAG(IS_TIZEN)
- eext_object_event_callback_add(popup_, EEXT_CALLBACK_BACK, ContextMenuHWBackKey, this);
- eext_object_event_callback_add(popup_, EEXT_CALLBACK_MORE,
- ContextMenuHWBackKey, this);
-#endif
- evas_object_show(popup_);
- evas_object_raise(popup_);
- if (IsMobileProfile())
- context_menu_status_ = VISIBLE;
- }
- return true;
-}
-
-void ContextMenuControllerEfl::HideSelectionHandle() {
- SelectionControllerEfl* controller = webview_->GetSelectionController();
- if (controller)
- controller->HideHandles();
-}
-
-void ContextMenuControllerEfl::ClearSelection() {
- auto controller = webview_->GetSelectionController();
- if (controller)
- controller->ClearSelection();
-}
-
-void ContextMenuControllerEfl::RequestShowSelectionHandleAndContextMenu(
- bool trigger_selection_change) {
- SelectionControllerEfl* controller = webview_->GetSelectionController();
- if (controller) {
- controller->SetSelectionStatus(true);
- controller->SetWaitsForRendererSelectionChanges(
- SelectionControllerEfl::Reason::RequestedByContextMenu);
- if (trigger_selection_change)
- controller->TriggerOnSelectionChange();
- }
-}
-
void ContextMenuControllerEfl::OnClipboardDownload(
download::DownloadItem* item,
download::DownloadInterruptReason interrupt_reason) {
}
#if BUILDFLAG(IS_TIZEN)
-static void destroy_app_handle(app_control_h* handle) {
- std::ignore = app_control_destroy(*handle);
-}
-
void ContextMenuControllerEfl::LaunchBrowserWithWebSearch(
const std::string& text) {
app_control_h app_control;
app_control_destroy(app_control);
}
-
-void ContextMenuControllerEfl::LaunchShareApp(const std::string& text) {
- app_control_h handle = nullptr;
- int error_code = app_control_create(&handle);
- if (error_code < 0 || !handle) {
- LOG(ERROR) << __PRETTY_FUNCTION__
- << " : Failed to create share service. Error code: "
- << error_code;
- return;
- }
-
- std::unique_ptr<app_control_h, decltype(&destroy_app_handle)> handle_ptr(
- &handle, destroy_app_handle);
-
- error_code =
- app_control_set_operation(handle, APP_CONTROL_OPERATION_SHARE_TEXT);
- if (error_code < 0) {
- LOG(ERROR) << __PRETTY_FUNCTION__
- << ": Failed to set share text operation. Error code: "
- << error_code;
- return;
- }
-
- error_code =
- app_control_add_extra_data(handle, APP_CONTROL_DATA_TEXT, text.c_str());
- if (error_code < 0) {
- LOG(ERROR) << __PRETTY_FUNCTION__
- << ": Failed to add data for share application. Error code: "
- << error_code;
- return;
- }
-
- error_code = app_control_send_launch_request(handle, nullptr, nullptr);
- if (error_code < 0) {
- LOG(ERROR) << __PRETTY_FUNCTION__
- << ": Failed to send launch request for share application. "
- << "Error code: " << error_code;
- return;
- }
-}
#endif
-void ContextMenuControllerEfl::ContextMenuPopupResize(void* data,
- Evas* e,
- Evas_Object* obj,
- void* event_info) {
- auto thiz = static_cast<ContextMenuControllerEfl*>(data);
- if (thiz)
- thiz->ContextMenuPopupListResize();
-}
-
-void ContextMenuControllerEfl::BlockClickedCallback(void* data, Evas_Object*, void*)
-{
- ContextMenuControllerEfl* menu_controller = static_cast<ContextMenuControllerEfl*>(data);
-
- if (!menu_controller)
- return;
-
- menu_controller->HideContextMenu();
-}
-
-void ContextMenuControllerEfl::ContextMenuPopupListResize() {
- if (!IsMobileProfile())
- return;
-
- int orientation = webview_->GetOrientation();
- if ((orientation == 90 || orientation == 270) &&
- _context_menu_listdata.size() > 3) {
- evas_object_size_hint_min_set(list_, 0, kMinHeightHorizontal);
- } else if ((orientation == 0 || orientation == 180) &&
- _context_menu_listdata.size() > 7) {
- evas_object_size_hint_min_set(list_, 0, kMinHeightVertical);
- } else {
- evas_object_size_hint_min_set(
- list_, 0, _context_menu_listdata.size() * _popup_item_height);
- }
-
- evas_object_show(list_);
-}
-
void ContextMenuControllerEfl::CustomMenuItemSelected(ContextMenuItemEfl* menu_item) {
_Ewk_Context_Menu_Item item(new ContextMenuItemEfl(menu_item->GetContextMenuOptionType(),
menu_item->GetContextMenuOption(),
void ContextMenuControllerEfl::MenuItemSelected(ContextMenuItemEfl* menu_item)
{
- if (!menu_item)
- return;
-
- if (!webview_)
+ if (!menu_item || !webview_)
return;
HideContextMenu();
}
}
-void ContextMenuControllerEfl::HideContextMenu() {
- if (IsMobileProfile() &&
- (context_menu_status_ == HIDDEN || context_menu_status_ == NONE))
- return;
-
- if (is_text_selection_) {
- SelectionControllerEfl* controller = webview_->GetSelectionController();
- if (controller)
- controller->ContextMenuStatusHidden();
- }
-
- if (popup_) {
- evas_object_event_callback_del(popup_, EVAS_CALLBACK_RESIZE,
- ContextMenuPopupResize);
- evas_object_del(popup_);
- popup_ = nullptr;
- }
-
- if (restore_timer_) {
- ecore_timer_del(restore_timer_);
- restore_timer_ = nullptr;
- }
-
- if (IsMobileProfile()) {
- context_menu_status_ = HIDDEN;
- } else if (menu_items_) {
- void* data;
- EINA_LIST_FREE(menu_items_, data) {
- _Ewk_Context_Menu_Item* item = static_cast<_Ewk_Context_Menu_Item*>(data);
- delete item;
- }
- menu_items_ = nullptr;
- }
-}
-
void ContextMenuControllerEfl::Resize(const gfx::Rect& webview_rect) {
if (save_fail_dialog_)
save_fail_dialog_->SetPopupSize(webview_rect.width(),
file_saved_dialog_->SetPopupSize(webview_rect.width(),
webview_rect.height());
- if (!popup_)
- return;
-
- if (IsMobileProfile() && context_menu_status_ != VISIBLE)
- return;
-
- if (is_text_selection_) {
- RequestSelectionRect();
- } else {
- evas_object_resize(popup_, webview_rect.width(), webview_rect.height());
- }
-}
-
-void ContextMenuControllerEfl::DeletePopup() {
- if (top_widget_)
- evas_object_data_set(top_widget_, "ContextMenuContollerEfl", 0);
-
- if (is_text_selection_) {
- SelectionControllerEfl* controller = webview_->GetSelectionController();
- if (controller)
- controller->ContextMenuStatusHidden();
- }
-
- if (popup_) {
- evas_object_data_set(popup_, "ContextMenuContollerEfl", 0);
- if (!IsMobileProfile())
- evas_object_smart_member_del(popup_);
- evas_object_del(popup_);
- popup_ = nullptr;
- list_ = nullptr;
- }
-
- if (menu_items_) {
- void* data;
- EINA_LIST_FREE(menu_items_, data) {
- _Ewk_Context_Menu_Item *item = static_cast<_Ewk_Context_Menu_Item*> (data);
- delete item;
- }
- menu_items_ = nullptr;
- }
- if (IsMobileProfile())
- context_menu_status_ = NONE;
+ ContextMenuControllerBase::Resize(webview_rect);
}
}
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef context_menu_controller_h
-#define context_menu_controller_h
+#ifndef context_menu_controller_efl_h
+#define context_menu_controller_efl_h
+
+#include "content/browser/context_menu/context_menu_controller_base.h"
-#include <Evas.h>
#include <set>
#include "base/memory/weak_ptr.h"
#include "browser/javascript_modal_dialog_efl.h"
#include "components/download/public/common/download_item.h"
#include "components/download/public/common/download_url_parameters.h"
-#include "content/public/browser/context_menu_params.h"
-#include "content/public/browser/render_view_host.h"
-#include "content/public/browser/web_contents.h"
-#include "public/ewk_context_menu_internal.h"
+#include "ui/base/window_open_disposition.h"
class EWebView;
-namespace gfx {
-class Rect;
-}
-
namespace content {
-class ContextMenuItemEfl {
+class ContextMenuControllerEfl : public ContextMenuControllerBase,
+ public download::DownloadItem::Observer {
public:
- ContextMenuItemEfl(Ewk_Context_Menu_Item_Type item,
- Ewk_Context_Menu_Item_Tag option,
- const std::string& title,
- const std::string& image_url = std::string(),
- const std::string& link_url = std::string(),
- const std::string& icon_path = std::string())
- : menu_type_(item)
- , menu_option_(option)
- , title_(title)
- , is_enabled_(true)
- , image_url_(image_url)
- , link_url_(link_url)
- , icon_path_(icon_path) {
- }
-
- ~ContextMenuItemEfl() { }
-
- const std::string& Title() const { return title_; }
- void SetTitle(const std::string& title) { title_ = title; }
-
- bool IsEnabled() const { return is_enabled_; }
- void SetEnabled(bool status) { is_enabled_ = status; }
- Ewk_Context_Menu_Item_Tag GetContextMenuOption() const { return menu_option_; }
- Ewk_Context_Menu_Item_Type GetContextMenuOptionType() const { return menu_type_; }
- const std::string& LinkURL() const { return link_url_; }
- const std::string& ImageURL() const { return image_url_; }
- const std::string& IconPath() const { return icon_path_; }
-
- private:
- Ewk_Context_Menu_Item_Type menu_type_;
- Ewk_Context_Menu_Item_Tag menu_option_;
- std::string title_;
- bool is_enabled_;
- std::string image_url_;
- std::string link_url_;
- std::string icon_path_;
-};
-
-class ContextMenuControllerEfl : public download::DownloadItem::Observer {
- public:
- static void ContextMenuCancelCallback(void* data, Evas_Object* obj, void* event_info);
- static void ContextMenuItemSelectedCallback(void* data, Evas_Object* obj, void* event_info);
- static void ContextMenuHWBackKey(void* data, Evas_Object* obj, void* event_info);
-
ContextMenuControllerEfl(EWebView* wv, WebContents& web_contents);
~ContextMenuControllerEfl();
+ ContextMenuControllerEfl(const ContextMenuControllerEfl&) = delete;
+ ContextMenuControllerEfl& operator=(const ContextMenuControllerEfl&) = delete;
+
bool PopulateAndShowContextMenu(const ContextMenuParams& params);
- void Move(int x, int y);
- void MenuItemSelected(ContextMenuItemEfl* menu_item);
- void HideContextMenu();
+ void MenuItemSelected(ContextMenuItemEfl* menu_item) override;
gfx::Point GetContextMenuShowPos() const { return context_menu_show_pos_; };
- void Resize(const gfx::Rect& webview_rect);
-
- void RequestSelectionRect() const;
- void OnSelectionRectReceived(gfx::Rect selection_rect);
- gfx::Point CalculateSelectionMenuPosition(const gfx::Rect& selection_rect);
+ void Resize(const gfx::Rect& webview_rect) override;
private:
- static void ContextMenuPopupResize(void* data,
- Evas* e,
- Evas_Object* obj,
- void* event_info);
- enum ContextMenuStatusTag { NONE = 0, HIDDEN, INPROGRESS, VISIBLE };
- static void BlockClickedCallback(void*, Evas_Object*, void*);
- void ContextMenuPopupListResize();
+ // ContextMenuControllerBase
+ Evas_Object* evas_object() override;
+ const char* GetSelectedText() override;
+
void CustomMenuItemSelected(ContextMenuItemEfl*);
void GetProposedContextMenu();
- bool CreateContextMenu(const ContextMenuParams& params);
- bool ShowContextMenu();
void AddItemToProposedList(Ewk_Context_Menu_Item_Type item,
Ewk_Context_Menu_Item_Tag option,
const std::string& title,
const std::string& image_url = std::string(),
const std::string& link_url = std::string(),
const std::string& icon_path = std::string());
- void HideSelectionHandle();
- void ClearSelection();
- void RequestShowSelectionHandleAndContextMenu(
- bool trigger_selection_change = false);
virtual void OnDownloadUpdated(download::DownloadItem* download) override;
void OnClipboardDownload(download::DownloadItem* item,
download::DownloadInterruptReason interrupt_reason);
void OpenURL(const GURL url, const WindowOpenDisposition disposition);
#if BUILDFLAG(IS_TIZEN)
void LaunchBrowserWithWebSearch(const std::string& text);
- void LaunchShareApp(const std::string& text);
#endif
- void DeletePopup();
-
- static Eina_Bool RestoreTimerCallback(void* data);
- static std::vector<ContextMenuItemEfl> _context_menu_listdata;
- static int _popup_item_height;
- static bool _context_menu_resized;
EWebView* webview_;
- Evas_Object* native_view_;
- Evas_Object* top_widget_ = nullptr;
- Evas_Object* popup_ = nullptr;
- Evas_Object* list_ = nullptr;
- Eina_List* menu_items_ = nullptr;
- ContextMenuParams params_;
- WebContents& web_contents_;
gfx::Point context_menu_show_pos_;
- bool is_text_selection_ = false;
std::set<download::DownloadItem*> clipboard_download_items_;
std::set<download::DownloadItem*> disk_download_items_;
std::unique_ptr<JavaScriptModalDialogEfl> file_saved_dialog_;
std::unique_ptr<JavaScriptModalDialogEfl> save_fail_dialog_;
- Ecore_Timer* restore_timer_ = nullptr;
- ContextMenuStatusTag context_menu_status_ = NONE;
base::WeakPtrFactory<ContextMenuControllerEfl> weak_ptr_factory_;
};
} // namespace
-#endif // context_menu_controller_h
+#endif // context_menu_controller_efl_h
--- /dev/null
+// Copyright 2022 Samsung Electronics. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef ewk_context_menu_item_private_h
+#define ewk_context_menu_item_private_h
+
+namespace content {
+class ContextMenuItemEfl;
+}
+
+class _Ewk_Context_Menu_Item {
+ public:
+ _Ewk_Context_Menu_Item(content::ContextMenuItemEfl* menu_item)
+ : menu_item_(menu_item) {}
+
+ ~_Ewk_Context_Menu_Item() { delete menu_item_; }
+
+ _Ewk_Context_Menu_Item(const _Ewk_Context_Menu_Item&) = delete;
+ _Ewk_Context_Menu_Item& operator=(const _Ewk_Context_Menu_Item&) = delete;
+
+ content::ContextMenuItemEfl* GetMenuItem() const { return menu_item_; }
+
+ private:
+ content::ContextMenuItemEfl* menu_item_;
+};
+
+#endif // ewk_context_menu_private_h
#include <stdio.h>
#include "context_menu_controller_efl.h"
-
-class _Ewk_Context_Menu_Item {
- public:
- _Ewk_Context_Menu_Item(content::ContextMenuItemEfl* menu_item)
- : menu_item_(menu_item) {
- }
-
- ~_Ewk_Context_Menu_Item() {
- delete menu_item_;
- }
-
- content::ContextMenuItemEfl* GetMenuItem() const {
- return menu_item_;
- }
- private:
- content::ContextMenuItemEfl* menu_item_;
-};
-
+#include "ewk_context_menu_item_private.h"
// Wrapper for context_menu_controller items
class _Ewk_Context_Menu {