From: Piotr Tworek Date: Thu, 19 Jun 2014 18:34:42 +0000 (-0700) Subject: Improve text selection handling X-Git-Tag: submit/tizen/20190801.160004~2594 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=743a764e161e7cdd313cd2cb35d796570f5709c5;p=platform%2Fframework%2Fweb%2Fchromium-efl.git Improve text selection handling This patch fixes several selection handle drawing issues caused by the fact that SelectionBoxEfl was only fully updated from after mouse up event handler was invoked. If a user manipulated the handles in a way that the handles needed to be updated several times during one selection the end results were not always matching the real state of the selection. Long term, it'd be good if the selection state could be storred only in one class. As it is right now the actual state of the selection resides in the SelectionBoxEfl, while the visible state of the handles is in SelectionHandleEfl. Those states are 'synchronized' in SelectionControllerEfl. Such approach is very error prone as it's not always obvious which state is valid at any given point in time. Patch also hide context menu during magnifier is showing. Issue-Id: CBBROWSER-156 Change-Id: I8c13e6c2734b294b5e912ce3a9fa78899da7e6de Conflicts: impl/browser/renderer_host/render_widget_host_view_efl.cc impl/browser/renderer_host/render_widget_host_view_efl.h impl/selection_controller_efl.cc impl/selection_controller_efl.h --- diff --git a/tizen_src/impl/browser/renderer_host/render_widget_host_view_efl.cc b/tizen_src/impl/browser/renderer_host/render_widget_host_view_efl.cc index 051ac9ad3167..b044fc8db846 100644 --- a/tizen_src/impl/browser/renderer_host/render_widget_host_view_efl.cc +++ b/tizen_src/impl/browser/renderer_host/render_widget_host_view_efl.cc @@ -503,6 +503,14 @@ void RenderWidgetHostViewEfl::TextInputTypeChanged(ui::TextInputType type, ui::T // Finally, the empty rect is not used. host_->ScrollFocusedEditableNodeIntoRect(gfx::Rect(0, 0, 0, 0)); } + + if (GetSelectionController()) { + GetSelectionController()->SetSelectionEditable( + type == ui::TEXT_INPUT_TYPE_TEXT || + type == ui::TEXT_INPUT_TYPE_PASSWORD || + type == ui::TEXT_INPUT_TYPE_TEXT_AREA || + type == ui::TEXT_INPUT_TYPE_CONTENT_EDITABLE); + } } void RenderWidgetHostViewEfl::TextInputStateChanged( @@ -513,33 +521,18 @@ void RenderWidgetHostViewEfl::TextInputStateChanged( } void RenderWidgetHostViewEfl::ImeCancelComposition() { - LOG(INFO) << __PRETTY_FUNCTION__; if (im_context_) im_context_->CancelComposition(); } -void RenderWidgetHostViewEfl::OnTextInputInFormStateChanged(bool is_in_form_tag) -{ +void RenderWidgetHostViewEfl::OnTextInputInFormStateChanged(bool is_in_form_tag) { if (im_context_) im_context_->SetIsInFormTag(is_in_form_tag); } -bool RenderWidgetHostViewEfl::GetCompositionCharacterBounds(uint32 index, gfx::Rect* rect) const -{ - LOG(INFO) << __PRETTY_FUNCTION__; - DCHECK(rect); - if (index >= composition_character_bounds_.size()) - return false; - - *rect = composition_character_bounds_[index]; - return true; -} - void RenderWidgetHostViewEfl::ImeCompositionRangeChanged( - const gfx::Range& range, - const std::vector& character_bounds) { - LOG(INFO) << __PRETTY_FUNCTION__; - composition_character_bounds_ = character_bounds; + const gfx::Range& range, + const std::vector& character_bounds) { SelectionControllerEfl* controller = web_view_->GetSelectionController(); if (controller) { controller->SetCaretSelectionStatus(false); @@ -569,7 +562,6 @@ void RenderWidgetHostViewEfl::SetTooltipText(const base::string16& text) { void RenderWidgetHostViewEfl::SelectionChanged(const base::string16& text, size_t offset, const gfx::Range& range) { - LOG(INFO) << __PRETTY_FUNCTION__; SelectionControllerEfl* controller = web_view_->GetSelectionController(); if (controller) controller->UpdateSelectionData(text); @@ -577,7 +569,6 @@ void RenderWidgetHostViewEfl::SelectionChanged(const base::string16& text, void RenderWidgetHostViewEfl::SelectionBoundsChanged( const ViewHostMsg_SelectionBounds_Params& params) { - LOG(INFO) << __PRETTY_FUNCTION__; ViewHostMsg_SelectionBounds_Params guest_params(params); guest_params.anchor_rect = ConvertRectToPixel(device_scale_factor_, params.anchor_rect); guest_params.focus_rect = ConvertRectToPixel(device_scale_factor_, params.focus_rect); @@ -596,7 +587,8 @@ void RenderWidgetHostViewEfl::ScrollOffsetChanged() { void RenderWidgetHostViewEfl::SelectionRootBoundsChanged(const gfx::Rect& rect) { if (GetSelectionController()) - GetSelectionController()->SetVisibilityBounds(rect); + GetSelectionController()->SetVisibilityBounds( + ConvertRectToPixel(device_scale_factor_, rect)); } void RenderWidgetHostViewEfl::DidStopFlinging() { @@ -1137,8 +1129,6 @@ void RenderWidgetHostViewEfl::HandleGesture(ui::GestureEvent* event) { gesture.globalX = root_point.x(); gesture.globalY = root_point.y(); - LOG(INFO) << "RenderWidgetHostViewEfl::HandleGesture : type = " << event->type(); - if (event->type() == ui::ET_GESTURE_TAP_DOWN) { // Webkit does not stop a fling-scroll on tap-down. So explicitly send an // event to stop any in-progress flings. diff --git a/tizen_src/impl/browser/renderer_host/render_widget_host_view_efl.h b/tizen_src/impl/browser/renderer_host/render_widget_host_view_efl.h index af6a939a6a45..ea98c15b87da 100755 --- a/tizen_src/impl/browser/renderer_host/render_widget_host_view_efl.h +++ b/tizen_src/impl/browser/renderer_host/render_widget_host_view_efl.h @@ -57,7 +57,6 @@ class ReadbackYUVInterface; // RenderWidgetHostView class hierarchy described in render_widget_host_view.h. class RenderWidgetHostViewEfl : public RenderWidgetHostViewBase, - public ui::TextInputClient, public base::SupportsWeakPtr, public IPC::Sender { public: @@ -158,44 +157,11 @@ class RenderWidgetHostViewEfl virtual void RenderProcessGone(base::TerminationStatus, int) OVERRIDE; virtual bool OnMessageReceived(const IPC::Message&) OVERRIDE; virtual void ProcessAckedTouchEvent(const TouchEventWithLatencyInfo&, InputEventAckState) OVERRIDE; + virtual void DidStopFlinging() OVERRIDE; - virtual bool IsEditingCommandEnabled(int) OVERRIDE { return false; } - virtual void ExecuteEditingCommand(int) OVERRIDE {} // IPC::Sender implementation: virtual bool Send(IPC::Message*) OVERRIDE; - // Overridden from ui::TextInputClient implementation: - virtual void SetCompositionText( - const ui::CompositionText& composition) OVERRIDE {} - virtual void ConfirmCompositionText() OVERRIDE {} - virtual void ClearCompositionText() OVERRIDE {} - virtual void InsertText(const base::string16& text) OVERRIDE {} - virtual void InsertChar(base::char16 ch, int flags) OVERRIDE {} - virtual gfx::NativeWindow GetAttachedWindow() const OVERRIDE { return gfx::NativeWindow(); } - virtual ui::TextInputType GetTextInputType() const OVERRIDE { return ui::TextInputType(); } - virtual ui::TextInputMode GetTextInputMode() const OVERRIDE { return ui::TextInputMode(); } - virtual bool CanComposeInline() const OVERRIDE { return false; } - virtual gfx::Rect GetCaretBounds() const OVERRIDE { return gfx::Rect(); } - virtual bool GetCompositionCharacterBounds(uint32 index, - gfx::Rect* rect) const OVERRIDE; - virtual bool HasCompositionText() const OVERRIDE { return false; } - virtual bool GetTextRange(gfx::Range* range) const OVERRIDE { return false; } - virtual bool GetCompositionTextRange(gfx::Range* range) const OVERRIDE { return false; } - virtual bool GetSelectionRange(gfx::Range* range) const OVERRIDE { return false; } - virtual bool SetSelectionRange(const gfx::Range& range) OVERRIDE { return false; } - virtual bool DeleteRange(const gfx::Range& range) OVERRIDE { return false; } - virtual bool GetTextFromRange(const gfx::Range& range, - base::string16* text) const OVERRIDE { return false; } - virtual void OnInputMethodChanged() OVERRIDE {} - virtual bool ChangeTextDirectionAndLayoutAlignment( - base::i18n::TextDirection direction) OVERRIDE { return false; } - virtual void ExtendSelectionAndDelete(size_t before, size_t after) OVERRIDE {} - virtual void EnsureCaretInRect(const gfx::Rect& rect) OVERRIDE {} - virtual void OnCandidateWindowShown() OVERRIDE {} - virtual void OnCandidateWindowUpdated() OVERRIDE {} - virtual void OnCandidateWindowHidden() OVERRIDE {} - virtual void DidStopFlinging() OVERRIDE; - void OnDidFirstVisuallyNonEmptyLayout(); void OnSelectionTextStyleState(const SelectionStylePrams& params); void OnDidChangeMaxScrollOffset(int maxScrollX, int maxScrollY); @@ -305,9 +271,6 @@ class RenderWidgetHostViewEfl typedef std::map PluginWindowToWidgetMap; PluginWindowToWidgetMap plugin_window_to_widget_map_; - // The current composition character bounds. - std::vector composition_character_bounds_; - bool m_magnifier; // Whether we are currently loading. diff --git a/tizen_src/impl/selection_box_efl.cc b/tizen_src/impl/selection_box_efl.cc index 505d98af1440..1354fe694640 100644 --- a/tizen_src/impl/selection_box_efl.cc +++ b/tizen_src/impl/selection_box_efl.cc @@ -25,22 +25,11 @@ namespace content { SelectionBoxEfl::SelectionBoxEfl(EWebView* parent_view) : status_(false), editable_(false), - is_anchor_first_(true), is_caret_selection_(false), context_params_(new ContextMenuParams()), parent_view_(parent_view) { } -void SelectionBoxEfl::UpdateHandleData() { - // Swap the handlers when these handles cross over - if (!is_anchor_first_) { - gfx::Rect swap_rect_; - swap_rect_ = left_rect_; - left_rect_ = right_rect_; - right_rect_ = swap_rect_; - } -} - void SelectionBoxEfl::UpdateSelectStringData(const base::string16& text) { context_params_->selection_text = text; } @@ -51,13 +40,17 @@ void SelectionBoxEfl::ClearRectData() { context_params_->x = context_params_->y = 0; } -void SelectionBoxEfl::UpdateRectData(const gfx::Rect& left_rect, const gfx::Rect& right_rect, bool is_anchor_first) { +void SelectionBoxEfl::UpdateRectData(const gfx::Rect& left_rect, const gfx::Rect& right_rect) { TRACE_EVENT2("selection,efl", __PRETTY_FUNCTION__, "left_rect", left_rect.ToString(), "right_rect", right_rect.ToString()); - is_anchor_first_ = is_anchor_first; - left_rect_ = left_rect; - right_rect_ = right_rect; + if (left_rect < right_rect) { + left_rect_ = left_rect; + right_rect_ = right_rect; + } else { + right_rect_ = left_rect; + left_rect_ = right_rect; + } // Display point of context Menu Evas_Coord x, y; @@ -65,8 +58,6 @@ void SelectionBoxEfl::UpdateRectData(const gfx::Rect& left_rect, const gfx::Rect //context params suppose to be global - related to evas not the web view context_params_->x = left_rect_.x() + x; context_params_->y = left_rect_.y() + y; - - UpdateHandleData(); } bool SelectionBoxEfl::IsInEditField() const { diff --git a/tizen_src/impl/selection_box_efl.h b/tizen_src/impl/selection_box_efl.h index df231fd2ef1f..902602db3383 100644 --- a/tizen_src/impl/selection_box_efl.h +++ b/tizen_src/impl/selection_box_efl.h @@ -41,9 +41,8 @@ class SelectionBoxEfl { bool GetStatus() const { return status_; } void SetEditable(bool enable) { GetContextMenuParams()->is_editable = editable_ = enable; } bool GetEditable() const { return editable_; } - void UpdateHandleData(); void UpdateSelectStringData(const base::string16& text); - void UpdateRectData(const gfx::Rect& left_rect, const gfx::Rect& right_rect, bool is_anchor_first); + void UpdateRectData(const gfx::Rect& left_rect, const gfx::Rect& right_rect); void ClearRectData(); bool IsInEditField() const; void SetCaretSelectionStatus(const bool enable) { is_caret_selection_ = enable; } @@ -51,7 +50,6 @@ class SelectionBoxEfl { gfx::Rect GetLeftRect() const { return left_rect_; } gfx::Rect GetRightRect() const { return right_rect_; } ContextMenuParams* GetContextMenuParams() const { return context_params_.get(); } - bool IsAnchorFirst() { return is_anchor_first_; } private: // Save the state of selection, if active or not @@ -60,9 +58,6 @@ class SelectionBoxEfl { // Save if the selection is in one of the editable fields bool editable_; - // Is set if handlers crossover rects are interchanged - bool is_anchor_first_; - // Caret is in a input field bool is_caret_selection_; diff --git a/tizen_src/impl/selection_controller_efl.cc b/tizen_src/impl/selection_controller_efl.cc index 4a5858c5e799..adc70cc27699 100644 --- a/tizen_src/impl/selection_controller_efl.cc +++ b/tizen_src/impl/selection_controller_efl.cc @@ -42,11 +42,13 @@ SelectionControllerEfl::SelectionControllerEfl(EWebView* parent_view) : parent_view_(parent_view), mouse_press_(false), scrolling_(false), + expecting_update_(false), long_mouse_press_(false), selection_data_(new SelectionBoxEfl(parent_view)), - start_handle_(new SelectionHandleEfl(this, SelectionHandleEfl::HANDLE_TYPE_LEFT, parent_view->evas_object())), - end_handle_(new SelectionHandleEfl(this, SelectionHandleEfl::HANDLE_TYPE_RIGHT, parent_view->evas_object())), - input_handle_(new SelectionHandleEfl(this, SelectionHandleEfl::HANDLE_TYPE_INPUT, parent_view->evas_object())), + start_handle_(new SelectionHandleEfl(*this, SelectionHandleEfl::HANDLE_TYPE_LEFT, parent_view->evas_object())), + end_handle_(new SelectionHandleEfl(*this, SelectionHandleEfl::HANDLE_TYPE_RIGHT, parent_view->evas_object())), + input_handle_(new SelectionHandleEfl(*this, SelectionHandleEfl::HANDLE_TYPE_INPUT, parent_view->evas_object())), + magnifier_(new SelectionMagnifierEfl(this)) { evas_object_event_callback_add(parent_view_->evas_object(), EVAS_CALLBACK_MOVE, &EvasParentViewMoveCallback, this); @@ -131,70 +133,74 @@ void SelectionControllerEfl::ClearSelectionViaEWebView() { parent_view_->ClearSelection(); } -void SelectionControllerEfl::UpdateSelectionDataAndShow(const gfx::Rect& left_rect, const gfx::Rect& right_rect, bool is_anchor_first) { +void SelectionControllerEfl::UpdateSelectionDataAndShow(const gfx::Rect& left_rect, const gfx::Rect& right_rect, bool) { TRACE_EVENT0("selection,efl", __PRETTY_FUNCTION__); - selection_data_->UpdateRectData(left_rect, right_rect, is_anchor_first); - parent_view_->QuerySelectionStyle(); + selection_data_->UpdateRectData(left_rect, right_rect); if (!IsSelectionValid(left_rect, right_rect)) { selection_data_->ClearRectData(); Clear(); - return; + } else { + if (selection_data_->GetEditable()) { + // In case we're selecting text in editable text field we've already sent swapped + // coordinates from OnMouseMove. No need to do it for the second time. + ShowHandleAndContextMenuIfRequired(); + } else { + ShowHandleAndContextMenuIfRequired(left_rect < right_rect); + } } - - // Do not show the context menu and handlers untill long mouse press is released - if (long_mouse_press_) - return; - - // Do not show the context menu and handlers while page is scrolling - if (scrolling_) - return; - - ShowHandleAndContextMenuIfRequired(); + expecting_update_ = false; } -void SelectionControllerEfl::ShowHandleAndContextMenuIfRequired() { +void SelectionControllerEfl::ShowHandleAndContextMenuIfRequired(bool anchor_first) { TRACE_EVENT0("selection,efl", __PRETTY_FUNCTION__); if (!selection_data_->GetStatus()) return; - Clear(); + gfx::Rect left, right; + if (anchor_first) { + left = selection_data_->GetLeftRect(); + right = selection_data_->GetRightRect(); + } else { + right = selection_data_->GetLeftRect(); + left = selection_data_->GetRightRect(); + } // Is in edit field and no text is selected. show only single handle - if (selection_data_->IsInEditField() && GetCaretSelectionStatus()) { + if (selection_data_->IsInEditField() && left == right) { gfx::Rect left = selection_data_->GetLeftRect(); input_handle_->SetBasePosition(gfx::Point(left.x(), left.y())); - input_handle_->SetCursorHandlerStatus(true); - input_handle_->Move(gfx::Point(left.x(), left.y() + left.height())); + input_handle_->Move(left.bottom_right()); input_handle_->Show(); + start_handle_->Hide(); + end_handle_->Hide(); if (!mouse_press_) parent_view_->ShowContextMenu(*(selection_data_->GetContextMenuParams()), MENU_TYPE_SELECTION); parent_view_->QuerySelectionStyle(); return; + } else { + input_handle_->Hide(); } - gfx::Rect left = selection_data_->GetLeftRect(); - gfx::Rect right = selection_data_->GetRightRect(); - if (left.x() == 0 && left.y() == 0 && right.x() == 0 && right.y() == 0) { selection_data_->ClearRectData(); return; } // The base position of start_handle should be set to the middle of the left rectangle. // Otherwise the start_handle may be shifted up when the right_handle is moving - start_handle_->SetBasePosition(gfx::Point(left.x(), left.y() + (left.height() / 2))); - start_handle_->Move(gfx::Point(left.x(), left.y() + left.height())); - if (left.x() >= visibility_rect_.x() && left.x() <= (visibility_rect_.x() + visibility_rect_.width())) + start_handle_->SetBasePosition(left.CenterPoint()); + start_handle_->Move(left.bottom_left()); + if (left.x() >= visibility_rect_.x() && left.x() <= visibility_rect_.right()) start_handle_->Show(); else start_handle_->Hide(); // The base position of end_handle should be set to the middle of the right rectangle. // Otherwise the end_handle may be shifted up when the left_handle is moving - end_handle_->SetBasePosition(gfx::Point(right.x(), right.y() + (right.height() / 2))); - end_handle_->Move(gfx::Point(right.x() + right.width(), right.y() + right.height())); - if (right.x() >= visibility_rect_.x() && right.x() <= (visibility_rect_.x() + visibility_rect_.width())) + end_handle_->SetBasePosition(right.CenterPoint()); + end_handle_->Move(right.bottom_right()); + if (right.x() >= visibility_rect_.x() && right.x() <= visibility_rect_.right()) end_handle_->Show(); else end_handle_->Hide(); @@ -227,6 +233,12 @@ void SelectionControllerEfl::Clear() { input_handle_->Hide(); } +bool SelectionControllerEfl::IsShowingMagnifier() { + if(magnifier_->IsShowing()) + return true; + return false; +} + void SelectionControllerEfl::OnMouseDown(const gfx::Point& touch_point) { // Hide context menu on mouse down parent_view_->CancelContextMenu(0); @@ -240,14 +252,20 @@ void SelectionControllerEfl::OnMouseMove(const gfx::Point& touch_point, Selectio // FIXME : Check the text Direction later magnifier_->UpdateLocation(touch_point); magnifier_->Move(touch_point); + expecting_update_ = true; switch (handle) { case SelectionHandleEfl::HANDLE_TYPE_INPUT: parent_view_->MoveCaret(input_handle_->GetBasePosition()); return; case SelectionHandleEfl::HANDLE_TYPE_LEFT: - parent_view_->SelectRange(end_handle_->GetBasePosition(), - start_handle_->GetBasePosition()); - return; + if (GetSelectionEditable()) { + // Form elements only support scrolling of extent/end caret. To + // move the start element we need to swap the coordinates provided + // to SelectRange function. + parent_view_->SelectRange(end_handle_->GetBasePosition(), + start_handle_->GetBasePosition()); + return; + } case SelectionHandleEfl::HANDLE_TYPE_RIGHT: parent_view_->SelectRange(start_handle_->GetBasePosition(), end_handle_->GetBasePosition()); @@ -256,10 +274,11 @@ void SelectionControllerEfl::OnMouseMove(const gfx::Point& touch_point, Selectio } void SelectionControllerEfl::OnMouseUp(const gfx::Point& touch_point) { - selection_data_->UpdateHandleData(); mouse_press_ = false; magnifier_->Hide(); - parent_view_->ShowContextMenu(*(selection_data_->GetContextMenuParams()), MENU_TYPE_SELECTION); + start_handle_->SetBasePosition(selection_data_->GetLeftRect().bottom_left()); + end_handle_->SetBasePosition(selection_data_->GetRightRect().bottom_right()); + ShowHandleAndContextMenuIfRequired(); } void SelectionControllerEfl::GetSelectionBounds(gfx::Rect* left, gfx::Rect* right) { @@ -271,6 +290,7 @@ void SelectionControllerEfl::GetSelectionBounds(gfx::Rect* left, gfx::Rect* righ void SelectionControllerEfl::HandleLongPressEvent(const gfx::Point& touch_point) { long_mouse_press_ = true; + Clear(); magnifier_->HandleLongPress(touch_point); } @@ -312,8 +332,8 @@ bool SelectionControllerEfl::IsSelectionValid(const gfx::Rect& left_rect, const // Thus the width is not sufficient for checking selection condition. // Further invesitigation showed left_rect and right_rect always have the same x,y values // for such cases. So, the equality for x and y rather than width should be tested. - if (left_rect.x()==right_rect.x() && left_rect.y()==right_rect.y() && - !selection_data_->IsInEditField() && !mouse_press_) { + if (left_rect.x() == right_rect.x() && left_rect.y() == right_rect.y() && + !selection_data_->IsInEditField() && !mouse_press_ && !expecting_update_) { SetSelectionStatus(false); return false; } diff --git a/tizen_src/impl/selection_controller_efl.h b/tizen_src/impl/selection_controller_efl.h index 519946f1a9e2..faab136e7e1c 100644 --- a/tizen_src/impl/selection_controller_efl.h +++ b/tizen_src/impl/selection_controller_efl.h @@ -77,6 +77,7 @@ class SelectionControllerEfl { // To update the selection bounds void UpdateSelectionDataAndShow(const gfx::Rect& left_rect, const gfx::Rect& right_rect, bool is_anchor_first); void GetSelectionBounds(gfx::Rect* left, gfx::Rect* right); + // Handles the mouse press,move and relase events on selection handles void OnMouseDown(const gfx::Point& touch_point); void OnMouseMove(const gfx::Point& touch_point, SelectionHandleEfl::HandleType); @@ -103,8 +104,12 @@ class SelectionControllerEfl { void ChangeContextMenuPosition(gfx::Point& position, int& drawDirection); + bool GetLongPressed() { return long_mouse_press_; } + + bool IsShowingMagnifier(); + private: - void ShowHandleAndContextMenuIfRequired(); + void ShowHandleAndContextMenuIfRequired(bool anchor_first = true); void Clear(); bool IsSelectionValid(const gfx::Rect& left_rect, const gfx::Rect& right_rect); @@ -126,6 +131,10 @@ class SelectionControllerEfl { // Saves state so that context menu is not displayed during page scrolling bool scrolling_; + // True when new caret/selection position was sent to chromium, + // but no reply was received, yet + bool expecting_update_; + // Saves state so that handlers and context menu is not shown when seletion change event occurs. bool long_mouse_press_; @@ -144,7 +153,7 @@ class SelectionControllerEfl { // Points to show the contents magnified scoped_ptr magnifier_; - // Visibility rectangle + // Rectangle inside of which selection handles should be visible. gfx::Rect visibility_rect_; }; diff --git a/tizen_src/impl/selection_handle_efl.cc b/tizen_src/impl/selection_handle_efl.cc index e0666430fb69..ddc8d19cd118 100644 --- a/tizen_src/impl/selection_handle_efl.cc +++ b/tizen_src/impl/selection_handle_efl.cc @@ -27,6 +27,8 @@ namespace content { +// Size of the left/right margin which causes selection handles to be rotated +const int kReverseMargin = 32; const char* kLeftHandlePath = "elm/entry/selection/block_handle_left"; const char* kRightHandlePath = "elm/entry/selection/block_handle_right"; const char* kInputHandlePath = "elm/entry/cursor_handle/default"; @@ -44,13 +46,12 @@ static const char* GetEdjeObjectGroupPath(SelectionHandleEfl::HandleType type) { } } -SelectionHandleEfl::SelectionHandleEfl(SelectionControllerEfl* controller, HandleType type, Evas_Object* parent) +SelectionHandleEfl::SelectionHandleEfl(SelectionControllerEfl& controller, HandleType type, Evas_Object* parent) : base_point_(0,0), current_touch_point_(0,0), diff_point_(0,0), controller_(controller), - is_cursor_handle_(false), - is_mouse_downed_(false), + pressed_(false), is_top_(false), handle_type_(type) { @@ -85,7 +86,6 @@ SelectionHandleEfl::~SelectionHandleEfl() { } void SelectionHandleEfl::Show() { - // FIXME: Currently no viewport boudry checks present. Add later evas_object_show(handle_); } @@ -98,157 +98,165 @@ bool SelectionHandleEfl::IsVisible() const { } void SelectionHandleEfl::Move(const gfx::Point& point) { - Evas_Coord x, y, deviceWidth, deviceHeight; - gfx::Rect selectionRect = GetSelectionRect(); - gfx::Point movePoint = point; - const int reverseMargin = 32; - int handleHeight; - - edje_object_part_geometry_get(handle_, "handle", 0, 0, 0, &handleHeight); - evas_object_geometry_get(controller_->GetParentView()->evas_object(), &x, &y, &deviceWidth, &deviceHeight); - - if ((handle_type_ == HANDLE_TYPE_LEFT && (movePoint.x() <= reverseMargin)) - || (handle_type_ == HANDLE_TYPE_RIGHT && (movePoint.x() >= deviceWidth - reverseMargin))) { - if ((movePoint.y() + handleHeight) > (y + deviceHeight)) { - movePoint.set_y(movePoint.y() - selectionRect.height()); - if (!is_mouse_downed_) { - ChangeObjectDirection(handle_type_, DirectionTopReverse); - is_top_ = true; - } - } else { - if (!is_mouse_downed_) { - ChangeObjectDirection(handle_type_, DirectionBottomReverse); - is_top_ = false; - } - } - } else { - if ((movePoint.y() + handleHeight) > (y + deviceHeight)) { - // Check If handler is not overLapping Device Boundary. - if ((movePoint.y() - selectionRect.height() - handleHeight) >= y) { - movePoint.set_y(movePoint.y() - selectionRect.height()); - if (!is_mouse_downed_) { - ChangeObjectDirection(handle_type_, DirectionTopNormal); - is_top_ = true; - } - MoveObject(movePoint); - return; - } - } - - if (!is_mouse_downed_) { - ChangeObjectDirection(handle_type_, DirectionBottomNormal); - is_top_ = false; - } - } - - MoveObject(movePoint); + ChangeObjectDirection(CalculateDirection(point)); + MoveObject(point); } void SelectionHandleEfl::OnMouseDown(void* data, Evas*, Evas_Object*, void* event_info) { Evas_Event_Mouse_Down* event = static_cast(event_info); SelectionHandleEfl* handle = static_cast(data); - handle->SetIsMouseDowned(true); + handle->pressed_ = true; evas_object_event_callback_add(handle->handle_, EVAS_CALLBACK_MOUSE_MOVE, OnMouseMove, handle); //Save the diff_point between touch point and base point of the handle handle->diff_point_.SetPoint(event->canvas.x - handle->base_point_.x(), event->canvas.y - handle->base_point_.y()); - handle->controller_->OnMouseDown(gfx::Point(event->canvas.x , event->canvas.y )); + handle->controller_.OnMouseDown(gfx::Point(event->canvas.x , event->canvas.y )); } void SelectionHandleEfl::OnMouseMove(void* data, Evas*, Evas_Object*, void* event_info) { Evas_Event_Mouse_Move* event = static_cast(event_info); SelectionHandleEfl* handle = static_cast(data); handle->current_touch_point_.SetPoint(event->cur.canvas.x, event->cur.canvas.y); - ecore_job_add(UpdateMouseMove, handle); + ecore_job_add(UpdateMouseMove, handle); } void SelectionHandleEfl::OnMouseUp(void* data, Evas*, Evas_Object*, void* event_info) { Evas_Event_Mouse_Up* event = static_cast(event_info); SelectionHandleEfl* handle = static_cast(data); - handle->SetIsMouseDowned(false); + handle->pressed_ = false; evas_object_event_callback_del(handle->handle_, EVAS_CALLBACK_MOUSE_MOVE, OnMouseMove); Evas_Coord x, y; - evas_object_geometry_get(handle->controller_->GetParentView()->evas_object(), &x, &y, 0, 0); - handle->controller_->OnMouseUp(gfx::Point(event->canvas.x - x, event->canvas.y - y)); + evas_object_geometry_get(handle->controller_.GetParentView()->evas_object(), &x, &y, 0, 0); + handle->controller_.OnMouseUp(gfx::Point(event->canvas.x - x, event->canvas.y - y)); } void SelectionHandleEfl::UpdateMouseMove(void* data) { SelectionHandleEfl* handle = static_cast(data); Evas_Coord x, y; - evas_object_geometry_get(handle->controller_->GetParentView()->evas_object(), &x, &y, 0, 0); - if (!handle->is_cursor_handle_) { + evas_object_geometry_get(handle->controller_.GetParentView()->evas_object(), &x, &y, 0, 0); + if (handle->handle_type_ != HANDLE_TYPE_INPUT) { //New base point calculation should be based on new touch point and diff_point int delta_x = handle->current_touch_point_.x() - handle->diff_point_.x(); int delta_y = handle->current_touch_point_.y() - handle->diff_point_.y(); handle->base_point_.SetPoint(delta_x, delta_y); - handle->controller_->OnMouseMove( + handle->controller_.OnMouseMove( gfx::Point(handle->current_touch_point_.x(), handle->current_touch_point_.y()), handle->handle_type_); } else { handle->base_point_.set_x(handle->current_touch_point_.x() - x); - handle->controller_->OnMouseMove( + handle->controller_.OnMouseMove( gfx::Point(handle->current_touch_point_.x() - x, handle->current_touch_point_.y() - y), handle->handle_type_); } } -void SelectionHandleEfl::ChangeObjectDirection(HandleType handleType, int direction) { +SelectionHandleEfl::HandleDirection SelectionHandleEfl::CalculateDirection( + const gfx::Point& point) const { + bool reverse_horizontally = false, reverse_vertically = false; + Evas_Coord x, y, deviceWidth, deviceHeight; + int handleHeight; + + edje_object_part_geometry_get(handle_, "handle", 0, 0, 0, &handleHeight); + evas_object_geometry_get(controller_.GetParentView()->evas_object(), + &x, &y, &deviceWidth, &deviceHeight); + gfx::Rect reverse_direction_rect = gfx::Rect(x + kReverseMargin, + y, deviceWidth - 2 * kReverseMargin, deviceHeight - handleHeight); + + if (!reverse_direction_rect.Contains(point)) { + if (point.x() <= reverse_direction_rect.x() || + point.x() >= reverse_direction_rect.right()) { + reverse_vertically = true; + } + if (point.y() <= reverse_direction_rect.y() || + point.y() >= reverse_direction_rect.bottom()) { + reverse_horizontally = true; + } + } + + if (handle_type_ != HANDLE_TYPE_INPUT) { + if (reverse_vertically) { + if (reverse_horizontally) { + return DirectionTopReverse; + } else { + return DirectionBottomReverse; + } + } else { + if (reverse_horizontally) { + return DirectionTopNormal; + } else { + return DirectionBottomNormal; + } + } + } else { + // Input handle can only be rotated horizontally + if (reverse_horizontally) { + return DirectionTopNormal; + } else { + return DirectionBottomNormal; + } + } + + NOTREACHED(); +} + +void SelectionHandleEfl::ChangeObjectDirection(HandleDirection direction) { TRACE_EVENT2("selection,efl", __PRETTY_FUNCTION__, - "handle type", handleType, "direction", direction); + "handle type", handle_type_, "direction", direction); + + is_top_ = (direction == DirectionTopNormal || direction == DirectionTopReverse); + switch (direction) { case DirectionBottomNormal: - if (is_cursor_handle_) + if (handle_type_ == HANDLE_TYPE_INPUT) edje_object_signal_emit(handle_, "edje,cursor,handle,show", "edje"); else edje_object_signal_emit(handle_, "elm,state,bottom", "elm"); break; case DirectionBottomReverse: - if (is_cursor_handle_) + if (handle_type_ == HANDLE_TYPE_INPUT) edje_object_signal_emit(handle_, "edje,cursor,handle,show", "edje"); else edje_object_signal_emit(handle_, "elm,state,bottom,reversed", "elm"); break; case DirectionTopNormal: - if (is_cursor_handle_) + if (handle_type_ == HANDLE_TYPE_INPUT) edje_object_signal_emit(handle_, "edje,cursor,handle,top", "edje"); else edje_object_signal_emit(handle_, "elm,state,top", "elm"); break; case DirectionTopReverse: - if (is_cursor_handle_) + if (handle_type_ == HANDLE_TYPE_INPUT) edje_object_signal_emit(handle_, "edje,cursor,handle,top", "edje"); else edje_object_signal_emit(handle_, "elm,state,top,reversed", "elm"); break; } - switch (handleType) { + switch (handle_type_) { case HANDLE_TYPE_LEFT: - evas_object_smart_callback_call(controller_->GetParentView()->evas_object(), "selection,handle,left,direction", &direction); + evas_object_smart_callback_call(controller_.GetParentView()->evas_object(), + "selection,handle,left,direction", &direction); break; case HANDLE_TYPE_RIGHT: - evas_object_smart_callback_call(controller_->GetParentView()->evas_object(), "selection,handle,right,direction", &direction); + evas_object_smart_callback_call(controller_.GetParentView()->evas_object(), + "selection,handle,right,direction", &direction); break; case HANDLE_TYPE_INPUT: - evas_object_smart_callback_call(controller_->GetParentView()->evas_object(), "selection,handle,large,direction", &direction); + evas_object_smart_callback_call(controller_.GetParentView()->evas_object(), + "selection,handle,large,direction", &direction); break; } - handle_type_ = handleType; -} - -SelectionHandleEfl::HandleType SelectionHandleEfl::GetHandleType() const { - return handle_type_; } -gfx::Rect SelectionHandleEfl::GetSelectionRect() { +gfx::Rect SelectionHandleEfl::GetSelectionRect() const { gfx::Rect rect; switch(handle_type_) { case HANDLE_TYPE_RIGHT: - return controller_->GetRightRect(); + return controller_.GetRightRect(); case HANDLE_TYPE_LEFT: - return controller_->GetLeftRect(); + return controller_.GetLeftRect(); case HANDLE_TYPE_INPUT: // no rect for this type of handle @@ -258,10 +266,10 @@ gfx::Rect SelectionHandleEfl::GetSelectionRect() { return gfx::Rect(); } -void SelectionHandleEfl::MoveObject(gfx::Point& point) { +void SelectionHandleEfl::MoveObject(const gfx::Point& point) { Evas_Coord x, y; - evas_object_geometry_get(controller_->GetParentView()->evas_object(), &x, &y, 0, 0); + evas_object_geometry_get(controller_.GetParentView()->evas_object(), &x, &y, 0, 0); evas_object_move(handle_, point.x() + x, point.y() + y); } -} +} // namespace content diff --git a/tizen_src/impl/selection_handle_efl.h b/tizen_src/impl/selection_handle_efl.h index bfca980235ec..edd64fec9ca5 100644 --- a/tizen_src/impl/selection_handle_efl.h +++ b/tizen_src/impl/selection_handle_efl.h @@ -55,7 +55,7 @@ class SelectionHandleEfl { DirectionNone, }; - SelectionHandleEfl(SelectionControllerEfl* controller, HandleType type, Evas_Object* parent); + SelectionHandleEfl(SelectionControllerEfl& controller, HandleType type, Evas_Object* parent); ~SelectionHandleEfl(); void Show(); void Hide(); @@ -63,7 +63,6 @@ class SelectionHandleEfl { void Move(const gfx::Point& point); void SetBasePosition(const gfx::Point& point) { base_point_ = point; } gfx::Point GetBasePosition() const { return base_point_; } - void SetCursorHandlerStatus(bool enable) { is_cursor_handle_ = enable; } bool IsTop() { return is_top_; } Evas_Object* evas_object() const { return handle_; } @@ -73,11 +72,10 @@ class SelectionHandleEfl { static void OnMouseUp(void* data, Evas*, Evas_Object*, void* event_info); static void UpdateMouseMove(void* data); - void ChangeObjectDirection(HandleType, int); - HandleType GetHandleType() const; - gfx::Rect GetSelectionRect(); - void MoveObject(gfx::Point&); - void SetIsMouseDowned(bool enable) { is_mouse_downed_ = enable; }; + HandleDirection CalculateDirection(const gfx::Point&) const; + void ChangeObjectDirection(HandleDirection direction); + gfx::Rect GetSelectionRect() const; + void MoveObject(const gfx::Point& point); // This point is one which will be used during extending selection // it is in web view coordinates @@ -91,16 +89,13 @@ class SelectionHandleEfl { gfx::Point diff_point_; // Parent to send back mouse events - content::SelectionControllerEfl* controller_; + SelectionControllerEfl& controller_; // Handler object Evas_Object* handle_; - // Is set if the handle is of type input - bool is_cursor_handle_; - - // Is mouse down - bool is_mouse_downed_; + // Is pressed + bool pressed_; // Direction of handle bool is_top_; diff --git a/tizen_src/impl/selection_magnifier_efl.cc b/tizen_src/impl/selection_magnifier_efl.cc index 18662957b655..490a5f327916 100644 --- a/tizen_src/impl/selection_magnifier_efl.cc +++ b/tizen_src/impl/selection_magnifier_efl.cc @@ -36,7 +36,8 @@ const float kZoomScale = 0.66; SelectionMagnifierEfl::SelectionMagnifierEfl(content::SelectionControllerEfl* controller) : controller_(controller), content_image_(0), - animator_(0) { + animator_(0), + shown_(false) { Evas_Object* top_widget = elm_object_top_widget_get( elm_object_parent_widget_get(controller->GetParentView()->evas_object())); if (!top_widget) @@ -177,12 +178,14 @@ void SelectionMagnifierEfl::Move(const gfx::Point& location) { } void SelectionMagnifierEfl::Show() { + shown_ = true; evas_object_show(container_); controller_->GetParentView()->SmartCallback().call(); controller_->GetParentView()->set_magnifier(true); } void SelectionMagnifierEfl::Hide() { + shown_ = false; evas_object_hide(content_image_); evas_object_hide(container_); controller_->GetParentView()->SmartCallback().call(); diff --git a/tizen_src/impl/selection_magnifier_efl.h b/tizen_src/impl/selection_magnifier_efl.h index 381442be359d..7addb98630ce 100644 --- a/tizen_src/impl/selection_magnifier_efl.h +++ b/tizen_src/impl/selection_magnifier_efl.h @@ -42,6 +42,7 @@ class SelectionMagnifierEfl { void Move(const gfx::Point& location); void Show(); void Hide(); + bool IsShowing() { return shown_; } private: static Eina_Bool MoveAnimatorCallback(void* data); @@ -64,6 +65,9 @@ class SelectionMagnifierEfl { // Handle longmove Ecore_Animator* animator_; + + // Is magnifier showing + bool shown_; }; }