Backed out changeset 9f30d3caa231 (bug 1221459)
@ -813,6 +813,18 @@
|
||||
@RESPATH@/res/accessiblecaret_tilt_right@1.5x.png
|
||||
@RESPATH@/res/accessiblecaret_tilt_right@2.25x.png
|
||||
@RESPATH@/res/accessiblecaret_tilt_right@2x.png
|
||||
@RESPATH@/res/text_caret.png
|
||||
@RESPATH@/res/text_caret@1.5x.png
|
||||
@RESPATH@/res/text_caret@2.25x.png
|
||||
@RESPATH@/res/text_caret@2x.png
|
||||
@RESPATH@/res/text_caret_tilt_left.png
|
||||
@RESPATH@/res/text_caret_tilt_left@1.5x.png
|
||||
@RESPATH@/res/text_caret_tilt_left@2.25x.png
|
||||
@RESPATH@/res/text_caret_tilt_left@2x.png
|
||||
@RESPATH@/res/text_caret_tilt_right.png
|
||||
@RESPATH@/res/text_caret_tilt_right@1.5x.png
|
||||
@RESPATH@/res/text_caret_tilt_right@2.25x.png
|
||||
@RESPATH@/res/text_caret_tilt_right@2x.png
|
||||
@RESPATH@/res/grabber.gif
|
||||
#ifdef XP_MACOSX
|
||||
@RESPATH@/res/cursors/*
|
||||
|
@ -751,6 +751,18 @@
|
||||
@RESPATH@/res/accessiblecaret_tilt_right@1.5x.png
|
||||
@RESPATH@/res/accessiblecaret_tilt_right@2.25x.png
|
||||
@RESPATH@/res/accessiblecaret_tilt_right@2x.png
|
||||
@RESPATH@/res/text_caret.png
|
||||
@RESPATH@/res/text_caret@1.5x.png
|
||||
@RESPATH@/res/text_caret@2.25x.png
|
||||
@RESPATH@/res/text_caret@2x.png
|
||||
@RESPATH@/res/text_caret_tilt_left.png
|
||||
@RESPATH@/res/text_caret_tilt_left@1.5x.png
|
||||
@RESPATH@/res/text_caret_tilt_left@2.25x.png
|
||||
@RESPATH@/res/text_caret_tilt_left@2x.png
|
||||
@RESPATH@/res/text_caret_tilt_right.png
|
||||
@RESPATH@/res/text_caret_tilt_right@1.5x.png
|
||||
@RESPATH@/res/text_caret_tilt_right@2.25x.png
|
||||
@RESPATH@/res/text_caret_tilt_right@2x.png
|
||||
@RESPATH@/res/grabber.gif
|
||||
#ifdef XP_MACOSX
|
||||
@RESPATH@/res/cursors/*
|
||||
|
@ -41,6 +41,7 @@
|
||||
#include "nsIObjectFrame.h"
|
||||
#include "nsBindingManager.h"
|
||||
#include "nsStyleCoord.h"
|
||||
#include "SelectionCarets.h"
|
||||
#include "TabChild.h"
|
||||
#include "nsFrameLoader.h"
|
||||
|
||||
@ -1691,6 +1692,11 @@ nsFocusManager::Blur(nsPIDOMWindow* aWindowToClear,
|
||||
SetCaretVisible(presShell, false, nullptr);
|
||||
}
|
||||
|
||||
RefPtr<SelectionCarets> selectionCarets = presShell->GetSelectionCarets();
|
||||
if (selectionCarets) {
|
||||
selectionCarets->NotifyBlur(aIsLeavingDocument || !mActiveWindow);
|
||||
}
|
||||
|
||||
RefPtr<AccessibleCaretEventHub> eventHub = presShell->GetAccessibleCaretEventHub();
|
||||
if (eventHub) {
|
||||
eventHub->NotifyBlur(aIsLeavingDocument || !mActiveWindow);
|
||||
|
@ -207,6 +207,7 @@
|
||||
#include "prrng.h"
|
||||
#include "nsSandboxFlags.h"
|
||||
#include "TimeChangeObserver.h"
|
||||
#include "TouchCaret.h"
|
||||
#include "mozilla/dom/AudioContext.h"
|
||||
#include "mozilla/dom/BrowserElementDictionariesBinding.h"
|
||||
#include "mozilla/dom/cache/CacheStorage.h"
|
||||
|
@ -59,4 +59,16 @@ RESOURCE_FILES += [
|
||||
'res/table-remove-row-active.gif',
|
||||
'res/table-remove-row-hover.gif',
|
||||
'res/table-remove-row.gif',
|
||||
'res/text_caret.png',
|
||||
'res/text_caret@1.5x.png',
|
||||
'res/text_caret@2.25x.png',
|
||||
'res/text_caret@2x.png',
|
||||
'res/text_caret_tilt_left.png',
|
||||
'res/text_caret_tilt_left@1.5x.png',
|
||||
'res/text_caret_tilt_left@2.25x.png',
|
||||
'res/text_caret_tilt_left@2x.png',
|
||||
'res/text_caret_tilt_right.png',
|
||||
'res/text_caret_tilt_right@1.5x.png',
|
||||
'res/text_caret_tilt_right@2.25x.png',
|
||||
'res/text_caret_tilt_right@2x.png',
|
||||
]
|
||||
|
BIN
editor/composer/res/text_caret.png
Normal file
After Width: | Height: | Size: 2.1 KiB |
BIN
editor/composer/res/text_caret@1.5x.png
Normal file
After Width: | Height: | Size: 2.7 KiB |
BIN
editor/composer/res/text_caret@2.25x.png
Normal file
After Width: | Height: | Size: 3.5 KiB |
BIN
editor/composer/res/text_caret@2x.png
Normal file
After Width: | Height: | Size: 3.2 KiB |
BIN
editor/composer/res/text_caret_tilt_left.png
Normal file
After Width: | Height: | Size: 2.0 KiB |
BIN
editor/composer/res/text_caret_tilt_left@1.5x.png
Normal file
After Width: | Height: | Size: 2.5 KiB |
BIN
editor/composer/res/text_caret_tilt_left@2.25x.png
Normal file
After Width: | Height: | Size: 3.3 KiB |
BIN
editor/composer/res/text_caret_tilt_left@2x.png
Normal file
After Width: | Height: | Size: 3.0 KiB |
BIN
editor/composer/res/text_caret_tilt_right.png
Normal file
After Width: | Height: | Size: 2.0 KiB |
BIN
editor/composer/res/text_caret_tilt_right@1.5x.png
Normal file
After Width: | Height: | Size: 2.5 KiB |
BIN
editor/composer/res/text_caret_tilt_right@2.25x.png
Normal file
After Width: | Height: | Size: 3.3 KiB |
BIN
editor/composer/res/text_caret_tilt_right@2x.png
Normal file
After Width: | Height: | Size: 3.0 KiB |
1340
layout/base/SelectionCarets.cpp
Normal file
277
layout/base/SelectionCarets.h
Normal file
@ -0,0 +1,277 @@
|
||||
/* -*- 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 SelectionCarets_h__
|
||||
#define SelectionCarets_h__
|
||||
|
||||
#include "nsDirection.h"
|
||||
#include "nsIReflowObserver.h"
|
||||
#include "nsIScrollObserver.h"
|
||||
#include "nsISelectionListener.h"
|
||||
#include "nsWeakPtr.h"
|
||||
#include "nsWeakReference.h"
|
||||
#include "Units.h"
|
||||
#include "mozilla/dom/SelectionStateChangedEvent.h"
|
||||
#include "mozilla/EventForwards.h"
|
||||
#include "mozilla/WeakPtr.h"
|
||||
|
||||
class nsDocShell;
|
||||
class nsFrameSelection;
|
||||
class nsIContent;
|
||||
class nsIPresShell;
|
||||
class nsITimer;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
namespace dom {
|
||||
class Selection;
|
||||
} // namespace dom
|
||||
|
||||
/**
|
||||
* NOTE: SelectionCarets was obsoleted by AccessibleCaret, and is no longer used
|
||||
* on B2G. This file is going to be removed in bug 1221459. Please see the wiki
|
||||
* page for more information. https://wiki.mozilla.org/Copy_n_Paste
|
||||
*
|
||||
* The SelectionCarets draw a pair of carets when the selection is not
|
||||
* collapsed, one at each end of the selection.
|
||||
* SelectionCarets also handle visibility, dragging caret and selecting word
|
||||
* when long tap event fired.
|
||||
*
|
||||
* The DOM structure is 2 div elements for showing start and end caret.
|
||||
* Each div element has a child div element. That is, each caret consist of
|
||||
* outer div and inner div. Outer div takes responsibility for detecting two
|
||||
* carets are overlapping. Inner div is for actual appearance.
|
||||
*
|
||||
* Here is an explanation of the html class names:
|
||||
* .moz-selectioncaret-left: Indicates start DIV.
|
||||
* .moz-selectioncaret-right: Indicates end DIV.
|
||||
* .hidden: This class name is set by SetVisibility,
|
||||
* SetStartFrameVisibility and SetEndFrameVisibility. Element
|
||||
* with this class name become hidden.
|
||||
* .tilt: This class name is set by SetTilted. According to the
|
||||
* UX spec, when selection carets are overlapping, the image of
|
||||
* caret becomes tilt.
|
||||
*/
|
||||
class SelectionCarets final : public nsIReflowObserver,
|
||||
public nsISelectionListener,
|
||||
public nsIScrollObserver,
|
||||
public nsSupportsWeakReference
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Indicate which part of caret we are dragging at.
|
||||
*/
|
||||
enum DragMode {
|
||||
NONE,
|
||||
START_FRAME,
|
||||
END_FRAME
|
||||
};
|
||||
|
||||
explicit SelectionCarets(nsIPresShell *aPresShell);
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIREFLOWOBSERVER
|
||||
NS_DECL_NSISELECTIONLISTENER
|
||||
|
||||
// Notify selection carets about the blur event to hidden itself
|
||||
void NotifyBlur(bool aIsLeavingDocument);
|
||||
|
||||
// nsIScrollObserver
|
||||
virtual void ScrollPositionChanged() override;
|
||||
|
||||
// AsyncPanZoom started/stopped callbacks from nsIScrollObserver
|
||||
virtual void AsyncPanZoomStarted() override;
|
||||
virtual void AsyncPanZoomStopped() override;
|
||||
|
||||
void Init();
|
||||
void Terminate();
|
||||
|
||||
nsEventStatus HandleEvent(WidgetEvent* aEvent);
|
||||
|
||||
bool GetVisibility() const
|
||||
{
|
||||
return mVisible;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get from pref "selectioncaret.inflatesize.threshold". This will inflate size of
|
||||
* caret frame when we checking if user click on caret or not. In app units.
|
||||
*/
|
||||
static int32_t SelectionCaretsInflateSize()
|
||||
{
|
||||
return sSelectionCaretsInflateSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set visibility for selection caret.
|
||||
*/
|
||||
void SetVisibility(bool aVisible);
|
||||
|
||||
/**
|
||||
* Update selection caret position base on current selection range.
|
||||
*/
|
||||
void UpdateSelectionCarets();
|
||||
|
||||
private:
|
||||
virtual ~SelectionCarets();
|
||||
|
||||
SelectionCarets() = delete;
|
||||
|
||||
/**
|
||||
* Select a word base on current position, which activates only if element is
|
||||
* selectable. Triggered by long tap event.
|
||||
*/
|
||||
nsresult SelectWord();
|
||||
|
||||
/**
|
||||
* Move selection base on current touch/mouse point
|
||||
*/
|
||||
nsEventStatus DragSelection(const nsPoint &movePoint);
|
||||
|
||||
/**
|
||||
* Get the vertical center position of selection caret relative to root
|
||||
* frame.
|
||||
*/
|
||||
nscoord GetCaretYCenterPosition();
|
||||
|
||||
/**
|
||||
* Simulate drag state when we change the selection range.
|
||||
* Hence, the selection change event will fire normally.
|
||||
*/
|
||||
void SetSelectionDragState(bool aState);
|
||||
|
||||
void SetSelectionDirection(nsDirection aDir);
|
||||
|
||||
/**
|
||||
* Move start frame of selection caret based on current caret pos.
|
||||
* In app units.
|
||||
*/
|
||||
void SetStartFramePos(const nsRect& aCaretRect);
|
||||
|
||||
/**
|
||||
* Move end frame of selection caret based on current caret pos.
|
||||
* In app units.
|
||||
*/
|
||||
void SetEndFramePos(const nsRect& aCaretRect);
|
||||
|
||||
/**
|
||||
* Check if aPosition is on the start or end frame of the
|
||||
* selection caret's inner div element.
|
||||
*
|
||||
* @param aPosition should be relative to document's root frame
|
||||
* in app units
|
||||
*/
|
||||
bool IsOnStartFrameInner(const nsPoint& aPosition);
|
||||
bool IsOnEndFrameInner(const nsPoint& aPosition);
|
||||
|
||||
/**
|
||||
* Get rect of selection caret's outer div element relative
|
||||
* to document's root frame, in app units.
|
||||
*/
|
||||
nsRect GetStartFrameRect();
|
||||
nsRect GetEndFrameRect();
|
||||
|
||||
/**
|
||||
* Get rect of selection caret's inner div element relative
|
||||
* to document's root frame, in app units.
|
||||
*/
|
||||
nsRect GetStartFrameRectInner();
|
||||
nsRect GetEndFrameRectInner();
|
||||
|
||||
/**
|
||||
* Set visibility for start part of selection caret, this function
|
||||
* only affects css property of start frame. So it doesn't change
|
||||
* mVisible member. When caret overflows element's box we'll hide
|
||||
* it by calling this function.
|
||||
*/
|
||||
void SetStartFrameVisibility(bool aVisible);
|
||||
|
||||
/**
|
||||
* Same as above function but for end frame of selection caret.
|
||||
*/
|
||||
void SetEndFrameVisibility(bool aVisible);
|
||||
|
||||
/**
|
||||
* Set tilt class name to start and end frame of selection caret.
|
||||
*/
|
||||
void SetTilted(bool aIsTilt);
|
||||
|
||||
// Utility functions
|
||||
dom::Selection* GetSelection();
|
||||
already_AddRefed<nsFrameSelection> GetFrameSelection();
|
||||
nsIContent* GetFocusedContent();
|
||||
void DispatchSelectionStateChangedEvent(dom::Selection* aSelection,
|
||||
dom::SelectionState aState);
|
||||
void DispatchSelectionStateChangedEvent(dom::Selection* aSelection,
|
||||
const dom::Sequence<dom::SelectionState>& aStates);
|
||||
void DispatchCustomEvent(const nsAString& aEvent);
|
||||
|
||||
/**
|
||||
* Detecting long tap using timer
|
||||
*/
|
||||
void LaunchLongTapDetector();
|
||||
void CancelLongTapDetector();
|
||||
static void FireLongTap(nsITimer* aTimer, void* aSelectionCarets);
|
||||
|
||||
void LaunchScrollEndDetector();
|
||||
void CancelScrollEndDetector();
|
||||
static void FireScrollEnd(nsITimer* aTimer, void* aSelectionCarets);
|
||||
|
||||
nsIPresShell* mPresShell;
|
||||
WeakPtr<nsDocShell> mDocShell;
|
||||
|
||||
// This timer is used for detecting long tap fire. If content process
|
||||
// has APZC, we'll use APZC for long tap detecting. Otherwise, we use this
|
||||
// timer to detect long tap.
|
||||
nsCOMPtr<nsITimer> mLongTapDetectorTimer;
|
||||
|
||||
// This timer is used for detecting scroll end. We don't have
|
||||
// scroll end event now, so we will fire this event with a
|
||||
// const time when we scroll. So when timer triggers, we treat it
|
||||
// as scroll end event.
|
||||
nsCOMPtr<nsITimer> mScrollEndDetectorTimer;
|
||||
|
||||
// When touch or mouse down, we save the position for detecting
|
||||
// drag distance
|
||||
nsPoint mDownPoint;
|
||||
|
||||
// For filter multitouch event
|
||||
int32_t mActiveTouchId;
|
||||
|
||||
nscoord mCaretCenterToDownPointOffsetY;
|
||||
|
||||
// The horizontal boundary is defined by the first selected frame which
|
||||
// determines the start-caret position. When users drag the end-caret up,
|
||||
// the touch input(pos.y) will be changed to not cross this boundary.
|
||||
// Otherwise, the selection range changes to one character only
|
||||
// which causes the bad user experience.
|
||||
nscoord mDragUpYBoundary;
|
||||
// The horizontal boundary is defined by the last selected frame which
|
||||
// determines the end-caret position. When users drag the start-caret down,
|
||||
// the touch input(pos.y) will be changed to not cross this boundary.
|
||||
// Otherwise, the selection range changes to one character only
|
||||
// which causes the bad user experience.
|
||||
nscoord mDragDownYBoundary;
|
||||
|
||||
DragMode mDragMode;
|
||||
|
||||
// True if async-pan-zoom should be used for selection carets.
|
||||
bool mUseAsyncPanZoom;
|
||||
// True if AsyncPanZoom is started
|
||||
bool mInAsyncPanZoomGesture;
|
||||
|
||||
bool mEndCaretVisible;
|
||||
bool mStartCaretVisible;
|
||||
bool mSelectionVisibleInScrollFrames;
|
||||
bool mVisible;
|
||||
|
||||
// Preference
|
||||
static int32_t sSelectionCaretsInflateSize;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif //SelectionCarets_h__
|
1110
layout/base/TouchCaret.cpp
Normal file
321
layout/base/TouchCaret.h
Normal file
@ -0,0 +1,321 @@
|
||||
/* -*- 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"
|
||||
|
||||
class nsCanvasFrame;
|
||||
class nsIFrame;
|
||||
class nsIPresShell;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
/**
|
||||
* NOTE: TouchCaret was obsoleted by AccessibleCaret, and is no longer used on
|
||||
* B2G. This file is going to be removed in bug 1221459. Please see the wiki
|
||||
* page for more information. https://wiki.mozilla.org/Copy_n_Paste
|
||||
*
|
||||
* The TouchCaret places a touch caret according to caret position when the
|
||||
* 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 final : public nsISelectionListener,
|
||||
public nsIScrollObserver,
|
||||
public nsSupportsWeakReference
|
||||
{
|
||||
public:
|
||||
explicit TouchCaret(nsIPresShell* aPresShell);
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSISELECTIONLISTENER
|
||||
|
||||
void Init();
|
||||
void Terminate();
|
||||
|
||||
// nsIScrollObserver
|
||||
virtual void ScrollPositionChanged() override;
|
||||
|
||||
// AsyncPanZoom started/stopped callbacks from nsIScrollObserver
|
||||
virtual void AsyncPanZoomStarted() override;
|
||||
virtual void AsyncPanZoomStopped() override;
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
void SyncVisibilityWithCaret();
|
||||
|
||||
void UpdatePositionIfNeeded();
|
||||
|
||||
/**
|
||||
* GetVisibility will get the visibility of the touch caret.
|
||||
*/
|
||||
bool GetVisibility() const
|
||||
{
|
||||
return mVisible;
|
||||
}
|
||||
|
||||
/**
|
||||
* Open or close the Android TextSelection ActionBar based on visibility.
|
||||
*/
|
||||
static void UpdateAndroidActionBarVisibility(bool aVisibility, uint32_t& aViewID);
|
||||
|
||||
private:
|
||||
// Hide default constructor.
|
||||
TouchCaret() = delete;
|
||||
|
||||
~TouchCaret();
|
||||
|
||||
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);
|
||||
|
||||
/**
|
||||
* Helper function to get caret's focus frame and caret's bounding rect.
|
||||
*/
|
||||
nsIFrame* GetCaretFocusFrame(nsRect* aOutRect = nullptr);
|
||||
|
||||
/**
|
||||
* Find the nsCanvasFrame which holds the touch caret.
|
||||
*/
|
||||
nsCanvasFrame* GetCanvasFrame();
|
||||
|
||||
/**
|
||||
* Find the root frame to update the touch caret's position.
|
||||
*/
|
||||
nsIFrame* GetRootFrame();
|
||||
|
||||
/**
|
||||
* 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();
|
||||
|
||||
/**
|
||||
* Retrieve the rect of the touch caret.
|
||||
* The returned rect is relative to the canvas frame.
|
||||
*/
|
||||
nsRect GetTouchCaretRect();
|
||||
|
||||
/**
|
||||
* Clamp the position of the touch caret to the scroll frame boundary.
|
||||
* The returned rect is relative to the canvas frame.
|
||||
*/
|
||||
nsRect ClampRectToScrollFrame(const nsRect& aRect);
|
||||
|
||||
/**
|
||||
* Set the position of the touch caret.
|
||||
* Touch caret is an absolute positioned div.
|
||||
*/
|
||||
void SetTouchFramePos(const nsRect& aRect);
|
||||
|
||||
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);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* Dispatch touch caret tap event to chrome.
|
||||
*/
|
||||
void DispatchTapEvent();
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* 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; }
|
||||
|
||||
static int32_t TouchCaretExpirationTime()
|
||||
{
|
||||
return sTouchCaretExpirationTime;
|
||||
}
|
||||
|
||||
void LaunchScrollEndDetector();
|
||||
void CancelScrollEndDetector();
|
||||
static void FireScrollEnd(nsITimer* aTimer, void* aSelectionCarets);
|
||||
|
||||
// This timer is used for detecting scroll end. We don't have
|
||||
// scroll end event now, so we will fire this event with a
|
||||
// const time when we scroll. So when timer triggers, we treat it
|
||||
// as scroll end event.
|
||||
nsCOMPtr<nsITimer> mScrollEndDetectorTimer;
|
||||
|
||||
nsWeakPtr mPresShell;
|
||||
WeakPtr<nsDocShell> mDocShell;
|
||||
|
||||
// True if AsyncPanZoom is started
|
||||
bool mInAsyncPanZoomGesture;
|
||||
|
||||
// Touch caret visibility
|
||||
bool mVisible;
|
||||
// Use for detecting single tap on touch caret.
|
||||
bool mIsValidTap;
|
||||
// Touch caret timer
|
||||
nsCOMPtr<nsITimer> mTouchCaretExpirationTimer;
|
||||
|
||||
// Preference
|
||||
static int32_t sTouchCaretInflateSize;
|
||||
static int32_t sTouchCaretExpirationTime;
|
||||
|
||||
// The auto scroll timer's interval in miliseconds.
|
||||
friend class SelectionCarets;
|
||||
static const int32_t sAutoScrollTimerDelay = 30;
|
||||
// Time for trigger scroll end event, in miliseconds.
|
||||
static const int32_t sScrollEndTimerDelay = 300;
|
||||
};
|
||||
} //namespace mozilla
|
||||
#endif //mozilla_TouchCaret_h__
|
@ -6,16 +6,7 @@
|
||||
*/
|
||||
|
||||
#include "TouchManager.h"
|
||||
|
||||
#include "mozilla/TouchEvents.h"
|
||||
#include "mozilla/dom/EventTarget.h"
|
||||
#include "nsIFrame.h"
|
||||
#include "nsPresShell.h"
|
||||
#include "nsView.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
using EventTarget = ::mozilla::dom::EventTarget;
|
||||
|
||||
nsRefPtrHashtable<nsUint32HashKey, dom::Touch>* TouchManager::gCaptureTouchList;
|
||||
|
||||
@ -231,5 +222,3 @@ TouchManager::PreHandleEvent(WidgetEvent* aEvent,
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -15,8 +15,6 @@
|
||||
class PresShell;
|
||||
class nsIDocument;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class TouchManager {
|
||||
public:
|
||||
// Initialize and release static variables
|
||||
@ -41,6 +39,4 @@ private:
|
||||
nsCOMPtr<nsIDocument> mDocument;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif /* !defined(TouchManager_h_) */
|
||||
|
@ -7,10 +7,8 @@
|
||||
|
||||
#include <inttypes.h>
|
||||
#include "FrameMetrics.h"
|
||||
#include "gfxPrefs.h"
|
||||
#include "LayersLogging.h"
|
||||
#include "mozilla/layers/APZCCallbackHelper.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "nsDocument.h"
|
||||
#include "nsIFrame.h"
|
||||
#include "nsLayoutUtils.h"
|
||||
|
@ -40,8 +40,9 @@ with Files('nsChangeHint.h'):
|
||||
with Files('nsBidi*'):
|
||||
BUG_COMPONENT = ('Core', 'Layout: Text')
|
||||
|
||||
with Files('AccessibleCaret*'):
|
||||
BUG_COMPONENT = ('Core', 'Selection')
|
||||
for caret_file in ('AccessibleCaret*', 'TouchCaret*', 'SelectionCarets*'):
|
||||
with Files(caret_file):
|
||||
BUG_COMPONENT = ('Core', 'Selection')
|
||||
|
||||
XPIDL_SOURCES += [
|
||||
'nsIStyleSheetService.idl',
|
||||
@ -146,7 +147,9 @@ UNIFIED_SOURCES += [
|
||||
'RestyleManager.cpp',
|
||||
'RestyleTracker.cpp',
|
||||
'ScrollbarStyles.cpp',
|
||||
'SelectionCarets.cpp',
|
||||
'StackArena.cpp',
|
||||
'TouchCaret.cpp',
|
||||
'TouchManager.cpp',
|
||||
'ZoomConstraintsClient.cpp',
|
||||
]
|
||||
|
@ -63,6 +63,8 @@ class nsCaret;
|
||||
namespace mozilla {
|
||||
class AccessibleCaretEventHub;
|
||||
class CSSStyleSheet;
|
||||
class TouchCaret;
|
||||
class SelectionCarets;
|
||||
} // namespace mozilla
|
||||
class nsFrameSelection;
|
||||
class nsFrameManager;
|
||||
@ -805,6 +807,31 @@ public:
|
||||
*/
|
||||
virtual void NotifyDestroyingFrame(nsIFrame* aFrame) = 0;
|
||||
|
||||
/**
|
||||
* Get the touch caret, if it exists. AddRefs it.
|
||||
*/
|
||||
virtual already_AddRefed<mozilla::TouchCaret> GetTouchCaret() const = 0;
|
||||
|
||||
/**
|
||||
* Returns the touch caret element of the presshell.
|
||||
*/
|
||||
virtual mozilla::dom::Element* GetTouchCaretElement() const = 0;
|
||||
|
||||
/**
|
||||
* Get the selection caret, if it exists. AddRefs it.
|
||||
*/
|
||||
virtual already_AddRefed<mozilla::SelectionCarets> GetSelectionCarets() const = 0;
|
||||
|
||||
/**
|
||||
* Returns the start part of selection caret element of the presshell.
|
||||
*/
|
||||
virtual mozilla::dom::Element* GetSelectionCaretsStartElement() const = 0;
|
||||
|
||||
/**
|
||||
* Returns the end part of selection caret element of the presshell.
|
||||
*/
|
||||
virtual mozilla::dom::Element* GetSelectionCaretsEndElement() const = 0;
|
||||
|
||||
/**
|
||||
* Get the AccessibleCaretEventHub, if it exists. AddRefs it.
|
||||
*/
|
||||
|
@ -78,6 +78,8 @@
|
||||
#include "nsIMozBrowserFrame.h"
|
||||
#include "nsCaret.h"
|
||||
#include "AccessibleCaretEventHub.h"
|
||||
#include "TouchCaret.h"
|
||||
#include "SelectionCarets.h"
|
||||
#include "nsIDOMHTMLDocument.h"
|
||||
#include "nsFrameManager.h"
|
||||
#include "nsXPCOM.h"
|
||||
@ -703,9 +705,33 @@ nsIPresShell::FrameSelection()
|
||||
static bool sSynthMouseMove = true;
|
||||
static uint32_t sNextPresShellId;
|
||||
static bool sPointerEventEnabled = true;
|
||||
static bool sTouchCaretEnabled = false;
|
||||
static bool sSelectionCaretEnabled = false;
|
||||
static bool sAccessibleCaretEnabled = false;
|
||||
static bool sBeforeAfterKeyboardEventEnabled = false;
|
||||
|
||||
/* static */ bool
|
||||
PresShell::TouchCaretPrefEnabled()
|
||||
{
|
||||
static bool initialized = false;
|
||||
if (!initialized) {
|
||||
Preferences::AddBoolVarCache(&sTouchCaretEnabled, "touchcaret.enabled");
|
||||
initialized = true;
|
||||
}
|
||||
return sTouchCaretEnabled;
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
PresShell::SelectionCaretPrefEnabled()
|
||||
{
|
||||
static bool initialized = false;
|
||||
if (!initialized) {
|
||||
Preferences::AddBoolVarCache(&sSelectionCaretEnabled, "selectioncaret.enabled");
|
||||
initialized = true;
|
||||
}
|
||||
return sSelectionCaretEnabled;
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
PresShell::AccessibleCaretEnabled()
|
||||
{
|
||||
@ -856,6 +882,18 @@ PresShell::Init(nsIDocument* aDocument,
|
||||
// Add the preference style sheet.
|
||||
UpdatePreferenceStyles();
|
||||
|
||||
if (TouchCaretPrefEnabled() && !AccessibleCaretEnabled()) {
|
||||
// Create touch caret handle
|
||||
mTouchCaret = new TouchCaret(this);
|
||||
mTouchCaret->Init();
|
||||
}
|
||||
|
||||
if (SelectionCaretPrefEnabled() && !AccessibleCaretEnabled()) {
|
||||
// Create selection caret handle
|
||||
mSelectionCarets = new SelectionCarets(this);
|
||||
mSelectionCarets->Init();
|
||||
}
|
||||
|
||||
if (AccessibleCaretEnabled()) {
|
||||
// Need to happen before nsFrameSelection has been set up.
|
||||
mAccessibleCaretEventHub = new AccessibleCaretEventHub(this);
|
||||
@ -1157,6 +1195,16 @@ PresShell::Destroy()
|
||||
mSelection->DisconnectFromPresShell();
|
||||
}
|
||||
|
||||
if (mTouchCaret) {
|
||||
mTouchCaret->Terminate();
|
||||
mTouchCaret = nullptr;
|
||||
}
|
||||
|
||||
if (mSelectionCarets) {
|
||||
mSelectionCarets->Terminate();
|
||||
mSelectionCarets = nullptr;
|
||||
}
|
||||
|
||||
if (mAccessibleCaretEventHub) {
|
||||
mAccessibleCaretEventHub->Terminate();
|
||||
mAccessibleCaretEventHub = nullptr;
|
||||
@ -1943,6 +1991,19 @@ already_AddRefed<nsCaret> PresShell::GetCaret() const
|
||||
return caret.forget();
|
||||
}
|
||||
|
||||
// TouchCaret
|
||||
already_AddRefed<TouchCaret> PresShell::GetTouchCaret() const
|
||||
{
|
||||
RefPtr<TouchCaret> touchCaret = mTouchCaret;
|
||||
return touchCaret.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<SelectionCarets> PresShell::GetSelectionCarets() const
|
||||
{
|
||||
RefPtr<SelectionCarets> selectionCaret = mSelectionCarets;
|
||||
return selectionCaret.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<AccessibleCaretEventHub> PresShell::GetAccessibleCaretEventHub() const
|
||||
{
|
||||
RefPtr<AccessibleCaretEventHub> eventHub = mAccessibleCaretEventHub;
|
||||
@ -1973,6 +2034,12 @@ NS_IMETHODIMP PresShell::SetCaretEnabled(bool aInEnable)
|
||||
}
|
||||
}
|
||||
|
||||
// We should sync touch caret's visibility with caret every time since touch
|
||||
// caret might be hidden due to timeout while caret is enabled.
|
||||
if (mTouchCaret) {
|
||||
mTouchCaret->SyncVisibilityWithCaret();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -2303,6 +2370,24 @@ PresShell::GetCanvasFrame() const
|
||||
return do_QueryFrame(frame);
|
||||
}
|
||||
|
||||
Element*
|
||||
PresShell::GetTouchCaretElement() const
|
||||
{
|
||||
return GetCanvasFrame() ? GetCanvasFrame()->GetTouchCaretElement() : nullptr;
|
||||
}
|
||||
|
||||
Element*
|
||||
PresShell::GetSelectionCaretsStartElement() const
|
||||
{
|
||||
return GetCanvasFrame() ? GetCanvasFrame()->GetSelectionCaretsStartElement() : nullptr;
|
||||
}
|
||||
|
||||
Element*
|
||||
PresShell::GetSelectionCaretsEndElement() const
|
||||
{
|
||||
return GetCanvasFrame() ? GetCanvasFrame()->GetSelectionCaretsEndElement() : nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
PresShell::BeginUpdate(nsIDocument *aDocument, nsUpdateType aUpdateType)
|
||||
{
|
||||
@ -3701,6 +3786,10 @@ PresShell::UnsuppressAndInvalidate()
|
||||
if (rootFrame) {
|
||||
// let's assume that outline on a root frame is not supported
|
||||
rootFrame->InvalidateFrame();
|
||||
|
||||
if (mTouchCaret) {
|
||||
mTouchCaret->SyncVisibilityWithCaret();
|
||||
}
|
||||
}
|
||||
|
||||
// now that painting is unsuppressed, focus may be set on the document
|
||||
@ -6891,6 +6980,47 @@ PresShell::HandleEvent(nsIFrame* aFrame,
|
||||
|
||||
RecordMouseLocation(aEvent);
|
||||
|
||||
// Determine whether event need to be consumed by touch caret or not.
|
||||
if (TouchCaretPrefEnabled() || SelectionCaretPrefEnabled()) {
|
||||
// We have to target the focus window because regardless of where the
|
||||
// touch goes, we want to access the touch caret when user is typing on an
|
||||
// editable element.
|
||||
nsCOMPtr<nsPIDOMWindow> window = GetFocusedDOMWindowInOurWindow();
|
||||
nsCOMPtr<nsIDocument> retargetEventDoc = window ? window->GetExtantDoc() : nullptr;
|
||||
nsCOMPtr<nsIPresShell> presShell = retargetEventDoc ?
|
||||
retargetEventDoc->GetShell() :
|
||||
nullptr;
|
||||
|
||||
// Bug 1057256: Touch caret should handle the event before selection carets.
|
||||
// Otherwise, a long tap on touch caret will be incorrectly handled by
|
||||
// selection carets which makes moving touch caret failed.
|
||||
RefPtr<TouchCaret> touchCaret = presShell ?
|
||||
presShell->GetTouchCaret() :
|
||||
nullptr;
|
||||
if (touchCaret) {
|
||||
*aEventStatus = touchCaret->HandleEvent(aEvent);
|
||||
if (*aEventStatus == nsEventStatus_eConsumeNoDefault) {
|
||||
// If the event is consumed by the touch caret, cancel APZC panning by
|
||||
// setting mMultipleActionsPrevented.
|
||||
aEvent->mFlags.mMultipleActionsPrevented = true;
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
RefPtr<SelectionCarets> selectionCaret = presShell ?
|
||||
presShell->GetSelectionCarets() :
|
||||
nullptr;
|
||||
if (selectionCaret) {
|
||||
*aEventStatus = selectionCaret->HandleEvent(aEvent);
|
||||
if (*aEventStatus == nsEventStatus_eConsumeNoDefault) {
|
||||
// If the event is consumed by the selection carets, cancel APZC panning by
|
||||
// setting mMultipleActionsPrevented.
|
||||
aEvent->mFlags.mMultipleActionsPrevented = true;
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (AccessibleCaretEnabled()) {
|
||||
// We have to target the focus window because regardless of where the
|
||||
// touch goes, we want to access the copy paste manager.
|
||||
@ -8711,6 +8841,10 @@ PresShell::DidDoReflow(bool aInterruptible)
|
||||
SynthesizeMouseMove(false);
|
||||
}
|
||||
|
||||
if (mTouchCaret) {
|
||||
mTouchCaret->UpdatePositionIfNeeded();
|
||||
}
|
||||
|
||||
mPresContext->NotifyMissingFonts();
|
||||
}
|
||||
|
||||
|
@ -73,6 +73,12 @@ public:
|
||||
// nsISupports
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
// Touch caret preference
|
||||
static bool TouchCaretPrefEnabled();
|
||||
|
||||
// Selection caret preference
|
||||
static bool SelectionCaretPrefEnabled();
|
||||
|
||||
static bool AccessibleCaretEnabled();
|
||||
|
||||
// BeforeAfterKeyboardEvent preference
|
||||
@ -240,6 +246,14 @@ public:
|
||||
virtual void ClearMouseCaptureOnView(nsView* aView) override;
|
||||
virtual bool IsVisible() override;
|
||||
|
||||
// touch caret
|
||||
virtual already_AddRefed<mozilla::TouchCaret> GetTouchCaret() const override;
|
||||
virtual mozilla::dom::Element* GetTouchCaretElement() const override;
|
||||
// selection caret
|
||||
virtual already_AddRefed<mozilla::SelectionCarets> GetSelectionCarets() const override;
|
||||
virtual mozilla::dom::Element* GetSelectionCaretsStartElement() const override;
|
||||
virtual mozilla::dom::Element* GetSelectionCaretsEndElement() const override;
|
||||
|
||||
virtual already_AddRefed<mozilla::AccessibleCaretEventHub> GetAccessibleCaretEventHub() const override;
|
||||
|
||||
// caret handling
|
||||
@ -802,11 +816,15 @@ protected:
|
||||
nsCallbackEventRequest* mFirstCallbackEventRequest;
|
||||
nsCallbackEventRequest* mLastCallbackEventRequest;
|
||||
|
||||
mozilla::TouchManager mTouchManager;
|
||||
// TouchManager
|
||||
TouchManager mTouchManager;
|
||||
|
||||
RefPtr<ZoomConstraintsClient> mZoomConstraintsClient;
|
||||
RefPtr<MobileViewportManager> mMobileViewportManager;
|
||||
|
||||
// TouchCaret
|
||||
RefPtr<mozilla::TouchCaret> mTouchCaret;
|
||||
RefPtr<mozilla::SelectionCarets> mSelectionCarets;
|
||||
RefPtr<mozilla::AccessibleCaretEventHub> mAccessibleCaretEventHub;
|
||||
|
||||
// This timer controls painting suppression. Until it fires
|
||||
|
@ -23,6 +23,11 @@
|
||||
#include "gfxPlatform.h"
|
||||
#include "nsPrintfCString.h"
|
||||
#include "mozilla/dom/AnonymousContent.h"
|
||||
// for touchcaret
|
||||
#include "nsContentList.h"
|
||||
#include "nsContentCreatorFunctions.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsStyleSet.h"
|
||||
// for focus
|
||||
#include "nsIScrollableFrame.h"
|
||||
#ifdef DEBUG_CANVAS_FOCUS
|
||||
@ -49,6 +54,8 @@ NS_QUERYFRAME_HEAD(nsCanvasFrame)
|
||||
NS_QUERYFRAME_ENTRY(nsIAnonymousContentCreator)
|
||||
NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame)
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsCanvasFrame::DummyTouchListener, nsIDOMEventListener)
|
||||
|
||||
void
|
||||
nsCanvasFrame::ShowCustomContentContainer()
|
||||
{
|
||||
@ -76,6 +83,66 @@ nsCanvasFrame::CreateAnonymousContent(nsTArray<ContentInfo>& aElements)
|
||||
|
||||
nsCOMPtr<nsIDocument> doc = mContent->OwnerDoc();
|
||||
nsresult rv = NS_OK;
|
||||
ErrorResult er;
|
||||
// We won't create touch caret element if preference is not enabled.
|
||||
if (PresShell::TouchCaretPrefEnabled()) {
|
||||
RefPtr<NodeInfo> nodeInfo;
|
||||
|
||||
// Create and append touch caret frame.
|
||||
nodeInfo = doc->NodeInfoManager()->GetNodeInfo(nsGkAtoms::div, nullptr,
|
||||
kNameSpaceID_XHTML,
|
||||
nsIDOMNode::ELEMENT_NODE);
|
||||
NS_ENSURE_TRUE(nodeInfo, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
rv = NS_NewHTMLElement(getter_AddRefs(mTouchCaretElement), nodeInfo.forget(),
|
||||
NOT_FROM_PARSER);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
aElements.AppendElement(mTouchCaretElement);
|
||||
|
||||
// Set touch caret to visibility: hidden by default.
|
||||
nsAutoString classValue;
|
||||
classValue.AppendLiteral("moz-touchcaret hidden");
|
||||
rv = mTouchCaretElement->SetAttr(kNameSpaceID_None, nsGkAtoms::_class,
|
||||
classValue, true);
|
||||
|
||||
if (!mDummyTouchListener) {
|
||||
mDummyTouchListener = new DummyTouchListener();
|
||||
}
|
||||
mTouchCaretElement->AddEventListener(NS_LITERAL_STRING("touchstart"),
|
||||
mDummyTouchListener, false);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
if (PresShell::SelectionCaretPrefEnabled()) {
|
||||
// Selection caret
|
||||
mSelectionCaretsStartElement = doc->CreateHTMLElement(nsGkAtoms::div);
|
||||
aElements.AppendElement(mSelectionCaretsStartElement);
|
||||
nsCOMPtr<mozilla::dom::Element> selectionCaretsStartElementInner = doc->CreateHTMLElement(nsGkAtoms::div);
|
||||
mSelectionCaretsStartElement->AppendChildTo(selectionCaretsStartElementInner, false);
|
||||
|
||||
mSelectionCaretsEndElement = doc->CreateHTMLElement(nsGkAtoms::div);
|
||||
aElements.AppendElement(mSelectionCaretsEndElement);
|
||||
nsCOMPtr<mozilla::dom::Element> selectionCaretsEndElementInner = doc->CreateHTMLElement(nsGkAtoms::div);
|
||||
mSelectionCaretsEndElement->AppendChildTo(selectionCaretsEndElementInner, false);
|
||||
|
||||
rv = mSelectionCaretsStartElement->SetAttr(kNameSpaceID_None, nsGkAtoms::_class,
|
||||
NS_LITERAL_STRING("moz-selectioncaret-left hidden"),
|
||||
true);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = mSelectionCaretsEndElement->SetAttr(kNameSpaceID_None, nsGkAtoms::_class,
|
||||
NS_LITERAL_STRING("moz-selectioncaret-right hidden"),
|
||||
true);
|
||||
|
||||
if (!mDummyTouchListener) {
|
||||
mDummyTouchListener = new DummyTouchListener();
|
||||
}
|
||||
mSelectionCaretsStartElement->AddEventListener(NS_LITERAL_STRING("touchstart"),
|
||||
mDummyTouchListener, false);
|
||||
mSelectionCaretsEndElement->AddEventListener(NS_LITERAL_STRING("touchstart"),
|
||||
mDummyTouchListener, false);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
// Create the custom content container.
|
||||
mCustomContentContainer = doc->CreateHTMLElement(nsGkAtoms::div);
|
||||
@ -121,6 +188,18 @@ nsCanvasFrame::CreateAnonymousContent(nsTArray<ContentInfo>& aElements)
|
||||
void
|
||||
nsCanvasFrame::AppendAnonymousContentTo(nsTArray<nsIContent*>& aElements, uint32_t aFilter)
|
||||
{
|
||||
if (mTouchCaretElement) {
|
||||
aElements.AppendElement(mTouchCaretElement);
|
||||
}
|
||||
|
||||
if (mSelectionCaretsStartElement) {
|
||||
aElements.AppendElement(mSelectionCaretsStartElement);
|
||||
}
|
||||
|
||||
if (mSelectionCaretsEndElement) {
|
||||
aElements.AppendElement(mSelectionCaretsEndElement);
|
||||
}
|
||||
|
||||
aElements.AppendElement(mCustomContentContainer);
|
||||
}
|
||||
|
||||
@ -133,6 +212,25 @@ nsCanvasFrame::DestroyFrom(nsIFrame* aDestructRoot)
|
||||
sf->RemoveScrollPositionListener(this);
|
||||
}
|
||||
|
||||
if (mTouchCaretElement) {
|
||||
mTouchCaretElement->RemoveEventListener(NS_LITERAL_STRING("touchstart"),
|
||||
mDummyTouchListener, false);
|
||||
}
|
||||
|
||||
if (mSelectionCaretsStartElement) {
|
||||
mSelectionCaretsStartElement->RemoveEventListener(NS_LITERAL_STRING("touchstart"),
|
||||
mDummyTouchListener, false);
|
||||
}
|
||||
|
||||
if (mSelectionCaretsEndElement) {
|
||||
mSelectionCaretsEndElement->RemoveEventListener(NS_LITERAL_STRING("touchstart"),
|
||||
mDummyTouchListener, false);
|
||||
}
|
||||
|
||||
nsContentUtils::DestroyAnonymousContent(&mTouchCaretElement);
|
||||
nsContentUtils::DestroyAnonymousContent(&mSelectionCaretsStartElement);
|
||||
nsContentUtils::DestroyAnonymousContent(&mSelectionCaretsEndElement);
|
||||
|
||||
// Elements inserted in the custom content container have the same lifetime as
|
||||
// the document, so before destroying the container, make sure to keep a clone
|
||||
// of each of them at document level so they can be re-appended on reframe.
|
||||
@ -199,8 +297,8 @@ nsCanvasFrame::AppendFrames(ChildListID aListID,
|
||||
MOZ_ASSERT(aListID == kPrincipalList, "unexpected child list");
|
||||
if (!mFrames.IsEmpty()) {
|
||||
for (nsFrameList::Enumerator e(aFrameList); !e.AtEnd(); e.Next()) {
|
||||
// We only allow native anonymous child frames to be in principal child
|
||||
// list in canvas frame.
|
||||
// We only allow native anonymous child frame for touch caret,
|
||||
// which its placeholder is added to the Principal child lists.
|
||||
MOZ_ASSERT(e.get()->GetContent()->IsInNativeAnonymousSubtree(),
|
||||
"invalid child list");
|
||||
}
|
||||
@ -429,6 +527,15 @@ nsCanvasFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
||||
|
||||
nsIFrame* kid;
|
||||
for (kid = GetFirstPrincipalChild(); kid; kid = kid->GetNextSibling()) {
|
||||
// Skip touch/selection caret frame if we do not build caret.
|
||||
if (!aBuilder->IsBuildingCaret()) {
|
||||
if(kid->GetContent() == mTouchCaretElement ||
|
||||
kid->GetContent() == mSelectionCaretsStartElement||
|
||||
kid->GetContent() == mSelectionCaretsEndElement) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Put our child into its own pseudo-stack.
|
||||
BuildDisplayListForChild(aBuilder, kid, aDirtyRect, aLists);
|
||||
}
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include "nsIScrollPositionListener.h"
|
||||
#include "nsDisplayList.h"
|
||||
#include "nsIAnonymousContentCreator.h"
|
||||
#include "nsIDOMEventListener.h"
|
||||
|
||||
class nsPresContext;
|
||||
class nsRenderingContext;
|
||||
@ -82,6 +83,23 @@ public:
|
||||
virtual nsresult CreateAnonymousContent(nsTArray<ContentInfo>& aElements) override;
|
||||
virtual void AppendAnonymousContentTo(nsTArray<nsIContent*>& aElements, uint32_t aFilter) override;
|
||||
|
||||
// Touch caret handle function
|
||||
mozilla::dom::Element* GetTouchCaretElement() const
|
||||
{
|
||||
return mTouchCaretElement;
|
||||
}
|
||||
|
||||
// Selection Caret Handle function
|
||||
mozilla::dom::Element* GetSelectionCaretsStartElement() const
|
||||
{
|
||||
return mSelectionCaretsStartElement;
|
||||
}
|
||||
|
||||
mozilla::dom::Element* GetSelectionCaretsEndElement() const
|
||||
{
|
||||
return mSelectionCaretsEndElement;
|
||||
}
|
||||
|
||||
mozilla::dom::Element* GetCustomContentContainer() const
|
||||
{
|
||||
return mCustomContentContainer;
|
||||
@ -147,7 +165,28 @@ protected:
|
||||
bool mDoPaintFocus;
|
||||
bool mAddedScrollPositionListener;
|
||||
|
||||
nsCOMPtr<mozilla::dom::Element> mTouchCaretElement;
|
||||
nsCOMPtr<mozilla::dom::Element> mSelectionCaretsStartElement;
|
||||
nsCOMPtr<mozilla::dom::Element> mSelectionCaretsEndElement;
|
||||
nsCOMPtr<mozilla::dom::Element> mCustomContentContainer;
|
||||
|
||||
class DummyTouchListener final : public nsIDOMEventListener
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
NS_IMETHOD HandleEvent(nsIDOMEvent* aEvent) override
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
private:
|
||||
~DummyTouchListener() {}
|
||||
};
|
||||
|
||||
/**
|
||||
* A no-op touch-listener used for APZ purposes.
|
||||
*/
|
||||
RefPtr<DummyTouchListener> mDummyTouchListener;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -51,6 +51,9 @@ static NS_DEFINE_CID(kFrameTraversalCID, NS_FRAMETRAVERSAL_CID);
|
||||
#include "nsPresContext.h"
|
||||
#include "nsIPresShell.h"
|
||||
#include "nsCaret.h"
|
||||
#include "TouchCaret.h"
|
||||
#include "SelectionCarets.h"
|
||||
|
||||
#include "AccessibleCaretEventHub.h"
|
||||
|
||||
#include "mozilla/MouseEvents.h"
|
||||
@ -820,6 +823,24 @@ nsFrameSelection::Init(nsIPresShell *aShell, nsIContent *aLimiter)
|
||||
"dom.select_events.enabled", false);
|
||||
}
|
||||
|
||||
// Set touch caret as selection listener
|
||||
RefPtr<TouchCaret> touchCaret = mShell->GetTouchCaret();
|
||||
if (touchCaret) {
|
||||
int8_t index = GetIndexFromSelectionType(nsISelectionController::SELECTION_NORMAL);
|
||||
if (mDomSelections[index]) {
|
||||
mDomSelections[index]->AddSelectionListener(touchCaret);
|
||||
}
|
||||
}
|
||||
|
||||
// Set selection caret as selection listener
|
||||
RefPtr<SelectionCarets> selectionCarets = mShell->GetSelectionCarets();
|
||||
if (selectionCarets) {
|
||||
int8_t index = GetIndexFromSelectionType(nsISelectionController::SELECTION_NORMAL);
|
||||
if (mDomSelections[index]) {
|
||||
mDomSelections[index]->AddSelectionListener(selectionCarets);
|
||||
}
|
||||
}
|
||||
|
||||
RefPtr<AccessibleCaretEventHub> eventHub = mShell->GetAccessibleCaretEventHub();
|
||||
if (eventHub) {
|
||||
int8_t index = GetIndexFromSelectionType(nsISelectionController::SELECTION_NORMAL);
|
||||
@ -3269,6 +3290,19 @@ nsFrameSelection::SetDelayedCaretData(WidgetMouseEvent* aMouseEvent)
|
||||
void
|
||||
nsFrameSelection::DisconnectFromPresShell()
|
||||
{
|
||||
// Remove touch caret as selection listener
|
||||
RefPtr<TouchCaret> touchCaret = mShell->GetTouchCaret();
|
||||
if (touchCaret) {
|
||||
int8_t index = GetIndexFromSelectionType(nsISelectionController::SELECTION_NORMAL);
|
||||
mDomSelections[index]->RemoveSelectionListener(touchCaret);
|
||||
}
|
||||
|
||||
RefPtr<SelectionCarets> selectionCarets = mShell->GetSelectionCarets();
|
||||
if (selectionCarets) {
|
||||
int8_t index = GetIndexFromSelectionType(nsISelectionController::SELECTION_NORMAL);
|
||||
mDomSelections[index]->RemoveSelectionListener(selectionCarets);
|
||||
}
|
||||
|
||||
RefPtr<AccessibleCaretEventHub> eventHub = mShell->GetAccessibleCaretEventHub();
|
||||
if (eventHub) {
|
||||
int8_t index = GetIndexFromSelectionType(nsISelectionController::SELECTION_NORMAL);
|
||||
|
@ -417,6 +417,114 @@ div:-moz-native-anonymous.moz-accessiblecaret.none {
|
||||
}
|
||||
}
|
||||
|
||||
div:-moz-native-anonymous.moz-touchcaret,
|
||||
div:-moz-native-anonymous.moz-selectioncaret-left,
|
||||
div:-moz-native-anonymous.moz-selectioncaret-right {
|
||||
position: fixed;
|
||||
width: 44px;
|
||||
height: 47px;
|
||||
}
|
||||
|
||||
div:-moz-native-anonymous.moz-selectioncaret-left > div,
|
||||
div:-moz-native-anonymous.moz-selectioncaret-right > div {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
div:-moz-native-anonymous.moz-touchcaret,
|
||||
div:-moz-native-anonymous.moz-selectioncaret-left,
|
||||
div:-moz-native-anonymous.moz-selectioncaret-right,
|
||||
div:-moz-native-anonymous.moz-selectioncaret-left > div,
|
||||
div:-moz-native-anonymous.moz-selectioncaret-right > div {
|
||||
background-position: center bottom;
|
||||
background-size: 100%;
|
||||
background-repeat: no-repeat;
|
||||
z-index: 2147483647;
|
||||
}
|
||||
|
||||
div:-moz-native-anonymous.moz-touchcaret,
|
||||
div:-moz-native-anonymous.moz-selectioncaret-left > div,
|
||||
div:-moz-native-anonymous.moz-selectioncaret-right > div {
|
||||
background-image: url("resource://gre/res/text_caret.png");
|
||||
}
|
||||
|
||||
div:-moz-native-anonymous.moz-touchcaret,
|
||||
div:-moz-native-anonymous.moz-selectioncaret-left,
|
||||
div:-moz-native-anonymous.moz-selectioncaret-right {
|
||||
margin-left: -23px;
|
||||
}
|
||||
|
||||
div:-moz-native-anonymous.moz-selectioncaret-left.tilt > div {
|
||||
background-image: url("resource://gre/res/text_caret_tilt_left.png");
|
||||
margin-left: -17px;
|
||||
}
|
||||
|
||||
div:-moz-native-anonymous.moz-selectioncaret-right.tilt > div {
|
||||
background-image: url("resource://gre/res/text_caret_tilt_right.png");
|
||||
margin-left: 18px;
|
||||
}
|
||||
|
||||
@media (min-resolution: 1.5dppx) {
|
||||
div:-moz-native-anonymous.moz-touchcaret,
|
||||
div:-moz-native-anonymous.moz-selectioncaret-left > div,
|
||||
div:-moz-native-anonymous.moz-selectioncaret-right > div {
|
||||
background-image: url("resource://gre/res/text_caret@1.5x.png");
|
||||
}
|
||||
|
||||
div:-moz-native-anonymous.moz-selectioncaret-left.tilt > div {
|
||||
background-image: url("resource://gre/res/text_caret_tilt_left@1.5x.png");
|
||||
}
|
||||
|
||||
div:-moz-native-anonymous.moz-selectioncaret-right.tilt > div {
|
||||
background-image: url("resource://gre/res/text_caret_tilt_right@1.5x.png");
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-resolution: 2dppx) {
|
||||
div:-moz-native-anonymous.moz-touchcaret,
|
||||
div:-moz-native-anonymous.moz-selectioncaret-left > div,
|
||||
div:-moz-native-anonymous.moz-selectioncaret-right > div {
|
||||
background-image: url("resource://gre/res/text_caret@2x.png");
|
||||
}
|
||||
|
||||
div:-moz-native-anonymous.moz-selectioncaret-left.tilt > div {
|
||||
background-image: url("resource://gre/res/text_caret_tilt_left@2x.png");
|
||||
}
|
||||
|
||||
div:-moz-native-anonymous.moz-selectioncaret-right.tilt > div {
|
||||
background-image: url("resource://gre/res/text_caret_tilt_right@2x.png");
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-resolution: 2.25dppx) {
|
||||
div:-moz-native-anonymous.moz-touchcaret,
|
||||
div:-moz-native-anonymous.moz-selectioncaret-left > div,
|
||||
div:-moz-native-anonymous.moz-selectioncaret-right > div {
|
||||
background-image: url("resource://gre/res/text_caret@2.25x.png");
|
||||
}
|
||||
|
||||
div:-moz-native-anonymous.moz-selectioncaret-left.tilt > div {
|
||||
background-image: url("resource://gre/res/text_caret_tilt_left@2.25x.png");
|
||||
}
|
||||
|
||||
div:-moz-native-anonymous.moz-selectioncaret-right.tilt > div {
|
||||
background-image: url("resource://gre/res/text_caret_tilt_right@2.25x.png");
|
||||
}
|
||||
}
|
||||
|
||||
div:-moz-native-anonymous.moz-touchcaret.hidden,
|
||||
div:-moz-native-anonymous.moz-selectioncaret-left.hidden,
|
||||
div:-moz-native-anonymous.moz-selectioncaret-right.hidden,
|
||||
div:-moz-native-anonymous.moz-selectioncaret-left.hidden > div,
|
||||
div:-moz-native-anonymous.moz-selectioncaret-right.hidden > div {
|
||||
width: 0px;
|
||||
height: 0px;
|
||||
margin: 0px;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
/* Custom content container in the CanvasFrame, fixed positioned on top of
|
||||
everything else, not reacting to pointer events. */
|
||||
div:-moz-native-anonymous.moz-custom-content-container {
|
||||
|
@ -51,6 +51,9 @@
|
||||
// reflow so that that rare edge case doesn't lead to reftest
|
||||
// failures.
|
||||
branch.setBoolPref("layout.interruptible-reflow.enabled", false);
|
||||
// Disable the auto-hide feature of touch caret to avoid potential
|
||||
// intermittent issues.
|
||||
branch.setIntPref("touchcaret.expiration.time", 0);
|
||||
|
||||
// Tell the search service we are running in the US. This also has the
|
||||
// desired side-effect of preventing our geoip lookup.
|
||||
|
@ -543,18 +543,18 @@
|
||||
@BINPATH@/res/language.properties
|
||||
@BINPATH@/res/entityTables/*
|
||||
#ifdef NIGHTLY_BUILD
|
||||
@BINPATH@/res/accessiblecaret.png
|
||||
@BINPATH@/res/accessiblecaret@1.5x.png
|
||||
@BINPATH@/res/accessiblecaret@2.25x.png
|
||||
@BINPATH@/res/accessiblecaret@2x.png
|
||||
@BINPATH@/res/accessiblecaret_tilt_left.png
|
||||
@BINPATH@/res/accessiblecaret_tilt_left@1.5x.png
|
||||
@BINPATH@/res/accessiblecaret_tilt_left@2.25x.png
|
||||
@BINPATH@/res/accessiblecaret_tilt_left@2x.png
|
||||
@BINPATH@/res/accessiblecaret_tilt_right.png
|
||||
@BINPATH@/res/accessiblecaret_tilt_right@1.5x.png
|
||||
@BINPATH@/res/accessiblecaret_tilt_right@2.25x.png
|
||||
@BINPATH@/res/accessiblecaret_tilt_right@2x.png
|
||||
@BINPATH@/res/text_caret.png
|
||||
@BINPATH@/res/text_caret@1.5x.png
|
||||
@BINPATH@/res/text_caret@2.25x.png
|
||||
@BINPATH@/res/text_caret@2x.png
|
||||
@BINPATH@/res/text_caret_tilt_left.png
|
||||
@BINPATH@/res/text_caret_tilt_left@1.5x.png
|
||||
@BINPATH@/res/text_caret_tilt_left@2.25x.png
|
||||
@BINPATH@/res/text_caret_tilt_left@2x.png
|
||||
@BINPATH@/res/text_caret_tilt_right.png
|
||||
@BINPATH@/res/text_caret_tilt_right@1.5x.png
|
||||
@BINPATH@/res/text_caret_tilt_right@2.25x.png
|
||||
@BINPATH@/res/text_caret_tilt_right@2x.png
|
||||
#endif
|
||||
|
||||
#ifndef MOZ_ANDROID_EXCLUDE_FONTS
|
||||
|
@ -4856,6 +4856,25 @@ pref("browser.safebrowsing.allowOverride", true);
|
||||
// Turn off Spatial navigation by default.
|
||||
pref("snav.enabled", false);
|
||||
|
||||
// Original caret implementation on collapsed selection.
|
||||
pref("touchcaret.enabled", false);
|
||||
|
||||
// This will inflate the size of the touch caret frame when checking if user
|
||||
// clicks on the caret or not. In app units.
|
||||
pref("touchcaret.inflatesize.threshold", 40);
|
||||
|
||||
// We'll start to increment time when user release the control of touch caret.
|
||||
// When time exceed this expiration time, we'll hide touch caret.
|
||||
// In milliseconds. (0 means disable this feature)
|
||||
pref("touchcaret.expiration.time", 3000);
|
||||
|
||||
// Original caret implementation on non-collapsed selection.
|
||||
pref("selectioncaret.enabled", false);
|
||||
|
||||
// This will inflate size of selection caret frame when we checking if
|
||||
// user click on selection caret or not. In app units.
|
||||
pref("selectioncaret.inflatesize.threshold", 40);
|
||||
|
||||
// New implementation to unify touch-caret and selection-carets.
|
||||
pref("layout.accessiblecaret.enabled", false);
|
||||
|
||||
|
@ -9,3 +9,4 @@ user_pref("dom.mozBrowserFramesEnabled", "%(OOP)s");
|
||||
user_pref("dom.mozBrowserFramesWhitelist","app://test-container.gaiamobile.org,http://mochi.test:8888");
|
||||
user_pref("dom.testing.datastore_enabled_for_hosted_apps", true);
|
||||
user_pref("marionette.force-local", true);
|
||||
user_pref("touchcaret.expiration.time", 0);
|
||||
|