Bug 1016184 - Part 3b: Revise touch caret visibility logic. f=pchang, r=ehsan

* Refactor UpdateTouchCaret() into smaller functions.
* Update touch caret in PresShell::DidDoReflow() and
  PresShell::UnsuppressAndInvalidate() if needed.
This commit is contained in:
Ting-Yu Lin 2014-07-27 00:15:00 +02:00
parent ac20b2f613
commit 4099ebe260
3 changed files with 107 additions and 35 deletions

View File

@ -58,7 +58,7 @@ TouchCaret::TouchCaret(nsIPresShell* aPresShell)
mCaretCenterToDownPointOffsetY(0),
mVisible(false)
{
TOUCHCARET_LOG("Constructor");
TOUCHCARET_LOG("Constructor, PresShell=%p", aPresShell);
MOZ_ASSERT(NS_IsMainThread());
static bool addedTouchCaretPref = false;
@ -100,27 +100,29 @@ void
TouchCaret::SetVisibility(bool aVisible)
{
if (mVisible == aVisible) {
TOUCHCARET_LOG("Visibility not changed");
TOUCHCARET_LOG("Set visibility %s, same as the old one",
(aVisible ? "shown" : "hidden"));
return;
}
mVisible = aVisible;
nsCOMPtr<nsIPresShell> presShell = do_QueryReferent(mPresShell);
if (!presShell) {
return;
}
mozilla::dom::Element* touchCaretElement = presShell->GetTouchCaretElement();
if (!touchCaretElement) {
return;
}
mVisible = aVisible;
// Set touch caret visibility.
ErrorResult err;
touchCaretElement->ClassList()->Toggle(NS_LITERAL_STRING("hidden"),
dom::Optional<bool>(!mVisible),
err);
TOUCHCARET_LOG("Visibility %s", (mVisible ? "shown" : "hidden"));
TOUCHCARET_LOG("Set visibility %s", (mVisible ? "shown" : "hidden"));
// Set touch caret expiration time.
mVisible ? LaunchExpirationTimer() : CancelExpirationTimer();
@ -331,6 +333,8 @@ nsresult
TouchCaret::NotifySelectionChanged(nsIDOMDocument* aDoc, nsISelection* aSel,
int16_t aReason)
{
TOUCHCARET_LOG("Reason=%d", aReason);
// Hide touch caret while no caret exists.
nsCOMPtr<nsIPresShell> presShell = do_QueryReferent(mPresShell);
if (!presShell) {
@ -349,52 +353,110 @@ TouchCaret::NotifySelectionChanged(nsIDOMDocument* aDoc, nsISelection* aSel,
// If this notification is for a selection that is not the one the
// the caret is currently interested in , then there is nothing to do!
if (aSel != caret->GetCaretDOMSelection()) {
TOUCHCARET_LOG("Return for selection mismatch!");
return NS_OK;
}
// Update touch caret position and visibility.
// Hide touch caret while key event causes selection change.
if ((aReason == nsISelectionListener::NO_REASON) ||
(aReason & nsISelectionListener::KEYPRESS_REASON)) {
UpdateTouchCaret(false);
if (aReason & nsISelectionListener::KEYPRESS_REASON) {
TOUCHCARET_LOG("KEYPRESS_REASON");
SetVisibility(false);
} else {
UpdateTouchCaret(true);
SyncVisibilityWithCaret();
}
return NS_OK;
}
void
TouchCaret::UpdateTouchCaret(bool aVisible)
TouchCaret::SyncVisibilityWithCaret()
{
TOUCHCARET_LOG("SyncVisibilityWithCaret");
if (IsDisplayable()) {
SetVisibility(true);
UpdatePosition();
} else {
SetVisibility(false);
}
}
void
TouchCaret::UpdatePositionIfNeeded()
{
TOUCHCARET_LOG("UpdatePositionIfNeeded");
if (IsDisplayable()) {
if (mVisible) {
UpdatePosition();
}
} else {
SetVisibility(false);
}
}
bool
TouchCaret::IsDisplayable()
{
// Hide touch caret while no caret exists.
nsCOMPtr<nsIPresShell> presShell = do_QueryReferent(mPresShell);
if (!presShell) {
return;
TOUCHCARET_LOG("PresShell is nullptr!");
return false;
}
nsRefPtr<nsCaret> caret = presShell->GetCaret();
if (!caret) {
SetVisibility(false);
return;
TOUCHCARET_LOG("Caret is nullptr!");
return false;
}
nsIFrame* canvasFrame = GetCanvasFrame();
if (!canvasFrame) {
TOUCHCARET_LOG("No canvas frame!");
return false;
}
dom::Element* touchCaretElement = presShell->GetTouchCaretElement();
if (!touchCaretElement) {
TOUCHCARET_LOG("No touch caret frame element!");
return false;
}
// Hide touch caret while caret is not visible.
bool caretVisible = false;
caret->GetCaretVisible(&caretVisible);
if (!caretVisible) {
TOUCHCARET_LOG("Caret is not visible");
SetVisibility(false);
return;
TOUCHCARET_LOG("Caret is not visible!");
return false;
}
// Caret is visible and shown, update touch caret.
nsISelection* caretSelection = caret->GetCaretDOMSelection();
nsRect focusRect;
nsIFrame* focusFrame = caret->GetGeometry(caretSelection, &focusRect);
if (!focusFrame) {
TOUCHCARET_LOG("Focus frame is not valid!");
return false;
}
if (focusRect.IsEmpty()) {
TOUCHCARET_LOG("Focus rect is empty!");
return false;
}
return true;
}
void
TouchCaret::UpdatePosition()
{
MOZ_ASSERT(mVisible);
nsCOMPtr<nsIPresShell> presShell = do_QueryReferent(mPresShell);
if (!presShell) {
return;
}
nsRefPtr<nsCaret> caret = presShell->GetCaret();
nsISelection* caretSelection = caret->GetCaretDOMSelection();
nsRect focusRect;
nsIFrame* focusFrame = caret->GetGeometry(caretSelection, &focusRect);
if (!focusFrame || focusRect.IsEmpty()) {
TOUCHCARET_LOG("Focus frame not valid");
SetVisibility(false);
return;
}
@ -415,6 +477,7 @@ TouchCaret::UpdateTouchCaret(bool aVisible)
while (closestScrollFrame) {
nsIScrollableFrame* sf = do_QueryFrame(closestScrollFrame);
nsRect visualRect = sf->GetScrollPortRect();
// Clamp the touch caret in the scroll port.
nsLayoutUtils::TransformRect(closestScrollFrame, canvasFrame, visualRect);
pos = visualRect.ClampPoint(pos);
@ -426,7 +489,6 @@ TouchCaret::UpdateTouchCaret(bool aVisible)
}
SetTouchFramePos(pos);
SetVisibility(aVisible);
}
/* static */void

View File

@ -45,18 +45,9 @@ public:
*/
nsEventStatus HandleEvent(WidgetEvent* aEvent);
/**
* By calling this function, touch caret recalculate touch frame position and
* update accordingly.
*/
void UpdateTouchCaret(bool aVisible);
void SyncVisibilityWithCaret();
/**
* 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);
void UpdatePositionIfNeeded();
/**
* GetVisibility will get the visibility of the touch caret.
@ -72,6 +63,17 @@ private:
~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);
/**
* Find the nsCanvasFrame which holds the touch caret.
*/

View File

@ -2245,7 +2245,7 @@ NS_IMETHODIMP PresShell::SetCaretEnabled(bool aInEnable)
mCaret->SetCaretVisible(mCaretEnabled);
}
if (mTouchCaret) {
mTouchCaret->UpdateTouchCaret(mCaretEnabled);
mTouchCaret->SyncVisibilityWithCaret();
}
}
@ -3932,6 +3932,9 @@ PresShell::UnsuppressAndInvalidate()
if (mCaretEnabled && mCaret) {
mCaret->CheckCaretDrawingState();
}
if (mTouchCaret) {
mTouchCaret->UpdatePositionIfNeeded();
}
}
// now that painting is unsuppressed, focus may be set on the document
@ -5805,7 +5808,7 @@ PresShell::MarkImagesInSubtreeVisible(nsIFrame* aFrame, const nsRect& aRect)
if (usingDisplayport) {
rect = displayPort;
} else {
rect = rect.Intersect(scrollFrame->GetScrollPortRect());
rect = rect.Intersect(scrollFrame->GetScrollPortRect());
}
rect = scrollFrame->ExpandRectToNearlyVisible(rect);
}
@ -8649,6 +8652,7 @@ PresShell::DidDoReflow(bool aInterruptible, bool aWasInterrupted)
if (sSynthMouseMove) {
SynthesizeMouseMove(false);
}
if (mCaret) {
// Update the caret's position now to account for any changes created by
// the reflow.
@ -8656,6 +8660,10 @@ PresShell::DidDoReflow(bool aInterruptible, bool aWasInterrupted)
mCaret->UpdateCaretPosition();
}
if (mTouchCaret) {
mTouchCaret->UpdatePositionIfNeeded();
}
if (!aWasInterrupted) {
ClearReflowOnZoomPending();
}