#include "base/strings/utf_string_conversions.h"
#include "content/browser/renderer_host/render_widget_host_impl.h"
#include "browser/renderer_host/render_widget_host_view_efl.h"
-#include "ui/gfx/rect.h"
#include <Ecore_Evas.h>
#include <Ecore_IMF_Evas.h>
Eina_Rectangle rect;
ecore_imf_context_input_panel_geometry_get(context_, &rect.x, &rect.y, &rect.w, &rect.h);
view_->eweb_view()->SmartCallback<EWebViewCallbacks::IMEInputMethodChanged>().call(&rect);
+
+ SetIMERect(gfx::Rect(rect.x, rect.y, rect.w, rect.h));
}
void IMContextEfl::OnCandidateInputPanelStateChanged(int state) {
composition_.Clear();
}
+bool IMContextEfl::IsShow() {
+ return (context_ && focused_ && ecore_imf_context_input_panel_state_get(context_) != ECORE_IMF_INPUT_PANEL_STATE_HIDE);
+}
+
} // namespace content
#include "ui/base/ime/text_input_mode.h"
#include "ui/base/ime/text_input_type.h"
#include "ui/base/ime/composition_text.h"
+#include "ui/gfx/rect.h"
#include <Evas.h>
void CancelComposition();
void ConfirmComposition();
void SetIsInFormTag(bool is_in_form_tag);
+ bool IsShow();
+ gfx::Rect GetIMERect() const { return ime_rect_; }
private:
IMContextEfl(RenderWidgetHostViewEfl*, Ecore_IMF_Context*);
void ShowPanel(ui::TextInputType, ui::TextInputMode, bool is_user_action = false);
void HidePanel();
+ void SetIMERect(const gfx::Rect& rect) { ime_rect_ = rect; }
+
// callbacks
static void IMFCommitCallback(void* data, Ecore_IMF_Context*, void* event_info) { reinterpret_cast<IMContextEfl*>(data)->OnCommit(event_info); }
static void IMFPreeditChangedCallback(void* data, Ecore_IMF_Context* context, void* event_info) { reinterpret_cast<IMContextEfl*>(data)->OnPreeditChanged(data, context, event_info); }
bool is_in_form_tag_;
ui::CompositionText composition_;
+
+ gfx::Rect ime_rect_;
};
} // namespace content
#include "content/browser/compositor/owned_mailbox.h"
#include "ui/base/ime/text_input_client.h"
#include "eweb_view.h"
+#include "browser/renderer_host/im_context_efl.h"
#include <Evas.h>
#include <Ecore_Evas.h>
#include <Evas_GL.h>
void set_eweb_view(EWebView*);
EWebView* eweb_view() const { return web_view_; }
RenderWidgetHostImpl* host() const { return host_; }
+ IMContextEfl* im_context() const { return im_context_; }
float device_scale_factor() const { return device_scale_factor_; }
}
bool ContextMenuControllerEfl::PopulateAndShowContextMenu(const ContextMenuParams ¶ms) {
+ LOG(INFO) << __PRETTY_FUNCTION__;
EWebView* view = ToEWebView(evas_object_);
if (!view)
return false;
if (!popup_)
return false;
- evas_object_move(popup_, params_.x, params_.y);
-#if defined(OS_TIZEN)
- // In device context menu is supported as per the platform efl theme.
- // So this supports horizontal popup and on this popup style is applied.
- // But style is not there on desktop version so using default provided by efl
+ LOG(INFO) << __PRETTY_FUNCTION__ << "param.x = " << params_.x << " params.y = " << params_.y;
+
if (type_ == MENU_TYPE_SELECTION) {
- elm_ctxpopup_horizontal_set(popup_, EINA_TRUE);
- elm_ctxpopup_direction_priority_set(popup_,
- ELM_CTXPOPUP_DIRECTION_UP,
- ELM_CTXPOPUP_DIRECTION_DOWN,
- ELM_CTXPOPUP_DIRECTION_LEFT,
- ELM_CTXPOPUP_DIRECTION_RIGHT);
+ int webViewX, webViewY, webViewWidth, webViewHeight;
+ Evas_Point point;
+
+ gfx::Point popupPosition = gfx::Point(params_.x, params_.y);
+
+ EWebView* view = ToEWebView(evas_object_);
+ if (!view)
+ return false;
+
+ evas_object_geometry_get(view->evas_object(), &webViewX, &webViewY, &webViewWidth, &webViewHeight);
+ popupPosition.set_x(popupPosition.x() + webViewX);
+ popupPosition.set_y(popupPosition.y() + webViewY);
+
+ point.x = popupPosition.x();
+ point.y = popupPosition.y();
+
+ evas_object_smart_callback_call(view->evas_object(), "contextmenu,willshow", &point);
+
+ bool allowed = true;
+ evas_object_smart_callback_call(view->evas_object(), "contextmenu,allowed", &allowed);
+ if (!allowed) {
+ evas_object_del(popup_);
+ return false;
+ }
+
elm_object_style_set(popup_, "copypaste");
- }
+ elm_ctxpopup_horizontal_set(popup_, EINA_TRUE);
+
+ int drawDirection;
+ SelectionControllerEfl* controller = view->GetSelectionController();
+
+ if (!controller) {
+ evas_object_del(popup_);
+ return false;
+ }
+
+ controller->ChangeContextMenuPosition(popupPosition, drawDirection);
+ switch(drawDirection) {
+ case 0:
+ elm_ctxpopup_direction_priority_set(popup_, ELM_CTXPOPUP_DIRECTION_DOWN, ELM_CTXPOPUP_DIRECTION_DOWN, ELM_CTXPOPUP_DIRECTION_DOWN, ELM_CTXPOPUP_DIRECTION_DOWN);
+ break;
+ case 1:
+ elm_ctxpopup_direction_priority_set(popup_, ELM_CTXPOPUP_DIRECTION_UP, ELM_CTXPOPUP_DIRECTION_UP, ELM_CTXPOPUP_DIRECTION_UP, ELM_CTXPOPUP_DIRECTION_UP);
+ break;
+ case 2:
+ elm_ctxpopup_direction_priority_set(popup_, ELM_CTXPOPUP_DIRECTION_LEFT, ELM_CTXPOPUP_DIRECTION_LEFT, ELM_CTXPOPUP_DIRECTION_LEFT, ELM_CTXPOPUP_DIRECTION_LEFT);
+ break;
+ case 3:
+ elm_ctxpopup_direction_priority_set(popup_, ELM_CTXPOPUP_DIRECTION_RIGHT, ELM_CTXPOPUP_DIRECTION_RIGHT, ELM_CTXPOPUP_DIRECTION_RIGHT, ELM_CTXPOPUP_DIRECTION_RIGHT);
+ break;
+ default:
+ elm_ctxpopup_direction_priority_set(popup_, ELM_CTXPOPUP_DIRECTION_UP, ELM_CTXPOPUP_DIRECTION_DOWN, ELM_CTXPOPUP_DIRECTION_LEFT, ELM_CTXPOPUP_DIRECTION_RIGHT);
+ };
+ evas_object_move(popup_, popupPosition.x(), popupPosition.y());
+#ifdef OS_TIZEN_MOBILE
+ elm_ctxpopup_auto_hide_disabled_set(popup_, EINA_TRUE);
#endif
+ } else {
+ evas_object_move(popup_, params_.x, params_.y);
+ }
evas_object_smart_callback_add(popup_, "dismissed", contextMenuCancelCallback, 0);
evas_object_show(popup_);
return true;
web_contents_delegate()->web_contents()->DidChooseColorInColorChooser(SkColorSetARGB(a, r, g, b));
return true;
}
+
+bool EWebView::IsIMEShow() {
+ return rwhv()->im_context()->IsShow();
+}
+
+gfx::Rect EWebView::GetIMERect() {
+ return rwhv()->im_context()->GetIMERect();
+}
scoped_refptr<EdgeEffect> edgeEffect() { return edge_effect_; }
#endif
+ bool IsIMEShow();
+ gfx::Rect GetIMERect();
+
private:
EWebView(EWebContext*, Evas_Object* smart_object);
~EWebView();
#include "selection_box_efl.h"
#include "selection_magnifier_efl.h"
+#include <Edje.h>
+
namespace content {
+const int menuHeight = 140;// The Height fo the context menu.
+const int menuPadding = 60;// This is padding for deciding when to modify context menu position.
+//const int spacePadding = 24;// This is for making context menu closer to the handles.
+const int spacePadding = 0;// This is for making context menu closer to the handles.
+const int textSelectionScrollSize = 50;// Scroll step when selection handler is moving out of viewport.
+static int s_magnifierMaxYOffsetDelta = 50;// Magnifier should not show the image below the viewport
+static int s_textSelectionMargin = 5;
+
static bool IsRectEmpty(const gfx::Rect& rect) {
if (rect.x() == 0 && rect.y() == 0 && rect.height() == 0 && rect.width() == 0) {
LOG(INFO) << "SelectionControllerEfl:IsRectEmpty : true";
return selection_data_->GetRightRect();
}
+void SelectionControllerEfl::ChangeContextMenuPosition(gfx::Point& position, int& drawDirection) {
+ drawDirection = DirectionNone; // Giving default Direction.
+ int handleHeight, webViewX, webViewY, webViewWidth, webViewHeight;
+ gfx::Rect imeRect;
+ edje_object_part_geometry_get(input_handle_->evas_object(), "handle", 0, 0, 0, &handleHeight);
+ evas_object_geometry_get(GetParentView()->evas_object(), &webViewX, &webViewY, &webViewWidth, &webViewHeight);
+ gfx::Rect viewportRect = gfx::Rect(webViewX, webViewY, webViewWidth, webViewHeight);
+
+ if (GetParentView()->IsIMEShow()) { // Get the Visible Rect .
+ imeRect = GetParentView()->GetIMERect();
+ if ((viewportRect.y() + viewportRect.height()) > imeRect.y())
+ viewportRect.set_height(imeRect.y() - viewportRect.y());
+ }
+
+ gfx::Rect leftHandleRect = selection_data_->GetLeftRect();
+ leftHandleRect.set_x(webViewX + leftHandleRect.x());
+ leftHandleRect.set_y(webViewY + leftHandleRect.y());
+
+ if (!GetCaretSelectionStatus()) {
+ gfx::Rect rightHandleRect = selection_data_->GetRightRect();
+ rightHandleRect.set_x(webViewX + rightHandleRect.x());
+ rightHandleRect.set_y(webViewY + rightHandleRect.y());
+ gfx::Rect oldLeftHandleRect = leftHandleRect;
+ gfx::Rect oldRightHandleRect = rightHandleRect;
+ gfx::Rect effectiveRect;
+ bool isEffecrtiveRectAvailable = false;
+
+ bool isTop = false;
+ bool isRightHandle = false;
+ bool doConsiderRightHandle = false;
+ bool doNotConsiderMenuUpward = false;
+
+ //if (leftHandleRect.x() < 0)
+ // leftHandleRect.set_x(0);
+ //if (leftHandleRect.y() < 0)
+ // leftHandleRect.set_y(0);
+
+ // Giving first preference to left handle.
+ if (leftHandleRect.IsEmpty() && viewportRect.Contains(leftHandleRect.x(), leftHandleRect.y())) {
+ isTop = start_handle_->IsTop();
+ effectiveRect = leftHandleRect;
+ isEffecrtiveRectAvailable = true;
+ // Check whether Menu will overlap the right handle or not.
+ if (leftHandleRect != rightHandleRect) {
+ if (!isTop) {
+ // If there is sufficient space above the handler that Menu can be placed. then shift context menu
+ // then no need to change effectiveRect from leftHandleRect to rightHandleRect.
+ bool directionUp = effectiveRect.y() - menuHeight > viewportRect.y() && (effectiveRect.y() - (viewportRect.y() + menuHeight) > menuPadding);
+ if (!directionUp && ((leftHandleRect.y() + leftHandleRect.height()) + menuHeight) > rightHandleRect.y()) {
+ doConsiderRightHandle = true;
+ doNotConsiderMenuUpward = true; // As if we draw the direction is UP it will overlap with left Handle.
+ }
+ }
+ }
+ } else {
+ doConsiderRightHandle = true;
+ }
+
+ if (doConsiderRightHandle && rightHandleRect.IsEmpty() && viewportRect.Contains(rightHandleRect.x(), rightHandleRect.y())) {
+ effectiveRect = rightHandleRect;
+ isEffecrtiveRectAvailable = true;
+ isTop = end_handle_->IsTop();
+ isRightHandle = true;
+ }
+
+ if (isEffecrtiveRectAvailable) {
+ //We will go for UpWard, DownWard, Left, Right directions.
+ if (effectiveRect.y() - menuHeight > viewportRect.y() && (effectiveRect.y() - (viewportRect.y() + menuHeight) > menuPadding) && !doNotConsiderMenuUpward) {
+ if (isTop) {
+ if (isRightHandle) {
+ position.set_y(effectiveRect.y() - spacePadding - handleHeight);
+ } else {
+ position.set_y(effectiveRect.y() - spacePadding - handleHeight);
+ //position.set_y(position.y() - effectiveRect.height());
+ }
+ } else {
+ position.set_y(effectiveRect.y() - spacePadding);
+ }
+ drawDirection = DirectionUp;
+ } else if ((effectiveRect.y() + effectiveRect.height()) + menuHeight < (viewportRect.y() + viewportRect.height())) {
+ position.set_y((effectiveRect.y() + effectiveRect.height()) - spacePadding + handleHeight);
+ drawDirection = DirectionDown;
+ } else if (effectiveRect.x() < (viewportRect.x() + viewportRect.width()/2)) {
+ position.set_x((effectiveRect.x() + effectiveRect.width()) + spacePadding + handleHeight);
+ position.set_y(effectiveRect.CenterPoint().y());
+ drawDirection = DirectionLeft;
+ } else {
+ position.set_x(effectiveRect.x());
+ position.set_y(effectiveRect.CenterPoint().y());
+ drawDirection = DirectionRight;
+ }
+ } else {
+ if (oldLeftHandleRect.y() < viewportRect.y() && oldRightHandleRect.y() > (viewportRect.y() + viewportRect.height()) && viewportRect.height() <= webViewHeight) {
+ position.set_y(viewportRect.CenterPoint().y() - spacePadding);
+ } else {
+ position.set_y(position.y() + spacePadding + handleHeight);// This value is chosen based on the how much close the context menu arrow should come to word.
+ }
+ drawDirection = DirectionNone;
+ }
+
+ return;
+ }
+
+ if (!selection_data_->IsInEditField())
+ return;
+
+ position.set_y(leftHandleRect.y() - spacePadding);
+
+ if (input_handle_->IsTop()) {
+ position.set_y(position.y() - leftHandleRect.height() - handleHeight);
+ return;
+ }
+
+ // The Width of the context menu is menuHeight so comapairing current position with the viewport point plus menuHeight.
+ // If position is less than this value then set new position for the contextmenu.
+ if ((position.y() <= (webViewY + menuHeight)) || ((position.y() - (webViewY + menuHeight)) <= menuPadding)) {
+ if (leftHandleRect.IsEmpty()) {
+ position.set_y(position.y() + spacePadding + handleHeight);// This value is chosen based on the how much close the context menu arrow should come to word.
+ drawDirection = DirectionDown;
+ return;
+ }
+
+ position.set_y((leftHandleRect.y() + leftHandleRect.height()) - spacePadding + handleHeight);
+ drawDirection = DirectionDown;
+ return;
+ }
+
+ return;
+}
+
}
// Hnadlers are shown to extent selection, On handler move touch points are sent to engine
// by SelectRange to extend the selection
class SelectionControllerEfl {
+
+ enum ContextMenuDirection {
+ DirectionDown = 0,
+ DirectionUp,
+ DirectionLeft,
+ DirectionRight,
+ DirectionNone,
+ };
+
public:
explicit SelectionControllerEfl(EWebView* parent_view);
gfx::Rect GetLeftRect();
gfx::Rect GetRightRect();
+ void ChangeContextMenuPosition(gfx::Point& position, int& drawDirection);
+
private:
void ShowHandleAndContextMenuIfRequired();
void Clear();
diff_point_(0,0),
controller_(controller),
is_cursor_handle_(false),
- is_mouse_downed_(false) {
+ is_mouse_downed_(false),
+ is_top_(false) {
Evas* evas = evas_object_evas_get(parent);
handle_ = edje_object_add(evas);
|| (handleType == HANDLE_TYPE_RIGHT && (movePoint.x() >= deviceWidth - reverseMargin))) {
if ((movePoint.y() + handleHeight) > (y + deviceHeight)) {
movePoint.set_y(movePoint.y() - selectionRect.height());
- if (!is_mouse_downed_)
+ if (!is_mouse_downed_) {
ChangeObjectDirection(handleType, DirectionTopReverse);
+ is_top_ = true;
+ }
} else {
- if (!is_mouse_downed_)
+ if (!is_mouse_downed_) {
ChangeObjectDirection(handleType, DirectionBottomReverse);
+ is_top_ = false;
+ }
}
} else {
if ((movePoint.y() + handleHeight) > (y + deviceHeight)) {
ChangeObjectDirection(handleType, DirectionTopNormal);
else
ChangeObjectDirection(handleType, DirectionTopNormal);
+ is_top_ = true;
}
MoveObject(movePoint);
return;
ChangeObjectDirection(handleType, DirectionBottomNormal);
else
ChangeObjectDirection(handleType, DirectionBottomNormal);
+ is_top_ = false;
}
}
DirectionTopReverse,
};
+ enum ContextMenuDirection {
+ DirectionDown,
+ DirectionUp,
+ DirectionLeft,
+ DirectionRight,
+ DirectionNone,
+ };
+
SelectionHandleEfl(SelectionControllerEfl* controller, HandleType type, Evas_Object* parent);
~SelectionHandleEfl();
void Show();
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_; }
private:
static void OnMouseDown(void* data, Evas*, Evas_Object*, void* event_info);
// Is mouse down
bool is_mouse_downed_;
+
+ // Direction of handle
+ bool is_top_;
};
} // namespace