#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_impl_efl.h"
+#include "content/browser/web_contents/web_contents_view_aura.h"
#include "content/public/browser/context_menu_params.h"
#include "content/public/browser/web_contents.h"
+#include "tizen/system_info.h"
#include "ui/base/clipboard/clipboard_helper_efl.h"
#include "ui/display/device_display_info_efl.h"
#include "ui/display/screen.h"
new SelectionHandleEfl(*this, SelectionHandleEfl::HANDLE_TYPE_RIGHT)),
input_handle_(
new SelectionHandleEfl(*this, SelectionHandleEfl::HANDLE_TYPE_INPUT)),
- magnifier_(new SelectionMagnifierEfl(this)),
- selection_mode_(None) {
+ magnifier_(new SelectionMagnifierEfl(this)) {
evas_object_event_callback_add(rwhva_->offscreen_helper()->content_image(),
EVAS_CALLBACK_MOVE,
&EvasParentViewMoveCallback, this);
}
bool SelectionControllerEfl::GetCaretSelectionStatus() const {
- TRACE_EVENT1("selection,efl", __PRETTY_FUNCTION__,
- "caret selection", selection_mode_ == Caret);
- return selection_mode_ == Caret;
+ TRACE_EVENT1("selection,efl", __PRETTY_FUNCTION__, "caret selection",
+ selection_mode_ == SelectionMode::CARET);
+ return selection_mode_ == SelectionMode::CARET;
}
void SelectionControllerEfl::SetControlsTemporarilyHidden(
const gfx::Rect& right_rect) {
if (left_rect == gfx::Rect() && right_rect == gfx::Rect())
- SetSelectionMode(None);
+ SetSelectionMode(SelectionMode::NONE);
else if (left_rect == right_rect && GetSelectionEditable())
- SetSelectionMode(Caret);
+ SetSelectionMode(SelectionMode::CARET);
else
- SetSelectionMode(Range);
+ SetSelectionMode(SelectionMode::RANGE);
}
bool SelectionControllerEfl::UpdateSelectionDataAndShow(
return true;
}
+bool SelectionControllerEfl::IsCaretMode() const {
+ return selection_data_->IsInEditField() && GetLeftRect() == GetRightRect();
+}
+
void SelectionControllerEfl::ShowHandleAndContextMenuIfRequired(
Reason explicit_reason) {
TRACE_EVENT0("selection,efl", __PRETTY_FUNCTION__);
+ Reason saved_reason = selection_change_reason_;
Reason effective_reason = selection_change_reason_;
+
if (explicit_reason != Reason::Irrelevant)
effective_reason = explicit_reason;
return;
}
- bool is_selection_range_visible =
- start_selection_.visible() || end_selection_.visible();
+ bool is_start_selection_visible = start_selection_.visible();
+ bool is_end_selection_visible = end_selection_.visible();
+
+ // When the view is only partially visible we need to check if
+ // the visible part contains selection rects.
+ auto visible_viewport_rect = GetVisibleViewportRect();
+ if (!visible_viewport_rect.IsEmpty() ||
+ rwhva_->offscreen_helper()->GetTopControlsHeight() > 0) {
+ auto view_offset =
+ rwhva_->offscreen_helper()->GetViewBoundsInPix().OffsetFromOrigin();
+ is_start_selection_visible =
+ is_start_selection_visible &&
+ !IsRectEmpty(IntersectRects(visible_viewport_rect, left + view_offset,
+ true /*ignore_width*/));
+ is_end_selection_visible =
+ is_end_selection_visible &&
+ !IsRectEmpty(IntersectRects(visible_viewport_rect, right + view_offset,
+ true /*ignore_width*/));
+ }
// Is in edit field and no text is selected. show only single handle
if (selection_data_->IsInEditField() && left == right) {
CHECK(start_selection_ == end_selection_);
- if (GetCaretSelectionStatus() && is_selection_range_visible) {
- gfx::Rect left = selection_data_->GetLeftRect();
+ if (GetCaretSelectionStatus() && is_start_selection_visible) {
input_handle_->SetBasePosition(gfx::Point(left.x(), left.y()));
input_handle_->Move(left.bottom_right());
input_handle_->Show();
}
bool show_context_menu =
- IsAnyHandleVisible() &&
+ input_handle_->IsVisible() &&
effective_reason != Reason::ScrollOrZoomGestureEnded &&
effective_reason != Reason::Tap &&
effective_reason != Reason::Irrelevant;
- if (!handle_being_dragged_ && show_context_menu)
+ if (!handle_being_dragged_ && show_context_menu) {
+ selection_change_reason_ = saved_reason;
ShowContextMenu();
-
+ }
return;
}
input_handle_->Hide();
start_handle_->SetBasePosition(left.bottom_left());
start_handle->Move(left.bottom_left());
- if (start_selection_.visible())
+ if (is_start_selection_visible)
start_handle->Show();
else
start_handle->Hide();
end_handle_->SetBasePosition(right.bottom_right());
end_handle->Move(right.bottom_right());
- if (end_selection_.visible())
+ if (is_end_selection_visible)
end_handle->Show();
else
end_handle->Hide();
// Do not show the context menu during selection extend and
// offscreen selection.
- if (!handle_being_dragged_ && effective_reason != Reason::Irrelevant &&
- IsAnyHandleVisible()) {
+ if (!handle_being_dragged_ && selection_mode_ != SelectionMode::NONE) {
+ selection_change_reason_ = saved_reason;
ShowContextMenu();
}
}
void SelectionControllerEfl::ShowContextMenu() {
-#if !defined(USE_AURA)
- content::ContextMenuParams convertedParams = *(selection_data_->GetContextMenuParams());
-
- RenderWidgetHostViewEfl* rwhv =
- static_cast<RenderWidgetHostViewEfl*>(web_contents_.GetRenderWidgetHostView());
- if (rwhv) {
- int blinkX, blinkY;
- rwhv->EvasToBlinkCords(convertedParams.x, convertedParams.y, &blinkX, &blinkY);
- convertedParams.x = blinkX;
- convertedParams.y = blinkY;
-
- // TODO(a1.gomes): In case of EWK apps, the call below end up calling
- // EWebView::ShowContextMenu. We have to make sure parameters
- // are correct.
- WebContentsImpl* wci = static_cast<WebContentsImpl*>(&web_contents_);
- WebContentsViewEfl* wcve = static_cast<WebContentsViewEfl*>(wci->GetView());
- wcve->ShowContextMenu(convertedParams);
+ if (!rwhva_)
+ return;
+
+ if (IsMobileProfile()) {
+ if (context_menu_status_ == ContextMenuStatus::INPROGRESS)
+ return;
+ else
+ context_menu_status_ = ContextMenuStatus::INPROGRESS;
}
-#endif
+ content::ContextMenuParams convertedParams =
+ *(selection_data_->GetContextMenuParams());
+
+ int blinkX, blinkY;
+ rwhva_->offscreen_helper()->EvasToBlinkCords(
+ convertedParams.x, convertedParams.y, &blinkX, &blinkY);
+ convertedParams.x = blinkX;
+ convertedParams.y = blinkY;
+
+ // TODO(a1.gomes): In case of EWK apps, the call below end up calling
+ // EWebView::ShowContextMenu. We have to make sure parameters
+ // are correct.
+ WebContentsImpl* wci = static_cast<WebContentsImpl*>(web_contents());
+ WebContentsViewAura* wcva = static_cast<WebContentsViewAura*>(wci->GetView());
+ wcva->wcva_helper()->ShowContextMenu(convertedParams);
}
void SelectionControllerEfl::CancelContextMenu(int request_id) {
-#if !defined(USE_AURA)
- WebContentsImpl* wci = static_cast<WebContentsImpl*>(&web_contents_);
- WebContentsViewEfl* wcve = static_cast<WebContentsViewEfl*>(wci->GetView());
- wcve->CancelContextMenu(request_id);
-#endif
+ if (IsMobileProfile() && (context_menu_status_ == ContextMenuStatus::HIDDEN ||
+ context_menu_status_ == ContextMenuStatus::NONE)) {
+ return;
+ }
+
+ WebContentsImpl* wci = static_cast<WebContentsImpl*>(web_contents());
+ WebContentsViewAura* wcva = static_cast<WebContentsViewAura*>(wci->GetView());
+ wcva->wcva_helper()->CancelContextMenu(request_id);
}
void SelectionControllerEfl::HideHandles() {
ecore_event_filter_del(ecore_events_filter_);
ecore_events_filter_ = nullptr;
- selection_change_reason_ = Reason::Irrelevant;
+ selection_change_reason_ = Reason::HandleReleased;
start_handle_->SetBasePosition(selection_data_->GetLeftRect().bottom_left());
end_handle_->SetBasePosition(selection_data_->GetRightRect().bottom_right());
handle_being_dragged_ = false;
- ShowHandleAndContextMenuIfRequired(Reason::HandleReleased);
+ ShowHandleAndContextMenuIfRequired();
}
void SelectionControllerEfl::GetSelectionBounds(gfx::Rect* left,
int y,
ui::EventType type) {
DVLOG(0) << "HandlePostponedGesture :: " << type;
-#if !defined(USE_AURA)
- RenderWidgetHostViewEfl* rwhv =
- static_cast<RenderWidgetHostViewEfl*>(web_contents_.GetRenderWidgetHostView());
+ RenderWidgetHostViewAura* rwhva = static_cast<RenderWidgetHostViewAura*>(
+ web_contents()->GetRenderWidgetHostView());
gfx::Point point = gfx::Point(x, y);
- if (rwhv)
- point = rwhv->ConvertPointInViewPix(point);
-#endif
+ if (rwhva)
+ point = rwhva->offscreen_helper()->ConvertPointInViewPix(point);
switch (type) {
case ui::ET_GESTURE_LONG_PRESS: {
ClearSelectionViaEWebView();
}
SetSelectionStatus(true);
SetSelectionEditable(true);
- if (selection_mode_ == None)
- SetSelectionMode(Caret);
+ if (selection_mode_ == SelectionMode::NONE)
+ SetSelectionMode(SelectionMode::CARET);
HandleLongPressEventPrivate(touch_point);
return true;
} else if (params.link_url.is_empty() && params.src_url.is_empty() &&
- params.is_text_node ||
- !params.selection_text.empty()) {
+ (params.is_text_node || !params.selection_text.empty())) {
// If user is long pressing on a content with
// -webkit-user-select: none, we should bail and not enter
// selection neither show magnigier class or context menu.
CancelContextMenu(0);
SetSelectionStatus(false);
SetSelectionEditable(false);
- SetSelectionMode(None);
+ SetSelectionMode(SelectionMode::NONE);
selection_change_reason_ = Reason::Irrelevant;
}
left_rect.Offset(visible_viewport_rect.x(), visible_viewport_rect.y());
right_rect.Offset(visible_viewport_rect.x(), visible_viewport_rect.y());
- bool is_caret_mode =
- selection_data_->IsInEditField() && left_rect == right_rect;
- if (is_caret_mode) {
+ if (IsCaretMode()) {
forbidden_region.set_x(left_rect.x());
forbidden_region.set_y(input_handle_->IsTop()
? left_rect.y() - kLargeHandleHeight
forbidden_region.set_height(forbidden_region.height() + 2 * kMenuPadding);
return IntersectRects(forbidden_region, visible_viewport_rect,
- is_caret_mode /*ignore_width*/);
+ IsCaretMode() /*ignore_width*/);
}
gfx::Rect SelectionControllerEfl::GetVisibleViewportRect() const {
return selection_data_->IsInEditField() &&
(selection_data_->GetLeftRect() != selection_data_->GetRightRect());
}
+
+void SelectionControllerEfl::SetVisiblityStatus(bool visiblity) {
+ if (!visiblity && !handle_being_dragged_ && !is_caret_mode_forced_)
+ selection_change_reason_ = Reason::Irrelevant;
+ else if (selection_change_reason_ == Reason::Irrelevant)
+ selection_change_reason_ = Reason::RequestedByContextMenu;
+}
+
+void SelectionControllerEfl::ContextMenuStatusHidden() {
+ if (IsMobileProfile())
+ context_menu_status_ = ContextMenuStatus::HIDDEN;
+ SetVisiblityStatus(false);
+}
+
+void SelectionControllerEfl::ContextMenuStatusVisible() {
+ if (IsMobileProfile())
+ context_menu_status_ = ContextMenuStatus::VISIBLE;
+ SetVisiblityStatus(true);
+}
}
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/path_service.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 "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)
// 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 content {
ContextMenuControllerEfl::ContextMenuControllerEfl(EWebView* wv,
WebContents& web_contents)
- : webview_(wv),
- popup_(nullptr),
- menu_items_(nullptr),
- web_contents_(web_contents),
- is_text_selection_(false),
- weak_ptr_factory_(this) {
+ : webview_(wv), web_contents_(web_contents), weak_ptr_factory_(this) {
native_view_ =
static_cast<WebContentsImpl*>(&web_contents_)->GetEflNativeView();
}
blink::mojom::ContextMenuDataInputFieldType::kPassword) {
AddItemToProposedList(EWK_CONTEXT_MENU_ITEM_TYPE_ACTION, EWK_CONTEXT_MENU_ITEM_TAG_COPY,
std::string(dgettext("WebKit", "IDS_WEBVIEW_OPT_COPY")));
+
if (!params_.is_editable) {
AddItemToProposedList(
EWK_CONTEXT_MENU_ITEM_TYPE_ACTION,
std::string(dgettext("WebKit", "IDS_WEBVIEW_OPT_COPY_IMAGE")),
params_.src_url.spec(),
params_.src_url.spec());
- } else if (!params_.link_url.is_empty()) {
+ } else if (!params_.link_url.is_empty() && !params_.is_user_select_none) {
AddItemToProposedList(EWK_CONTEXT_MENU_ITEM_TYPE_ACTION,
EWK_CONTEXT_MENU_ITEM_TAG_TEXT_SELECTION_MODE,
std::string(dgettext("WebKit", "IDS_WEBVIEW_OPT_SELECTION_MODE_ABB")),
#endif
elm_object_tree_focus_allow_set(popup_, false);
} else {
- evas_object_data_set(native_view_, "ContextMenuContollerEfl", this);
- popup_ = elm_popup_add(native_view_);
- elm_popup_align_set(popup_, 0.5, 0.5);
+ 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;
- auto smart_parent = evas_object_smart_parent_get(native_view_);
- if (!smart_parent) {
- LOG(ERROR) << "Unable to get smart parent from native view";
- evas_object_del(popup_);
- popup_ = nullptr;
- return false;
- }
- evas_object_smart_member_add(popup_, smart_parent);
- elm_object_part_content_set(smart_parent, "context_menu_popup", popup_);
+
+ 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);
} 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)) {
- std::vector<std::string> link_split;
+ 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;
- while ((next_delimiter = selected_link.find(":", current_pos))
- != std::string::npos) {
- std::string part = selected_link.substr(current_pos,
- next_delimiter - current_pos);
- link_split.push_back(part);
+ // 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);
- if (!last_part.empty())
- link_split.push_back(last_part);
-
- if (!link_split[1].size()) {
- std::vector<std::string> real_link_split;
- size_t current_pos = 0;
- size_t next_delimiter = 0;
- while ((next_delimiter = link_split[1].find("?", current_pos)) != std::string::npos) {
- std::string part = link_split[1].substr(current_pos, next_delimiter - current_pos);
- real_link_split.push_back(part);
- current_pos = next_delimiter + 1;
- }
- std::string last_part = link_split[1].substr(current_pos);
- if (!last_part.empty())
- real_link_split.push_back(last_part);
-
- elm_object_part_text_set(popup_, "title,text", real_link_split[0].c_str());
+ 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());
}
}
+// 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())
+ 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, "ContextEfl"));
- if (menu_controller) {
- menu_controller->HideContextMenu();
- menu_controller->HideSelectionHandle();
- evas_object_data_del(obj, "ContextEfl");
+ 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,
}
gfx::Point ContextMenuControllerEfl::CalculateSelectionMenuPosition(
- gfx::Rect selection_rect) {
- auto rwhva = static_cast<RenderWidgetHostViewAura*>(
- web_contents_.GetRenderWidgetHostView());
- auto selection_controller = webview_->GetSelectionController();
- CHECK(rwhva);
- CHECK(selection_controller);
- auto webview_bounds = rwhva->offscreen_helper()->GetViewBoundsInPix();
+ const gfx::Rect& selection_rect) {
+ auto* selection_controller = webview_->GetSelectionController();
+ if (!selection_controller)
+ return gfx::Point();
- // Consider a webview offset.
- selection_rect.Offset(webview_bounds.x(), webview_bounds.y());
auto visible_viewport_rect = selection_controller->GetVisibleViewportRect();
auto forbidden_rect =
selection_controller->GetForbiddenRegionRect(selection_rect);
// 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());
- return position;
- }
- // If there is no sufficient space above, we're trying to place selection menu
- // below forbidden region.
- if (forbidden_rect.bottom() + kMenuHeight < visible_viewport_rect.bottom()) {
+ } 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);
- return position;
+ } 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());
}
- // 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(
- const gfx::Rect& selection_rect) {
- gfx::Point selection_menu_position =
- CalculateSelectionMenuPosition(selection_rect);
- if (!webview_->GetSelectionController()->GetVisibleViewportRect().Contains(
- selection_menu_position)) {
+ 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);
- web_contents_.Focus();
+
if (IsMobileProfile())
elm_ctxpopup_auto_hide_disabled_set(popup_, EINA_TRUE);
#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.
} 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);
- // Workaround. After context menu shows up, there is "unfocused" event fired.
- // evas_object_smart_callback_add(popup_, "unfocused", ContextMenuHWBackKey, this);
- evas_object_focus_set(popup_, EINA_TRUE);
+ eext_object_event_callback_add(popup_, EEXT_CALLBACK_MORE,
+ ContextMenuHWBackKey, this);
#endif
evas_object_show(popup_);
evas_object_raise(popup_);
- return true;
+ if (IsMobileProfile())
+ context_menu_status_ = VISIBLE;
+ }
+ return true;
}
void ContextMenuControllerEfl::HideSelectionHandle() {
void ContextMenuControllerEfl::OnClipboardDownload(
download::DownloadItem* item,
download::DownloadInterruptReason interrupt_reason) {
+ item->SetUserData(DownloadManagerDelegateEfl::kDownloadTemporaryFile,
+ base::WrapUnique(new base::SupportsUserData::Data()));
item->AddObserver(this);
clipboard_download_items_.insert(item);
}
void ContextMenuControllerEfl::OnDownloadUpdated(
download::DownloadItem* download) {
if(download && download->AllDataSaved()) {
- if (clipboard_download_items_.find(download) != clipboard_download_items_.end()) {
-#if !defined(WAYLAND_BRINGUP)
+ if (clipboard_download_items_.find(download) !=
+ clipboard_download_items_.end()) {
const std::string& download_path = download->GetForcedFilePath().value();
ClipboardHelperEfl::GetInstance()->SetData(download_path,
ClipboardDataTypeEfl::IMAGE);
-#else
- NOTIMPLEMENTED();
-#endif
download->RemoveObserver(this);
clipboard_download_items_.erase(download);
}
base::FilePath ContextMenuControllerEfl::DownloadFile(
const GURL url,
const base::FilePath outputDir,
+ const base::FilePath suggested_filename,
download::DownloadUrlParameters::OnStartedCallback callback) {
LOG(INFO) << "Downloading file: " << url << "to: "<< outputDir.value();
const GURL referrer = web_contents_.GetVisibleURL();
dl_params->set_referrer(referrer);
#endif
dl_params->set_referrer_encoding("utf8");
- base::FilePath fileName = net::GenerateFileName(url,"","","","","");
+ base::FilePath fileName;
+ if (suggested_filename.empty())
+ fileName = net::GenerateFileName(url, "", "", "", "", "");
+ else
+ fileName = suggested_filename;
base::FilePath fullPath = outputDir.Append(fileName);
while (base::PathExists(fullPath)) {
std::ignore = app_control_destroy(*handle);
}
+void ContextMenuControllerEfl::LaunchBrowserWithWebSearch(
+ const std::string& text) {
+ app_control_h app_control;
+ app_control_create(&app_control);
+
+ app_control_set_operation(app_control, APP_CONTROL_OPERATION_SEARCH);
+ if (IsMobileProfile()) {
+ app_control_add_extra_data(
+ app_control, "http://tizen.org/appcontrol/data/keyword", text.c_str());
+ } else {
+ app_control_add_extra_data(app_control, APP_CONTROL_DATA_TEXT,
+ text.c_str());
+ }
+ app_control_send_launch_request(app_control, NULL, NULL);
+
+ 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 (!webview_)
return;
- if (popup_)
- evas_object_hide(popup_);
+ HideContextMenu();
// FIXME: Add cases as and when required
switch(menu_item->GetContextMenuOption())
{
break;
}
case EWK_CONTEXT_MENU_ITEM_TAG_COPY_IMAGE_TO_CLIPBOARD: {
- LOG(INFO) << "[CLIPBOARD] copying image to clipboard!";
- std::string plain_text = params_.src_url.spec();
- ClipboardHelperEfl::GetInstance()->SetData(
- plain_text, ClipboardDataTypeEfl::PLAIN_TEXT);
+ // FIXME(g.ludwikowsk): Find the correct path for temporarily saving
+ // images to clipboard.
+ base::FilePath copy_image_dir("/tmp/");
+ base::FilePath suggested_filename;
+ if (params_.src_url.has_query()) {
+ suggested_filename = base::FilePath(base::UnescapeURLComponent(
+ params_.src_url.query(),
+ base::UnescapeRule::SPACES | base::UnescapeRule::PATH_SEPARATORS |
+ base::UnescapeRule::URL_SPECIAL_CHARS_EXCEPT_PATH_SEPARATORS));
+ } else {
+ suggested_filename = net::GenerateFileName(GURL(params_.src_url.spec()),
+ "", "", "", "", "");
+ }
- // FIXME(g.ludwikowsk): Setting markup data doesn't work like this,
- // selection_text doesn't contain html. Do we actually need to do this?
- ClipboardHelperEfl::GetInstance()->SetData(
- base::UTF16ToASCII(params_.selection_text),
- ClipboardDataTypeEfl::MARKUP);
- DownloadFile(
- GURL(params_.src_url.spec()), base::FilePath("/tmp/"),
- base::BindRepeating(&ContextMenuControllerEfl::OnClipboardDownload,
- weak_ptr_factory_.GetWeakPtr()));
+ if (suggested_filename.Extension().empty()) {
+ suggested_filename =
+ suggested_filename.AddExtension(kDefaultImageExtension);
+ }
+
+ base::FilePath fullPath = copy_image_dir.Append(suggested_filename);
+ // For files with the same name clipboard app refuses to add another one,
+ // saying that it is already copied to clipboard. When DownloadFile
+ // tries to download a file which already exists, it appends a number
+ // to the file name. This causes clipboard app to recognize it as a
+ // different file and clipboard is filled with duplicate images.
+ // To prevent this, we do not download file if a file with the same name
+ // already exists. We still call SetData, so clipboard app would show
+ // toast popup for duplicates. This is for Tizen 2.4 compatibility.
+ if (PathExists(fullPath)) {
+ ClipboardHelperEfl::GetInstance()->SetData(fullPath.value(),
+ ClipboardDataTypeEfl::IMAGE);
+ } else {
+ DownloadFile(
+ GURL(params_.src_url.spec()), copy_image_dir, suggested_filename,
+ base::BindRepeating(&ContextMenuControllerEfl::OnClipboardDownload,
+ weak_ptr_factory_.GetWeakPtr()));
+ }
break;
}
case EWK_CONTEXT_MENU_ITEM_TAG_COPY_LINK_DATA: {
LOG(ERROR) << "Could not get downloads directory.";
break;
}
- DownloadFile(GURL(params_.link_url.spec()), path,
+ DownloadFile(GURL(params_.link_url.spec()), path, base::FilePath(),
base::BindOnce(&ContextMenuControllerEfl::OnDiskDownload,
weak_ptr_factory_.GetWeakPtr()));
}
LOG(ERROR) << "Could not get image downloads directory.";
break;
}
- DownloadFile(GURL(params_.src_url.spec()), path,
+ DownloadFile(GURL(params_.src_url.spec()), path, base::FilePath(),
base::BindOnce(&ContextMenuControllerEfl::OnDiskDownload,
weak_ptr_factory_.GetWeakPtr()));
}
case EWK_CONTEXT_MENU_ITEM_TAG_SEARCH_WEB: {
std::string search_text = base::UTF16ToUTF8(params_.selection_text);
webview_->ClearSelection();
+#if BUILDFLAG(IS_TIZEN)
+ if (IsMobileProfile()) {
+ LaunchBrowserWithWebSearch(search_text);
+ } else {
+ OpenURL(GURL(kWebSearchLink + search_text),
+ WindowOpenDisposition::NEW_FOREGROUND_TAB);
+ }
+#else
OpenURL(GURL(kWebSearchLink + search_text),
WindowOpenDisposition::NEW_FOREGROUND_TAB);
+#endif
break;
}
case EWK_CONTEXT_MENU_ITEM_TAG_CLIPBOARD: {
}
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);
popup_ = nullptr;
}
+ if (restore_timer_) {
+ ecore_timer_del(restore_timer_);
+ restore_timer_ = nullptr;
+ }
+
if (IsMobileProfile()) {
-#if !defined(EWK_BRINGUP)
context_menu_status_ = HIDDEN;
-#endif
} else if (menu_items_) {
void* data;
EINA_LIST_FREE(menu_items_, data) {
- _Ewk_Context_Menu_Item *item = static_cast<_Ewk_Context_Menu_Item*> (data);
+ _Ewk_Context_Menu_Item* item = static_cast<_Ewk_Context_Menu_Item*>(data);
delete item;
}
menu_items_ = nullptr;
if (!popup_)
return;
+ if (IsMobileProfile() && context_menu_status_ != VISIBLE)
+ return;
+
if (is_text_selection_) {
RequestSelectionRect();
} else {
}
void ContextMenuControllerEfl::DeletePopup() {
- if (native_view_)
- evas_object_data_set(native_view_, "ContextMenuContollerEfl", 0);
+ 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);
- evas_object_smart_member_del(popup_);
+ if (!IsMobileProfile())
+ evas_object_smart_member_del(popup_);
evas_object_del(popup_);
popup_ = nullptr;
list_ = nullptr;
}
menu_items_ = nullptr;
}
+ if (IsMobileProfile())
+ context_menu_status_ = NONE;
}
}