Bug 924692 - Part 4: Hooks up event handling to TouchCaret; r=roc, bugs

This commit is contained in:
Phoebe Chang 2014-06-03 15:08:54 +08:00
parent 5413497932
commit 943fc38329
15 changed files with 192 additions and 18 deletions

View File

@ -976,6 +976,9 @@ pref("browser.autofocus", false);
// Enable wakelock
pref("dom.wakelock.enabled", true);
// Disable touch caret by default
pref("touchcaret.enabled", false);
// Enable sync and mozId with Firefox Accounts.
#ifdef MOZ_SERVICES_FXACCOUNTS
pref("services.sync.fxaccounts.enabled", true);

View File

@ -2166,8 +2166,12 @@ nsFocusManager::SetCaretVisible(nsIPresShell* aPresShell,
nsISelection* domSelection = docFrameSelection->
GetSelection(nsISelectionController::SELECTION_NORMAL);
if (domSelection) {
nsCOMPtr<nsISelectionController> selCon(do_QueryInterface(aPresShell));
if (!selCon) {
return NS_ERROR_FAILURE;
}
// First, hide the caret to prevent attempting to show it in SetCaretDOMSelection
caret->SetCaretVisible(false);
selCon->SetCaretEnabled(false);
// Caret must blink on non-editable elements
caret->SetIgnoreUserModify(true);
@ -2178,13 +2182,8 @@ nsFocusManager::SetCaretVisible(nsIPresShell* aPresShell,
// fields, which have a different frame selection from the document.
// They will take care of making the caret visible themselves.
nsCOMPtr<nsISelectionController> selCon(do_QueryInterface(aPresShell));
if (!selCon)
return NS_ERROR_FAILURE;
selCon->SetCaretReadOnly(false);
selCon->SetCaretEnabled(aVisible);
caret->SetCaretVisible(aVisible);
}
}

View File

@ -570,7 +570,7 @@ nsPIDOMWindow::nsPIDOMWindow(nsPIDOMWindow *aOuterWindow)
mRunningTimeout(nullptr), mMutationBits(0), mIsDocumentLoaded(false),
mIsHandlingResizeEvent(false), mIsInnerWindow(aOuterWindow != nullptr),
mMayHavePaintEventListener(false), mMayHaveTouchEventListener(false),
mMayHaveMouseEnterLeaveEventListener(false),
mMayHaveTouchCaret(false), mMayHaveMouseEnterLeaveEventListener(false),
mMayHavePointerEnterLeaveEventListener(false),
mIsModalContentWindow(false),
mIsActive(false), mIsBackground(false),

View File

@ -60,8 +60,8 @@ enum UIStateChangeType
};
#define NS_PIDOMWINDOW_IID \
{ 0xf26953de, 0xa799, 0x4a92, \
{ 0x87, 0x49, 0x7c, 0x37, 0xe5, 0x90, 0x3f, 0x37 } }
{ 0x33403513, 0x6e4a, 0x4985, \
{ 0x99, 0x8d, 0xfc, 0x02, 0x81, 0x6e, 0xb9, 0xf2 } }
class nsPIDOMWindow : public nsIDOMWindowInternal
{
@ -468,6 +468,21 @@ public:
return mMayHaveTouchEventListener;
}
/**
* Will be called when touch caret visibility has changed. mMayHaveTouchCaret
* is set if that some node (this window, its document, or content in that
* document) has a visible touch caret.
*/
void SetMayHaveTouchCaret(bool aSetValue)
{
mMayHaveTouchCaret = aSetValue;
}
bool MayHaveTouchCaret()
{
return mMayHaveTouchCaret;
}
/**
* Moves the top-level window into fullscreen mode if aIsFullScreen is true,
* otherwise exits fullscreen. If aRequireTrust is true, this method only
@ -761,6 +776,7 @@ protected:
bool mIsInnerWindow;
bool mMayHavePaintEventListener;
bool mMayHaveTouchEventListener;
bool mMayHaveTouchCaret;
bool mMayHaveMouseEnterLeaveEventListener;
bool mMayHavePointerEnterLeaveEventListener;

View File

@ -2009,7 +2009,8 @@ TabChild::RecvRealTouchEvent(const WidgetTouchEvent& aEvent,
nsCOMPtr<nsPIDOMWindow> outerWindow = do_GetInterface(WebNavigation());
nsCOMPtr<nsPIDOMWindow> innerWindow = outerWindow->GetCurrentInnerWindow();
if (!innerWindow || !innerWindow->HasTouchEventListeners()) {
if (!innerWindow || (!innerWindow->HasTouchEventListeners() &&
!innerWindow->MayHaveTouchCaret())) {
SendContentReceivedTouch(aGuid, false);
return true;
}

View File

@ -731,6 +731,10 @@ nsEditorEventListener::CleanupDragDropCaret()
nsCOMPtr<nsIPresShell> presShell = GetPresShell();
if (presShell)
{
nsCOMPtr<nsISelectionController> selCon(do_QueryInterface(presShell));
if (selCon) {
selCon->SetCaretEnabled(false);
}
presShell->RestoreCaret();
}

View File

@ -758,6 +758,7 @@ struct ParamTraits<mozilla::layers::FrameMetrics>
WriteParam(aMsg, aParam.mZoom);
WriteParam(aMsg, aParam.mDevPixelsPerCSSPixel);
WriteParam(aMsg, aParam.mMayHaveTouchListeners);
WriteParam(aMsg, aParam.mMayHaveTouchCaret);
WriteParam(aMsg, aParam.mPresShellId);
WriteParam(aMsg, aParam.mIsRoot);
WriteParam(aMsg, aParam.mHasScrollgrab);
@ -785,6 +786,7 @@ struct ParamTraits<mozilla::layers::FrameMetrics>
ReadParam(aMsg, aIter, &aResult->mZoom) &&
ReadParam(aMsg, aIter, &aResult->mDevPixelsPerCSSPixel) &&
ReadParam(aMsg, aIter, &aResult->mMayHaveTouchListeners) &&
ReadParam(aMsg, aIter, &aResult->mMayHaveTouchCaret) &&
ReadParam(aMsg, aIter, &aResult->mPresShellId) &&
ReadParam(aMsg, aIter, &aResult->mIsRoot) &&
ReadParam(aMsg, aIter, &aResult->mHasScrollgrab) &&

View File

@ -81,6 +81,7 @@ public:
, mTransformScale(1)
, mDevPixelsPerCSSPixel(1)
, mMayHaveTouchListeners(false)
, mMayHaveTouchCaret(false)
, mIsRoot(false)
, mHasScrollgrab(false)
, mScrollId(NULL_SCROLL_ID)
@ -113,6 +114,7 @@ public:
mCumulativeResolution == aOther.mCumulativeResolution &&
mDevPixelsPerCSSPixel == aOther.mDevPixelsPerCSSPixel &&
mMayHaveTouchListeners == aOther.mMayHaveTouchListeners &&
mMayHaveTouchCaret == aOther.mMayHaveTouchCaret &&
mPresShellId == aOther.mPresShellId &&
mIsRoot == aOther.mIsRoot &&
mScrollId == aOther.mScrollId &&
@ -344,6 +346,9 @@ public:
// Whether or not this frame may have touch listeners.
bool mMayHaveTouchListeners;
// Whether or not this frame may have touch caret.
bool mMayHaveTouchCaret;
// Whether or not this is the root scroll frame for the root content document.
bool mIsRoot;

View File

@ -647,7 +647,8 @@ nsEventStatus AsyncPanZoomController::ReceiveInputEvent(const InputData& aEvent)
// enable as it introduces potentially unbounded lag because it causes a round-trip through
// content. Usually, if content is responding in a timely fashion, this only introduces a
// nearly constant few hundred ms of lag.
if (mFrameMetrics.mMayHaveTouchListeners && aEvent.mInputType == MULTITOUCH_INPUT &&
if ((mFrameMetrics.mMayHaveTouchListeners || mFrameMetrics.mMayHaveTouchCaret) &&
aEvent.mInputType == MULTITOUCH_INPUT &&
(mState == NOTHING || mState == TOUCHING || IsPanningState(mState))) {
const MultiTouchInput& multiTouchInput = aEvent.AsMultiTouchInput();
if (multiTouchInput.mType == MultiTouchInput::MULTITOUCH_START) {
@ -2034,6 +2035,7 @@ void AsyncPanZoomController::NotifyLayersUpdated(const FrameMetrics& aLayerMetri
UpdateTransformScale();
mFrameMetrics.mMayHaveTouchListeners = aLayerMetrics.mMayHaveTouchListeners;
mFrameMetrics.mMayHaveTouchCaret = aLayerMetrics.mMayHaveTouchCaret;
APZC_LOG_FM(aLayerMetrics, "%p got a NotifyLayersUpdated with aIsFirstPaint=%d", this, aIsFirstPaint);
LogRendertraceRect(GetGuid(), "page", "brown", aLayerMetrics.mScrollableRect);
@ -2243,7 +2245,8 @@ void AsyncPanZoomController::ContentReceivedTouch(bool aPreventDefault) {
void AsyncPanZoomController::CheckContentResponse() {
bool canProceedToTouchState = true;
if (mFrameMetrics.mMayHaveTouchListeners) {
if (mFrameMetrics.mMayHaveTouchListeners ||
mFrameMetrics.mMayHaveTouchCaret) {
canProceedToTouchState &= mTouchBlockState.mPreventDefaultSet;
}

View File

@ -112,6 +112,12 @@ TouchCaret::SetVisibility(bool aVisible)
err);
// Set touch caret expiration time.
mVisible ? LaunchExpirationTimer() : CancelExpirationTimer();
// We must call SetHasTouchCaret() in order to get APZC to wait until the
// event has been round-tripped and check whether it has been handled,
// otherwise B2G will end up panning the document when the user tries to drag
// touch caret.
presShell->SetMayHaveTouchCaret(mVisible);
}
nsRect

View File

@ -719,6 +719,7 @@ static void RecordFrameMetrics(nsIFrame* aForFrame,
metrics.mMayHaveTouchListeners = innerWin->HasTouchEventListeners();
}
}
metrics.mMayHaveTouchCaret = presShell->MayHaveTouchCaret();
}
LayoutDeviceToParentLayerScale layoutToParentLayerScale =

View File

@ -56,6 +56,9 @@ class nsIPageSequenceFrame;
class nsCanvasFrame;
class nsAString;
class nsCaret;
namespace mozilla {
class TouchCaret;
} // namespace mozilla
class nsFrameSelection;
class nsFrameManager;
class nsILayoutHistoryState;
@ -133,10 +136,10 @@ typedef struct CapturingContentInfo {
nsIContent* mContent;
} CapturingContentInfo;
//61e60df7-128a-4cdd-a684-5f0bd2ceb61f
//a4e5ff3a-dc5c-4b3a-a625-d164a9e50619
#define NS_IPRESSHELL_IID \
{ 0x61e60df7, 0x128a, 0x4cdd, \
{0xa6, 0x84, 0x5f, 0x0b, 0xd2, 0xce, 0xb6, 0x1f}}
{ 0xa4e5ff3a, 0xdc5c, 0x4b3a, \
{0xa6, 0x25, 0xd1, 0x64, 0xa9, 0xe5, 0x06, 0x19}}
// debug VerifyReflow flags
#define VERIFY_REFLOW_ON 0x01
@ -742,11 +745,27 @@ 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;
/**
* Will be called when touch caret visibility has changed.
* Set the mMayHaveTouchCaret flag to aSet.
*/
virtual void SetMayHaveTouchCaret(bool aSet) = 0;
/**
* Get the mMayHaveTouchCaret flag.
*/
virtual bool MayHaveTouchCaret() = 0;
/**
* Get the caret, if it exists. AddRefs it.
*/

View File

@ -75,6 +75,7 @@
#include "nsReadableUtils.h"
#include "nsIPageSequenceFrame.h"
#include "nsCaret.h"
#include "TouchCaret.h"
#include "nsIDOMHTMLDocument.h"
#include "nsFrameManager.h"
#include "nsXPCOM.h"
@ -863,6 +864,11 @@ PresShell::Init(nsIDocument* aDocument,
// before creating any frames.
SetPreferenceStyleRules(false);
if (TouchCaretPrefEnabled()) {
// Create touch caret handle
mTouchCaret = new TouchCaret(this);
}
NS_ADDREF(mSelection = new nsFrameSelection());
mSelection->Init(this, nullptr);
@ -1119,6 +1125,11 @@ PresShell::Destroy()
mSelection->DisconnectFromPresShell();
}
if (mTouchCaret) {
mTouchCaret->Terminate();
mTouchCaret = nullptr;
}
// release our pref style sheet, if we have one still
ClearPreferenceStyleRules();
@ -2146,6 +2157,13 @@ already_AddRefed<nsCaret> PresShell::GetCaret() const
return caret.forget();
}
// TouchCaret
already_AddRefed<TouchCaret> PresShell::GetTouchCaret() const
{
nsRefPtr<TouchCaret> touchCaret = mTouchCaret;
return touchCaret.forget();
}
void PresShell::MaybeInvalidateCaretPosition()
{
if (mCaret) {
@ -2169,14 +2187,21 @@ NS_IMETHODIMP PresShell::SetCaretEnabled(bool aInEnable)
mCaretEnabled = aInEnable;
if (mCaret && (mCaretEnabled != oldEnabled))
if (mCaretEnabled != oldEnabled)
{
/* Don't change the caret's selection here! This was an evil side-effect of SetCaretEnabled()
nsCOMPtr<nsIDOMSelection> domSel;
if (NS_SUCCEEDED(GetSelection(nsISelectionController::SELECTION_NORMAL, getter_AddRefs(domSel))) && domSel)
mCaret->SetCaretDOMSelection(domSel);
*/
mCaret->SetCaretVisible(mCaretEnabled);
MOZ_ASSERT(mCaret || mTouchCaret);
if (mCaret) {
mCaret->SetCaretVisible(mCaretEnabled);
}
if (mTouchCaret) {
mTouchCaret->UpdateTouchCaret(mCaretEnabled);
}
}
return NS_OK;
@ -2497,6 +2522,52 @@ PresShell::GetTouchCaretElement() const
return GetCanvasFrame() ? GetCanvasFrame()->GetTouchCaretElement() : nullptr;
}
void
PresShell::SetMayHaveTouchCaret(bool aSet)
{
if (!mPresContext) {
return;
}
if (!mPresContext->IsRoot()) {
nsIPresShell* rootPresShell = GetRootPresShell();
if (rootPresShell) {
rootPresShell->SetMayHaveTouchCaret(aSet);
}
return;
}
nsIDocument* document = GetDocument();
if (document) {
nsPIDOMWindow* innerWin = document->GetInnerWindow();
if (innerWin) {
innerWin->SetMayHaveTouchCaret(aSet);
}
}
}
bool
PresShell::MayHaveTouchCaret()
{
if (!mPresContext) {
return false;
}
if (!mPresContext->IsRoot()) {
nsIPresShell* rootPresShell = GetRootPresShell();
return rootPresShell ? rootPresShell->MayHaveTouchCaret() : false;
}
nsIDocument* document = GetDocument();
if (document) {
nsPIDOMWindow* innerWin = document->GetInnerWindow();
if (innerWin) {
return innerWin->MayHaveTouchCaret();
}
}
return false;
}
void
PresShell::BeginUpdate(nsIDocument *aDocument, nsUpdateType aUpdateType)
{
@ -6561,6 +6632,29 @@ PresShell::HandleEvent(nsIFrame* aFrame,
}
RecordMouseLocation(aEvent);
// Determine whether event need to be consumed by touch caret or not.
if (TouchCaretPrefEnabled()) {
// 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;
nsRefPtr<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;
}
}
}
if (sPointerEventEnabled) {
UpdateActivePointerState(aEvent);
}
@ -8135,7 +8229,7 @@ PresShell::Freeze()
mDocument->EnumerateFreezableElements(FreezeElement, nullptr);
if (mCaret) {
mCaret->SetCaretVisible(false);
SetCaretEnabled(false);
}
mPaintingSuppressed = true;

View File

@ -212,7 +212,10 @@ public:
virtual bool IsVisible() MOZ_OVERRIDE;
// touch caret
virtual already_AddRefed<mozilla::TouchCaret> GetTouchCaret() const MOZ_OVERRIDE;
virtual mozilla::dom::Element* GetTouchCaretElement() const MOZ_OVERRIDE;
virtual void SetMayHaveTouchCaret(bool aSet) MOZ_OVERRIDE;
virtual bool MayHaveTouchCaret() MOZ_OVERRIDE;
// caret handling
virtual already_AddRefed<nsCaret> GetCaret() const MOZ_OVERRIDE;
virtual void MaybeInvalidateCaretPosition() MOZ_OVERRIDE;
@ -766,6 +769,9 @@ protected:
nsCallbackEventRequest* mFirstCallbackEventRequest;
nsCallbackEventRequest* mLastCallbackEventRequest;
// TouchCaret
nsRefPtr<mozilla::TouchCaret> mTouchCaret;
// This timer controls painting suppression. Until it fires
// or all frames are constructed, we won't paint anything but
// our <body> background and scrollbars.

View File

@ -53,6 +53,7 @@ static NS_DEFINE_CID(kFrameTraversalCID, NS_FRAMETRAVERSAL_CID);
#include "nsPresContext.h"
#include "nsIPresShell.h"
#include "nsCaret.h"
#include "TouchCaret.h"
#include "mozilla/MouseEvents.h"
#include "mozilla/TextEvents.h"
@ -693,6 +694,14 @@ nsFrameSelection::Init(nsIPresShell *aShell, nsIContent *aLimiter)
mLimiter = aLimiter;
mCaretMovementStyle =
Preferences::GetInt("bidi.edit.caret_movement_style", 2);
// Set touch caret as selection listener
nsRefPtr<TouchCaret> touchCaret = mShell->GetTouchCaret();
if (touchCaret) {
int8_t index = GetIndexFromSelectionType(nsISelectionController::SELECTION_NORMAL);
if (mDomSelections[index]) {
mDomSelections[index]->AddSelectionListener(touchCaret);
}
}
}
nsresult
@ -3011,6 +3020,12 @@ nsFrameSelection::SetDelayedCaretData(WidgetMouseEvent* aMouseEvent)
void
nsFrameSelection::DisconnectFromPresShell()
{
// Remove touch caret as selection listener
nsRefPtr<TouchCaret> touchCaret = mShell->GetTouchCaret();
if (touchCaret) {
int8_t index = GetIndexFromSelectionType(nsISelectionController::SELECTION_NORMAL);
mDomSelections[index]->RemoveSelectionListener(touchCaret);
}
StopAutoScrollTimer();
for (int32_t i = 0; i < nsISelectionController::NUM_SELECTIONTYPES; i++) {
mDomSelections[i]->Clear(nullptr);