2014-06-03 11:08:45 +04:00
|
|
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
|
|
/* vim: set ts=2 sw=2 et tw=78: */
|
|
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
|
|
|
|
#ifndef mozilla_TouchCaret_h__
|
|
|
|
#define mozilla_TouchCaret_h__
|
|
|
|
|
|
|
|
#include "nsISelectionListener.h"
|
|
|
|
#include "nsIScrollObserver.h"
|
|
|
|
#include "nsIWeakReferenceUtils.h"
|
|
|
|
#include "nsITimer.h"
|
|
|
|
#include "mozilla/EventForwards.h"
|
|
|
|
#include "mozilla/TouchEvents.h"
|
|
|
|
#include "Units.h"
|
|
|
|
|
2014-10-14 05:07:00 +04:00
|
|
|
class nsCanvasFrame;
|
2014-08-06 09:19:25 +04:00
|
|
|
class nsIFrame;
|
|
|
|
class nsIPresShell;
|
|
|
|
|
2014-06-03 11:08:45 +04:00
|
|
|
namespace mozilla {
|
|
|
|
|
|
|
|
/**
|
2014-07-27 02:13:00 +04:00
|
|
|
* The TouchCaret places a touch caret according to caret position when the
|
2014-06-03 11:08:45 +04:00
|
|
|
* caret is shown.
|
|
|
|
* TouchCaret is also responsible for touch caret visibility. Touch caret
|
|
|
|
* won't be shown when timer expires or while key event causes selection change.
|
|
|
|
*/
|
|
|
|
class TouchCaret MOZ_FINAL : public nsISelectionListener
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
explicit TouchCaret(nsIPresShell* aPresShell);
|
|
|
|
|
|
|
|
NS_DECL_ISUPPORTS
|
|
|
|
NS_DECL_NSISELECTIONLISTENER
|
|
|
|
|
|
|
|
void Terminate()
|
|
|
|
{
|
|
|
|
mPresShell = nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Handle mouse and touch event only.
|
|
|
|
* Depends on visibility and position of touch caret, HandleEvent may consume
|
|
|
|
* that input event and return nsEventStatus_eConsumeNoDefault to the caller.
|
|
|
|
* In that case, caller should stop bubble up that input event.
|
|
|
|
*/
|
|
|
|
nsEventStatus HandleEvent(WidgetEvent* aEvent);
|
|
|
|
|
2014-07-27 02:15:00 +04:00
|
|
|
void SyncVisibilityWithCaret();
|
2014-06-03 11:08:45 +04:00
|
|
|
|
2014-07-27 02:15:00 +04:00
|
|
|
void UpdatePositionIfNeeded();
|
2014-06-03 11:08:45 +04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* GetVisibility will get the visibility of the touch caret.
|
|
|
|
*/
|
|
|
|
bool GetVisibility() const
|
|
|
|
{
|
|
|
|
return mVisible;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
// Hide default constructor.
|
|
|
|
TouchCaret() MOZ_DELETE;
|
|
|
|
|
2014-07-27 02:13:00 +04:00
|
|
|
~TouchCaret();
|
|
|
|
|
2014-07-27 02:15:00 +04:00
|
|
|
bool IsDisplayable();
|
|
|
|
|
|
|
|
void UpdatePosition();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* SetVisibility will set the visibility of the touch caret.
|
|
|
|
* SetVisibility performs an attribute-changed notification which could, in
|
|
|
|
* theory, destroy frames.
|
|
|
|
*/
|
|
|
|
void SetVisibility(bool aVisible);
|
|
|
|
|
2014-10-07 05:02:00 +04:00
|
|
|
/**
|
|
|
|
* Helper function to get caret's focus frame and caret's bounding rect.
|
|
|
|
*/
|
|
|
|
nsIFrame* GetCaretFocusFrame(nsRect* aOutRect = nullptr);
|
|
|
|
|
2014-06-03 11:08:45 +04:00
|
|
|
/**
|
|
|
|
* Find the nsCanvasFrame which holds the touch caret.
|
|
|
|
*/
|
2014-10-14 05:07:00 +04:00
|
|
|
nsCanvasFrame* GetCanvasFrame();
|
2014-06-03 11:08:45 +04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Retrieve the bounding rectangle of the touch caret.
|
|
|
|
*
|
|
|
|
* @returns A nsRect representing the bounding rectangle of this touch caret.
|
|
|
|
* The returned offset is relative to the canvas frame.
|
|
|
|
*/
|
|
|
|
nsRect GetTouchFrameRect();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Retrieve the bounding rectangle where the caret can be positioned.
|
|
|
|
* If we're positioning a caret in an input field, make sure the touch caret
|
|
|
|
* stays within the bounds of the field.
|
|
|
|
*
|
|
|
|
* @returns A nsRect representing the bounding rectangle of this valid area.
|
|
|
|
* The returned offset is relative to the canvas frame.
|
|
|
|
*/
|
|
|
|
nsRect GetContentBoundary();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Retrieve the center y position of the caret.
|
|
|
|
* The returned point is relative to the canvas frame.
|
|
|
|
*/
|
|
|
|
nscoord GetCaretYCenterPosition();
|
|
|
|
|
2014-10-15 05:05:00 +04:00
|
|
|
/**
|
|
|
|
* Retrieve the position of the touch caret.
|
|
|
|
* The returned point is relative to the canvas frame.
|
|
|
|
*/
|
|
|
|
nsPoint GetTouchCaretPosition();
|
|
|
|
|
2014-10-17 00:03:00 +04:00
|
|
|
/**
|
|
|
|
* Check whether nsCaret shows in the scroll frame boundary, i.e. its rect
|
|
|
|
* intersects scroll frame's rect.
|
|
|
|
*/
|
|
|
|
bool IsCaretShowingInScrollFrame();
|
|
|
|
|
2014-10-15 05:05:00 +04:00
|
|
|
/**
|
|
|
|
* Clamp the position of the touch caret to the scroll frame boundary.
|
|
|
|
* The returned point is relative to the canvas frame.
|
|
|
|
*/
|
|
|
|
nsPoint ClampPositionToScrollFrame(const nsPoint& aPosition);
|
|
|
|
|
2014-06-03 11:08:45 +04:00
|
|
|
/**
|
|
|
|
* Set the position of the touch caret.
|
|
|
|
* Touch caret is an absolute positioned div.
|
|
|
|
*/
|
|
|
|
void SetTouchFramePos(const nsPoint& aOrigin);
|
|
|
|
|
|
|
|
void LaunchExpirationTimer();
|
|
|
|
void CancelExpirationTimer();
|
|
|
|
static void DisableTouchCaretCallback(nsITimer* aTimer, void* aPresShell);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Move the caret to movePoint which is relative to the canvas frame.
|
|
|
|
* Caret will be scrolled into view.
|
|
|
|
*
|
|
|
|
* @param movePoint tap location relative to the canvas frame.
|
|
|
|
*/
|
|
|
|
void MoveCaret(const nsPoint& movePoint);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Check if aPoint is inside the touch caret frame.
|
|
|
|
*
|
|
|
|
* @param aPoint tap location relative to the canvas frame.
|
|
|
|
*/
|
|
|
|
bool IsOnTouchCaret(const nsPoint& aPoint);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* These Handle* functions comprise input alphabet of the TouchCaret
|
|
|
|
* finite-state machine triggering state transitions.
|
|
|
|
*/
|
|
|
|
nsEventStatus HandleMouseMoveEvent(WidgetMouseEvent* aEvent);
|
|
|
|
nsEventStatus HandleMouseUpEvent(WidgetMouseEvent* aEvent);
|
|
|
|
nsEventStatus HandleMouseDownEvent(WidgetMouseEvent* aEvent);
|
|
|
|
nsEventStatus HandleTouchMoveEvent(WidgetTouchEvent* aEvent);
|
|
|
|
nsEventStatus HandleTouchUpEvent(WidgetTouchEvent* aEvent);
|
|
|
|
nsEventStatus HandleTouchDownEvent(WidgetTouchEvent* aEvent);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the coordinates of a given touch event, relative to canvas frame.
|
|
|
|
* @param aEvent the event
|
|
|
|
* @param aIdentifier the mIdentifier of the touch which is to be converted.
|
|
|
|
* @return the point, or (NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE) if
|
|
|
|
* for some reason the coordinates for the touch are not known (e.g.,
|
|
|
|
* the mIdentifier touch is not found).
|
|
|
|
*/
|
|
|
|
nsPoint GetEventPosition(WidgetTouchEvent* aEvent, int32_t aIdentifier);
|
|
|
|
|
2014-08-04 08:24:00 +04:00
|
|
|
/**
|
|
|
|
* Set mouse down state in nsFrameSelection, we'll set state to true when
|
|
|
|
* user start dragging caret and set state to false when user release the
|
|
|
|
* caret. The reason for setting this state is it will fire drag reason
|
|
|
|
* when moving caret and fire mouseup reason when releasing caret. So that
|
|
|
|
* the display behavior of copy/paste menu becomes more reasonable.
|
|
|
|
*/
|
|
|
|
void SetSelectionDragState(bool aState);
|
|
|
|
|
2014-06-03 11:08:45 +04:00
|
|
|
/**
|
|
|
|
* Get the coordinates of a given mouse event, relative to canvas frame.
|
|
|
|
* @param aEvent the event
|
|
|
|
* @return the point, or (NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE) if
|
|
|
|
* for some reason the coordinates for the mouse are not known.
|
|
|
|
*/
|
|
|
|
nsPoint GetEventPosition(WidgetMouseEvent* aEvent);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* States of TouchCaret finite-state machine.
|
|
|
|
*/
|
|
|
|
enum TouchCaretState {
|
|
|
|
// In this state, either there is no touch/mouse event going on, or the
|
|
|
|
// first stroke does not hit the touch caret.
|
|
|
|
// Will enter TOUCHCARET_TOUCHDRAG_ACTIVE state if the first touch stroke
|
|
|
|
// hits the touch caret. Will enter TOUCHCARET_MOUSEDRAG_ACTIVE state if
|
|
|
|
// mouse (left button) down hits the touch caret.
|
|
|
|
// Allowed next state: TOUCHCARET_MOUSEDRAG_ACTIVE,
|
|
|
|
// TOUCHCARET_TOUCHDRAG_ACTIVE.
|
|
|
|
TOUCHCARET_NONE,
|
|
|
|
// The first (left button) mouse down hits on the touch caret and is
|
|
|
|
// alive. Will enter TOUCHCARET_NONE state if the left button is release.
|
|
|
|
// Allowed next states: TOUCHCARET_NONE.
|
|
|
|
TOUCHCARET_MOUSEDRAG_ACTIVE,
|
|
|
|
// The first touch start event hits on touch caret and is alive.
|
|
|
|
// Will enter TOUCHCARET_NONE state if the finger on touch caret is
|
|
|
|
// removed and there are no more fingers on the screen; will enter
|
|
|
|
// TOUCHCARET_TOUCHDRAG_INACTIVE state if the finger on touch caret is
|
|
|
|
// removed but still has fingers touching on the screen.
|
|
|
|
// Allowed next states: TOUCHCARET_NONE, TOUCHCARET_TOUCHDRAG_INACTIVE.
|
|
|
|
TOUCHCARET_TOUCHDRAG_ACTIVE,
|
|
|
|
// The first touch stroke, which hit on touch caret, is dead, but still has
|
|
|
|
// fingers touching on the screen.
|
|
|
|
// Will enter TOUCHCARET_NONE state if all the fingers are removed from the
|
|
|
|
// screen.
|
|
|
|
// Allowed next state: TOUCHCARET_NONE.
|
|
|
|
TOUCHCARET_TOUCHDRAG_INACTIVE,
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Do actual state transition and reset substates.
|
|
|
|
*/
|
|
|
|
void SetState(TouchCaretState aState);
|
|
|
|
|
2014-10-13 01:44:00 +04:00
|
|
|
/**
|
|
|
|
* Dispatch touch caret tap event to chrome.
|
|
|
|
*/
|
|
|
|
void DispatchTapEvent();
|
|
|
|
|
2014-06-03 11:08:45 +04:00
|
|
|
/**
|
|
|
|
* Current state we're dealing with.
|
|
|
|
*/
|
|
|
|
TouchCaretState mState;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Array containing all active touch IDs. When a touch happens, it gets added
|
|
|
|
* to this array, even if we choose not to handle it. When it ends, we remove
|
|
|
|
* it. We need to maintain this array in order to detect the end of the
|
|
|
|
* "multitouch" states because touch start events contain all current touches,
|
|
|
|
* but touch end events contain only those touches that have gone.
|
|
|
|
*/
|
|
|
|
nsTArray<int32_t> mTouchesId;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The mIdentifier of the touch which is on the touch caret.
|
|
|
|
*/
|
|
|
|
int32_t mActiveTouchId;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The offset between the tap location and the center of caret along y axis.
|
|
|
|
*/
|
|
|
|
nscoord mCaretCenterToDownPointOffsetY;
|
|
|
|
|
2014-09-15 04:58:00 +04:00
|
|
|
/**
|
|
|
|
* Get from pref "touchcaret.inflatesize.threshold". This will inflate the
|
|
|
|
* size of the touch caret frame when checking if user clicks on the caret
|
|
|
|
* or not. In app units.
|
|
|
|
*/
|
|
|
|
static int32_t TouchCaretInflateSize() { return sTouchCaretInflateSize; }
|
2014-06-03 11:08:45 +04:00
|
|
|
|
|
|
|
static int32_t TouchCaretExpirationTime()
|
|
|
|
{
|
|
|
|
return sTouchCaretExpirationTime;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsWeakPtr mPresShell;
|
|
|
|
|
|
|
|
// Touch caret visibility
|
|
|
|
bool mVisible;
|
2014-10-13 01:44:00 +04:00
|
|
|
// Use for detecting single tap on touch caret.
|
|
|
|
bool mIsValidTap;
|
2014-06-03 11:08:45 +04:00
|
|
|
// Touch caret timer
|
|
|
|
nsCOMPtr<nsITimer> mTouchCaretExpirationTimer;
|
|
|
|
|
|
|
|
// Preference
|
2014-09-15 04:58:00 +04:00
|
|
|
static int32_t sTouchCaretInflateSize;
|
2014-06-03 11:08:45 +04:00
|
|
|
static int32_t sTouchCaretExpirationTime;
|
2014-06-05 00:57:00 +04:00
|
|
|
|
|
|
|
// The auto scroll timer's interval in miliseconds.
|
|
|
|
friend class SelectionCarets;
|
|
|
|
static const int32_t sAutoScrollTimerDelay = 30;
|
2014-06-03 11:08:45 +04:00
|
|
|
};
|
|
|
|
} //namespace mozilla
|
|
|
|
#endif //mozilla_TouchCaret_h__
|