#ifndef UI_TOUCH_SELECTION_TOUCH_SELECTION_CONTROLLER_H_
#define UI_TOUCH_SELECTION_TOUCH_SELECTION_CONTROLLER_H_
#include "base/memory/raw_ptr.h"
#include "base/time/time.h"
#include "ui/events/types/event_type.h"
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/geometry/point_f.h"
#include "ui/gfx/geometry/rect_f.h"
#include "ui/gfx/geometry/vector2d_f.h"
#include "ui/gfx/native_ui_types.h"
#include "ui/gfx/selection_bound.h"
#include "ui/touch_selection/longpress_drag_selector.h"
#include "ui/touch_selection/selection_event_type.h"
#include "ui/touch_selection/touch_handle.h"
#include "ui/touch_selection/touch_handle_orientation.h"
#include "ui/touch_selection/ui_touch_selection_export.h"
#include "arkweb/build/features/features.h"
#if BUILDFLAG(IS_ANDROID)
namespace cc::slim {
class Layer;
}
#endif
namespace ui {
class MotionEvent;
#if BUILDFLAG(IS_ARKWEB)
class TouchSelectionControllerExt;
class TouchSelectionControllerUtils;
#endif
class UI_TOUCH_SELECTION_EXPORT TouchSelectionControllerClient {
public:
virtual ~TouchSelectionControllerClient() {}
virtual bool SupportsAnimation() const = 0;
virtual void SetNeedsAnimate() = 0;
virtual void MoveCaret(const gfx::PointF& position) = 0;
virtual void MoveRangeSelectionExtent(const gfx::PointF& extent) = 0;
virtual void SelectBetweenCoordinates(const gfx::PointF& base,
const gfx::PointF& extent) = 0;
virtual void OnSelectionEvent(SelectionEventType event) = 0;
virtual void OnDragUpdate(const TouchSelectionDraggable::Type type,
const gfx::PointF& position) = 0;
virtual std::unique_ptr<TouchHandleDrawable> CreateDrawable() = 0;
virtual void DidScroll() = 0;
virtual void ShowTouchSelectionContextMenu(const gfx::Point& location) {}
#if BUILDFLAG(ARKWEB_MENU)
virtual void SelectBetweenCoordinatesV2(const gfx::PointF& position, bool is_base) {}
virtual void NotifyShowMagnifier() {}
virtual bool IsShowHandle() { return false; }
#endif
#if BUILDFLAG(ARKWEB_PDF)
virtual void ClearTextSelection() {}
virtual void OnScaleChanged(float new_page_scale_factor) {}
#endif
};
class UI_TOUCH_SELECTION_EXPORT TouchSelectionController
: public TouchHandleClient,
public LongPressDragSelectorClient {
public:
enum ActiveStatus {
INACTIVE,
INSERTION_ACTIVE,
SELECTION_ACTIVE,
};
struct UI_TOUCH_SELECTION_EXPORT Config {
base::TimeDelta max_tap_duration = base::Milliseconds(300);
float tap_slop = 8;
bool enable_adaptive_handle_orientation = false;
bool enable_longpress_drag_selection = false;
bool hide_active_handle = false;
};
TouchSelectionController(TouchSelectionControllerClient* client,
const Config& config);
TouchSelectionController(const TouchSelectionController&) = delete;
TouchSelectionController& operator=(const TouchSelectionController&) = delete;
~TouchSelectionController() override;
#if BUILDFLAG(IS_ARKWEB)
friend class TouchSelectionControllerExt;
virtual TouchSelectionControllerExt* AsTouchSelectionControllerExt() {
return nullptr;
}
void UpdateSelectionChanged(
const TouchSelectionDraggable& draggable) override {}
gfx::PointF GetSelectionTop() const override { return start().edge_start(); }
#endif
void OnSelectionBoundsChanged(const gfx::SelectionBound& start,
const gfx::SelectionBound& end);
void OnViewportChanged(const gfx::RectF viewport_rect);
bool WillHandleTouchEvent(const MotionEvent& event);
void HandleTapEvent(const gfx::PointF& location, int tap_count);
void HandleLongPressEvent(base::TimeTicks event_time,
const gfx::PointF& location);
void HandleDoublePressEvent(base::TimeTicks event_time,
const gfx::PointF& location);
void OnScrollBeginEvent();
#if BUILDFLAG(IS_ANDROID)
void OnUpdateNativeViewTree(gfx::NativeView parent_native_view,
cc::slim::Layer* parent_layer);
#endif
#if BUILDFLAG(IS_ANDROID)
void HandleSwipeToMoveCursorGestureAck(
ui::EventType type,
const gfx::PointF& point,
const std::optional<bool>& cursor_control,
bool is_in_root_view);
#endif
void HideAndDisallowShowingAutomatically();
void SetTemporarilyHidden(bool hidden);
bool Animate(base::TimeTicks animate_time);
const gfx::SelectionBound& GetFocusBound() const;
gfx::RectF GetRectBetweenBounds() const;
gfx::RectF GetVisibleRectBetweenBounds() const;
gfx::RectF GetStartHandleRect() const;
gfx::RectF GetEndHandleRect() const;
float GetTouchHandleHeight() const;
const gfx::PointF& GetStartPosition() const;
const gfx::PointF& GetEndPosition() const;
void OnSwipeToMoveCursorBegin();
void OnSwipeToMoveCursorEnd();
const gfx::SelectionBound& start() const { return start_; }
const gfx::SelectionBound& end() const { return end_; }
ActiveStatus active_status() const { return active_status_; }
#if BUILDFLAG(ARKWEB_MENU)
bool IsShowHandle() override;
#endif
private:
friend class TouchSelectionControllerTestApi;
enum InputEventType { TAP, REPEATED_TAP, LONG_PRESS, INPUT_EVENT_TYPE_NONE };
enum class DragSelectorInitiatingGesture { kNone, kLongPress, kDoublePress };
bool WillHandleTouchEventImpl(const MotionEvent& event);
void OnDragBegin(const TouchSelectionDraggable& draggable,
const gfx::PointF& drag_position) override;
void OnDragUpdate(const TouchSelectionDraggable& draggable,
const gfx::PointF& drag_position) override;
void OnDragEnd(const TouchSelectionDraggable& draggable) override;
bool IsWithinTapSlop(const gfx::Vector2dF& delta) const override;
void OnHandleTapped(const TouchHandle& handle) override;
void SetNeedsAnimate() override;
std::unique_ptr<TouchHandleDrawable> CreateDrawable() override;
base::TimeDelta GetMaxTapDuration() const override;
bool IsAdaptiveHandleOrientationEnabled() const override;
void OnLongPressDragActiveStateChanged() override;
gfx::PointF GetSelectionStart() const override;
gfx::PointF GetSelectionEnd() const override;
void OnInsertionChanged();
void OnSelectionChanged();
bool ActivateInsertionIfNecessary();
void DeactivateInsertion();
bool ActivateSelectionIfNecessary();
void DeactivateSelection();
void UpdateHandleLayoutIfNecessary();
bool WillHandleTouchEventForLongPressDrag(const MotionEvent& event);
void SetTemporarilyHiddenForLongPressDrag(bool hidden);
void RefreshHandleVisibility();
float GetActiveHandleMiddleY() const;
void HideHandles();
gfx::Vector2dF GetStartLineOffset() const;
gfx::Vector2dF GetEndLineOffset() const;
bool GetStartVisible() const;
bool GetEndVisible() const;
TouchHandle::AnimationStyle GetAnimationStyle(bool was_active) const;
void LogDragType(const TouchSelectionDraggable& draggable);
const raw_ptr<TouchSelectionControllerClient, DanglingUntriaged> client_;
const Config config_;
InputEventType response_pending_input_event_;
gfx::SelectionBound start_;
gfx::SelectionBound end_;
TouchHandleOrientation start_orientation_;
TouchHandleOrientation end_orientation_;
ActiveStatus active_status_;
std::unique_ptr<TouchHandle> insertion_handle_;
std::unique_ptr<TouchHandle> start_selection_handle_;
std::unique_ptr<TouchHandle> end_selection_handle_;
bool temporarily_hidden_;
bool anchor_drag_to_selection_start_;
LongPressDragSelector longpress_drag_selector_;
DragSelectorInitiatingGesture drag_selector_initiating_gesture_ =
DragSelectorInitiatingGesture::kNone;
gfx::RectF viewport_rect_;
bool selection_handle_dragged_;
bool consume_touch_sequence_;
bool show_touch_handles_;
bool swipe_to_move_cursor_activated_ = false;
#if BUILDFLAG(ARKWEB_MENU)
bool is_first_drag_ = false;
#endif
#if BUILDFLAG(IS_ARKWEB)
std::unique_ptr<TouchSelectionControllerUtils> utils_;
#endif
};
}
#if BUILDFLAG(IS_ARKWEB)
#include "arkweb/chromium_ext/ui/touch_selection/touch_selection_controller_ext.h"
#endif
#endif