From eeec861d3a8e2e9d7f666124092d21324507c652 Mon Sep 17 00:00:00 2001 From: Ayush Kumar Date: Mon, 27 Feb 2023 14:04:15 +0530 Subject: [PATCH] [M108 Migration] Segregate ContextMenuControllerEfl into a base class 1. Split ContextMenuControllerEfl into two parts, one of which will be recycled by WRTJS as well 2. Removed redundant and extra headers and cleaned up the code a bit 3. Modified/Removed functions from ContextMenuController which are no longer needed in m108 Reference: 1. https://review.tizen.org/gerrit/282571 2. https://review.tizen.org/gerrit/284343 Change-Id: Ifc9730734bea5a0bf530b553bd00a90e0f39f136 Signed-off-by: Ayush Kumar --- .../browser/web_contents/web_contents_view_aura.h | 8 + .../chromium_impl/content/browser/browser_efl.gni | 2 + .../context_menu/context_menu_controller_base.cc | 641 +++++++++++++++++++++ .../context_menu/context_menu_controller_base.h | 145 +++++ tizen_src/ewk/efl_integration/BUILD.gn | 1 + .../efl_integration/context_menu_controller_efl.cc | 598 +------------------ .../efl_integration/context_menu_controller_efl.h | 112 +--- .../private/ewk_context_menu_item_private.h | 28 + .../private/ewk_context_menu_private.h | 19 +- 9 files changed, 859 insertions(+), 695 deletions(-) create mode 100644 tizen_src/chromium_impl/content/browser/context_menu/context_menu_controller_base.cc create mode 100644 tizen_src/chromium_impl/content/browser/context_menu/context_menu_controller_base.h create mode 100644 tizen_src/ewk/efl_integration/private/ewk_context_menu_item_private.h diff --git a/content/browser/web_contents/web_contents_view_aura.h b/content/browser/web_contents/web_contents_view_aura.h index db0945e..7e4abc8 100644 --- a/content/browser/web_contents/web_contents_view_aura.h +++ b/content/browser/web_contents/web_contents_view_aura.h @@ -86,6 +86,10 @@ class CONTENT_EXPORT WebContentsViewAura } #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. @@ -412,6 +416,10 @@ class CONTENT_EXPORT WebContentsViewAura std::unique_ptr wcva_helper_; #endif +#if BUILDFLAG(IS_TIZEN) + int orientation_ = 0; +#endif + base::WeakPtrFactory weak_ptr_factory_{this}; }; diff --git a/tizen_src/chromium_impl/content/browser/browser_efl.gni b/tizen_src/chromium_impl/content/browser/browser_efl.gni index 0830e10..03a1545 100644 --- a/tizen_src/chromium_impl/content/browser/browser_efl.gni +++ b/tizen_src/chromium_impl/content/browser/browser_efl.gni @@ -75,6 +75,8 @@ if (enable_wrt_js) { # 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", diff --git a/tizen_src/chromium_impl/content/browser/context_menu/context_menu_controller_base.cc b/tizen_src/chromium_impl/content/browser/context_menu/context_menu_controller_base.cc new file mode 100644 index 0000000..a740b9c --- /dev/null +++ b/tizen_src/chromium_impl/content/browser/context_menu/context_menu_controller_base.cc @@ -0,0 +1,641 @@ +// 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 + +#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 +#include +#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 + ContextMenuControllerBase::_context_menu_listdata; + +ContextMenuControllerBase::ContextMenuControllerBase(WebContents& web_contents) + : web_contents_(web_contents) { + native_view_ = + static_cast(&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(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(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( + 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( + evas_object_data_get(pop_up, "ContextMenuContollerEfl")); + + if (menu_controller) { + ContextMenuItemEfl* selected_menu_item = + static_cast(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 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(data); + if (thiz) + thiz->ContextMenuPopupListResize(); +} + +// static +void ContextMenuControllerBase::BlockClickedCallback(void* data, + Evas_Object*, + void*) { + ContextMenuControllerBase* menu_controller = + static_cast(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( + web_contents_.GetRenderWidgetHostView()); +} + +WebContentsViewAura* ContextMenuControllerBase::GetWebContentsViewAura() const { + WebContentsImpl* wc = static_cast(&web_contents_); + return static_cast(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( + 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 diff --git a/tizen_src/chromium_impl/content/browser/context_menu/context_menu_controller_base.h b/tizen_src/chromium_impl/content/browser/context_menu/context_menu_controller_base.h new file mode 100644 index 0000000..b8d427e --- /dev/null +++ b/tizen_src/chromium_impl/content/browser/context_menu/context_menu_controller_base.h @@ -0,0 +1,145 @@ +// 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 +#include + +#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 _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 diff --git a/tizen_src/ewk/efl_integration/BUILD.gn b/tizen_src/ewk/efl_integration/BUILD.gn index eacbd7d..33fac56 100755 --- a/tizen_src/ewk/efl_integration/BUILD.gn +++ b/tizen_src/ewk/efl_integration/BUILD.gn @@ -392,6 +392,7 @@ shared_library("chromium-ewk") { "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", diff --git a/tizen_src/ewk/efl_integration/context_menu_controller_efl.cc b/tizen_src/ewk/efl_integration/context_menu_controller_efl.cc index 838a328..b8e0ae2 100644 --- a/tizen_src/ewk/efl_integration/context_menu_controller_efl.cc +++ b/tizen_src/ewk/efl_integration/context_menu_controller_efl.cc @@ -2,9 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include -#include -#include +#include "context_menu_controller_efl.h" #include "base/files/file_path.h" #include "base/files/file_util.h" @@ -12,67 +10,41 @@ #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 -#include -#include #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 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(&web_contents_)->GetEflNativeView(); -} + : ContextMenuControllerBase(web_contents), + webview_(wv), + weak_ptr_factory_(this) {} ContextMenuControllerEfl::~ContextMenuControllerEfl() { for (std::set::iterator it = @@ -85,8 +57,14 @@ ContextMenuControllerEfl::~ContextMenuControllerEfl() { 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) { @@ -119,11 +97,6 @@ bool ContextMenuControllerEfl::PopulateAndShowContextMenu(const ContextMenuParam 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, @@ -302,384 +275,6 @@ void ContextMenuControllerEfl::GetProposedContextMenu() { } } -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(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(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( - evas_object_data_get(obj, "ContextMenuContollerEfl")); - if (!menu_controller) - return; - - RenderWidgetHostViewAura* rwhva = static_cast( - 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 - (evas_object_data_get(pop_up, "ContextMenuContollerEfl")); - - if (menu_controller) { - ContextMenuItemEfl* selected_menu_item = static_cast(data); - if (selected_menu_item) - menu_controller->MenuItemSelected(selected_menu_item); - } -} - -void ContextMenuControllerEfl::RequestSelectionRect() const { - auto rwhva = static_cast( - 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( - 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) { @@ -813,10 +408,6 @@ void ContextMenuControllerEfl::OpenURL( } #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; @@ -834,86 +425,8 @@ void ContextMenuControllerEfl::LaunchBrowserWithWebSearch( 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 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(data); - if (thiz) - thiz->ContextMenuPopupListResize(); -} - -void ContextMenuControllerEfl::BlockClickedCallback(void* data, Evas_Object*, void*) -{ - ContextMenuControllerEfl* menu_controller = static_cast(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(), @@ -926,10 +439,7 @@ void ContextMenuControllerEfl::CustomMenuItemSelected(ContextMenuItemEfl* menu_i void ContextMenuControllerEfl::MenuItemSelected(ContextMenuItemEfl* menu_item) { - if (!menu_item) - return; - - if (!webview_) + if (!menu_item || !webview_) return; HideContextMenu(); @@ -1135,41 +645,6 @@ void ContextMenuControllerEfl::MenuItemSelected(ContextMenuItemEfl* menu_item) } } -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(), @@ -1178,47 +653,6 @@ void ContextMenuControllerEfl::Resize(const gfx::Rect& webview_rect) { 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); } } diff --git a/tizen_src/ewk/efl_integration/context_menu_controller_efl.h b/tizen_src/ewk/efl_integration/context_menu_controller_efl.h index 1c898d2..cab9536 100644 --- a/tizen_src/ewk/efl_integration/context_menu_controller_efl.h +++ b/tizen_src/ewk/efl_integration/context_menu_controller_efl.h @@ -2,111 +2,50 @@ // 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 #include #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); @@ -121,34 +60,17 @@ class ContextMenuControllerEfl : public download::DownloadItem::Observer { 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 _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 clipboard_download_items_; std::set disk_download_items_; std::unique_ptr file_saved_dialog_; std::unique_ptr save_fail_dialog_; - Ecore_Timer* restore_timer_ = nullptr; - ContextMenuStatusTag context_menu_status_ = NONE; base::WeakPtrFactory weak_ptr_factory_; }; } // namespace -#endif // context_menu_controller_h +#endif // context_menu_controller_efl_h diff --git a/tizen_src/ewk/efl_integration/private/ewk_context_menu_item_private.h b/tizen_src/ewk/efl_integration/private/ewk_context_menu_item_private.h new file mode 100644 index 0000000..f2f548a --- /dev/null +++ b/tizen_src/ewk/efl_integration/private/ewk_context_menu_item_private.h @@ -0,0 +1,28 @@ +// 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 diff --git a/tizen_src/ewk/efl_integration/private/ewk_context_menu_private.h b/tizen_src/ewk/efl_integration/private/ewk_context_menu_private.h index ed5778b3..216b29d 100644 --- a/tizen_src/ewk/efl_integration/private/ewk_context_menu_private.h +++ b/tizen_src/ewk/efl_integration/private/ewk_context_menu_private.h @@ -9,24 +9,7 @@ #include #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 { -- 2.7.4