1 // Copyright 2013 Samsung Electronics. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "selection_handle_efl.h"
9 #include <Elementary.h>
11 #include "base/files/file_path.h"
12 #include "base/path_service.h"
13 #include "base/trace_event/trace_event.h"
14 #include "content/browser/renderer_host/render_widget_host_view_aura.h"
15 #include "content/browser/selection/selection_controller_efl.h"
16 #include "content/browser/web_contents/web_contents_impl.h"
17 #include "content/common/paths_efl.h"
21 // Size of the left/right margin which causes selection handles to be rotated
22 const int kReverseMargin = 32;
23 const char* kLeftHandlePath = "elm/entry/selection/block_handle_left";
24 const char* kRightHandlePath = "elm/entry/selection/block_handle_right";
25 const char* kInputHandlePath = "elm/entry/cursor_handle/default";
27 static const char* GetEdjeObjectGroupPath(SelectionHandleEfl::HandleType type) {
29 case SelectionHandleEfl::HANDLE_TYPE_LEFT:
30 return kLeftHandlePath;
31 case SelectionHandleEfl::HANDLE_TYPE_RIGHT:
32 return kRightHandlePath;
33 case SelectionHandleEfl::HANDLE_TYPE_INPUT:
34 return kInputHandlePath;
40 SelectionHandleEfl::SelectionHandleEfl(SelectionControllerEfl& controller,
42 : controller_(controller),
46 Evas* evas = evas_object_evas_get(
47 controller_.rwhva()->offscreen_helper()->content_image());
48 handle_ = edje_object_add(evas);
50 base::FilePath edj_dir;
51 base::PathService::Get(PathsEfl::EDJE_RESOURCE_DIR, &edj_dir);
52 base::FilePath selection_handles_edj =
53 edj_dir.Append(FILE_PATH_LITERAL("SelectionHandles.edj"));
55 std::string theme_path = selection_handles_edj.AsUTF8Unsafe();
56 const char* group = GetEdjeObjectGroupPath(type);
57 if (edje_file_group_exists(theme_path.c_str(), group)) {
58 edje_object_file_set(handle_, theme_path.c_str(), group);
61 edje_object_signal_emit(handle_, "edje,focus,in", "edje");
62 edje_object_signal_emit(handle_, "elm,state,bottom", "elm");
63 Evas_Object* main_layout_ =
64 static_cast<WebContentsImpl*>(
65 controller_.rwhva()->offscreen_helper()->GetWebContents())
67 Evas_Object* smart_parent = evas_object_smart_parent_get(main_layout_);
68 evas_object_smart_member_add(handle_, smart_parent);
69 evas_object_propagate_events_set(handle_, false);
71 evas_object_event_callback_add(handle_, EVAS_CALLBACK_MOUSE_DOWN, OnMouseDown, this);
72 evas_object_event_callback_add(handle_, EVAS_CALLBACK_MOUSE_UP, OnMouseUp, this);
75 SelectionHandleEfl::~SelectionHandleEfl() {
76 evas_object_event_callback_del(handle_, EVAS_CALLBACK_MOUSE_DOWN, OnMouseDown);
77 evas_object_event_callback_del(handle_, EVAS_CALLBACK_MOUSE_UP, OnMouseUp);
78 evas_object_smart_member_del(handle_);
79 evas_object_del(handle_);
82 void SelectionHandleEfl::Show() {
83 evas_object_show(handle_);
84 evas_object_raise(handle_);
87 void SelectionHandleEfl::Hide() {
88 evas_object_hide(handle_);
91 bool SelectionHandleEfl::IsVisible() const {
92 int handle_x, handle_y;
93 evas_object_geometry_get(handle_, &handle_x, &handle_y, nullptr, nullptr);
95 auto view_rect = controller_.GetVisibleViewportRect();
97 return evas_object_visible_get(handle_) &&
98 view_rect.Contains(handle_x, handle_y);
101 void SelectionHandleEfl::Move(const gfx::Point& point) {
103 ChangeObjectDirection(CalculateDirection(point));
105 if (handle_type_ == HANDLE_TYPE_INPUT)
106 MoveInputHandle(point);
108 MoveRangeHandle(point);
111 void SelectionHandleEfl::MoveInputHandle(const gfx::Point& point) {
112 CHECK(handle_type_ == HANDLE_TYPE_INPUT);
116 void SelectionHandleEfl::MoveRangeHandle(const gfx::Point& point) {
117 CHECK(handle_type_ != HANDLE_TYPE_INPUT);
122 void SelectionHandleEfl::OnMouseDown(void* data, Evas*, Evas_Object*, void* event_info) {
123 Evas_Event_Mouse_Down* event = static_cast<Evas_Event_Mouse_Down*>(event_info);
124 SelectionHandleEfl* handle = static_cast<SelectionHandleEfl*>(data);
125 handle->pressed_ = true;
126 //Save the diff_point between touch point and base point of the handle
127 handle->diff_point_.SetPoint(event->canvas.x - handle->base_point_.x(),
128 event->canvas.y - handle->base_point_.y());
130 handle->controller_.HandleDragBeginNotification(handle);
133 void SelectionHandleEfl::UpdatePosition(const gfx::Point& position) {
134 current_touch_point_ = position;
135 ecore_job_add(UpdateMouseMove, this);
138 void SelectionHandleEfl::OnMouseUp(void* data, Evas*, Evas_Object*, void* /* event_info */) {
139 SelectionHandleEfl* handle = static_cast<SelectionHandleEfl*>(data);
140 handle->pressed_ = false;
141 handle->controller_.HandleDragEndNotification();
144 void SelectionHandleEfl::UpdateMouseMove(void* data) {
145 SelectionHandleEfl* handle = static_cast<SelectionHandleEfl*>(data);
147 // As this method is queued and then precessed, it might happen that
148 // it gets called once user has lifted up its finger.
149 // Bail out in such cases.
150 if (!handle->pressed_)
153 int delta_x = handle->current_touch_point_.x() - handle->diff_point_.x();
154 int delta_y = handle->current_touch_point_.y() - handle->diff_point_.y();
155 handle->base_point_.SetPoint(delta_x, delta_y);
157 handle->controller_.HandleDragUpdateNotification(handle);
160 SelectionHandleEfl::HandleDirection SelectionHandleEfl::CalculateDirection(
161 const gfx::Point& point) const {
162 bool reverse_horizontally = false, reverse_vertically = false;
164 edje_object_part_geometry_get(handle_, "handle", 0, 0, 0, &handleHeight);
166 auto visible_viewport_rect = controller_.GetVisibleViewportRect();
167 gfx::Point conv_point(point.x() + visible_viewport_rect.x(),
168 point.y() + visible_viewport_rect.y());
170 gfx::Rect reverse_direction_rect = gfx::Rect(
171 visible_viewport_rect.x() + kReverseMargin, visible_viewport_rect.y(),
172 visible_viewport_rect.width() - 2 * kReverseMargin,
173 visible_viewport_rect.height() - handleHeight);
175 if (!reverse_direction_rect.Contains(conv_point)) {
176 if (conv_point.x() <= reverse_direction_rect.x() ||
177 conv_point.x() >= reverse_direction_rect.right()) {
178 reverse_vertically = true;
180 if (conv_point.y() <= reverse_direction_rect.y() ||
181 conv_point.y() >= reverse_direction_rect.bottom()) {
182 reverse_horizontally = true;
186 if (handle_type_ != HANDLE_TYPE_INPUT) {
187 if (reverse_vertically) {
188 if (reverse_horizontally)
189 return DirectionTopReverse;
191 return DirectionBottomReverse;
193 if (reverse_horizontally)
194 return DirectionTopNormal;
196 return DirectionBottomNormal;
199 // Input handle can only be rotated horizontally
200 if (reverse_horizontally)
201 return DirectionTopNormal;
203 return DirectionBottomNormal;
207 return DirectionBottomNormal;
210 void SelectionHandleEfl::ChangeObjectDirection(HandleDirection direction) {
211 TRACE_EVENT2("selection,efl", __PRETTY_FUNCTION__,
212 "handle type", handle_type_, "direction", direction);
214 is_top_ = (direction == DirectionTopNormal || direction == DirectionTopReverse);
217 case DirectionBottomNormal:
218 if (handle_type_ == HANDLE_TYPE_INPUT)
219 edje_object_signal_emit(handle_, "edje,cursor,handle,show", "edje");
221 edje_object_signal_emit(handle_, "elm,state,bottom", "elm");
223 case DirectionBottomReverse:
224 if (handle_type_ == HANDLE_TYPE_INPUT)
225 edje_object_signal_emit(handle_, "edje,cursor,handle,show", "edje");
227 edje_object_signal_emit(handle_, "elm,state,bottom,reversed", "elm");
229 case DirectionTopNormal:
230 if (handle_type_ == HANDLE_TYPE_INPUT)
231 edje_object_signal_emit(handle_, "edje,cursor,handle,top", "edje");
233 edje_object_signal_emit(handle_, "elm,state,top", "elm");
235 case DirectionTopReverse:
236 if (handle_type_ == HANDLE_TYPE_INPUT)
237 edje_object_signal_emit(handle_, "edje,cursor,handle,top", "edje");
239 edje_object_signal_emit(handle_, "elm,state,top,reversed", "elm");
243 switch (handle_type_) {
244 case HANDLE_TYPE_LEFT:
245 evas_object_smart_callback_call(
246 controller_.rwhva()->offscreen_helper()->ewk_view(),
247 "selection,handle,left,direction", &direction);
249 case HANDLE_TYPE_RIGHT:
250 evas_object_smart_callback_call(
251 controller_.rwhva()->offscreen_helper()->ewk_view(),
252 "selection,handle,right,direction", &direction);
254 case HANDLE_TYPE_INPUT:
255 evas_object_smart_callback_call(
256 controller_.rwhva()->offscreen_helper()->ewk_view(),
257 "selection,handle,large,direction", &direction);
262 gfx::Rect SelectionHandleEfl::GetSelectionRect() const {
265 switch(handle_type_) {
266 case HANDLE_TYPE_RIGHT:
267 return controller_.GetRightRect();
268 case HANDLE_TYPE_LEFT:
269 return controller_.GetLeftRect();
270 case HANDLE_TYPE_INPUT:
271 // no rect for this type of handle
278 void SelectionHandleEfl::MoveObject(const gfx::Point& point, bool ignore_parent_view_offset) {
279 gfx::Rect view_bounds =
280 controller_.rwhva()->offscreen_helper()->GetViewBoundsInPix();
281 int handle_x = point.x() + view_bounds.x();
282 int handle_y = point.y() + view_bounds.y();
285 if (handle_type_ == HANDLE_TYPE_RIGHT)
286 handle_y -= controller_.GetRightRect().height();
288 handle_y -= controller_.GetLeftRect().height();
291 // Prevent selection handles from moving out of visible webview.
292 if (handle_type_ != HANDLE_TYPE_INPUT) {
293 const gfx::Rect& viewport_rect = controller_.GetVisibleViewportRect();
294 int viewport_rect_x = viewport_rect.x();
295 int viewport_rect_y = viewport_rect.y();
296 int viewport_rect_w = viewport_rect.width();
297 int viewport_rect_h = viewport_rect.height();
299 if (handle_y < viewport_rect_y)
300 handle_y = viewport_rect_y;
301 else if (handle_y > viewport_rect_h + viewport_rect_y)
302 handle_y = viewport_rect_h + viewport_rect_y;
304 if (handle_x < viewport_rect_x)
305 handle_x = viewport_rect_x;
306 else if (handle_x > viewport_rect_w + viewport_rect_x)
307 handle_x = viewport_rect_w + viewport_rect_x;
310 evas_object_move(handle_, handle_x, handle_y);
313 } // namespace content