Bug 555642 part.1 nsCaret should have a way to override the caret visible state for hiding caret temporarily and nsEditor should hide caret if composition string doesn't have caret information r=roc

This commit is contained in:
Masayuki Nakano 2015-08-17 20:58:38 +09:00
Родитель ed11d345e0
Коммит 3645c1dbaf
5 изменённых файлов: 93 добавлений и 9 удалений

Просмотреть файл

@ -223,7 +223,12 @@ IMETextTxn::SetIMESelection(nsEditor& aEditor,
static_cast<uint32_t>(caretOffset) <= maxOffset);
rv = selection->Collapse(aTextNode, caretOffset);
setCaret = setCaret || NS_SUCCEEDED(rv);
NS_ASSERTION(setCaret, "Failed to collapse normal selection");
if (NS_WARN_IF(!setCaret)) {
continue;
}
// If caret range is specified explicitly, we should show the caret if
// it should be so.
aEditor.HideCaret(false);
continue;
}
@ -292,6 +297,8 @@ IMETextTxn::SetIMESelection(nsEditor& aEditor,
rv = selection->Collapse(aTextNode, caretOffset);
NS_ASSERTION(NS_SUCCEEDED(rv),
"Failed to set caret at the end of composition string");
// If caret range isn't specified explicitly, we should hide the caret.
aEditor.HideCaret(true);
}
rv = selection->EndBatchChanges();

Просмотреть файл

@ -147,6 +147,7 @@ nsEditor::nsEditor()
, mDidPostCreate(false)
, mDispatchInputEvent(true)
, mIsInEditAction(false)
, mHidingCaret(false)
{
}
@ -158,6 +159,8 @@ nsEditor::~nsEditor()
mComposition->OnEditorDestroyed();
mComposition = nullptr;
}
// If this editor is still hiding the caret, we need to restore it.
HideCaret(false);
mTxnMgr = nullptr;
delete mPhonetic;
@ -464,6 +467,8 @@ nsEditor::PreDestroy(bool aDestroyingFrames)
// Unregister event listeners
RemoveEventListeners();
// If this editor is still hiding the caret, we need to restore it.
HideCaret(false);
mActionListeners.Clear();
mEditorObservers.Clear();
mDocStateListeners.Clear();
@ -2065,6 +2070,10 @@ nsEditor::EndIMEComposition()
}
}
// Composition string may have hidden the caret. Therefore, we need to
// cancel it here.
HideCaret(false);
/* reset the data we need to construct a transaction */
mIMETextNode = nullptr;
mIMETextOffset = 0;
@ -5258,3 +5267,23 @@ nsEditor::GetIMESelectionStartOffsetIn(nsINode* aTextNode)
}
return minOffset < INT32_MAX ? minOffset : -1;
}
void
nsEditor::HideCaret(bool aHide)
{
if (mHidingCaret == aHide) {
return;
}
nsCOMPtr<nsIPresShell> presShell = GetPresShell();
NS_ENSURE_TRUE_VOID(presShell);
nsRefPtr<nsCaret> caret = presShell->GetCaret();
NS_ENSURE_TRUE_VOID(caret);
mHidingCaret = aHide;
if (aHide) {
caret->AddForceHide();
} else {
caret->RemoveForceHide();
}
}

Просмотреть файл

@ -824,6 +824,13 @@ public:
void FindBetterInsertionPoint(nsCOMPtr<nsINode>& aNode,
int32_t& aOffset);
/**
* HideCaret() hides caret with nsCaret::AddForceHide() or may show carent
* with nsCaret::RemoveForceHide(). This does NOT set visibility of
* nsCaret. Therefore, this is stateless.
*/
void HideCaret(bool aHide);
protected:
enum Tristate {
eTriUnset,
@ -883,6 +890,7 @@ protected:
bool mDidPostCreate; // whether PostCreate has been called
bool mDispatchInputEvent;
bool mIsInEditAction; // true while the instance is handling an edit action
bool mHidingCaret; // whether caret is hidden forcibly.
friend bool NSCanUnload(nsISupports* serviceMgr);
friend class nsAutoTxnsConserveSelection;

Просмотреть файл

@ -127,8 +127,9 @@ IsKeyboardRTL()
nsCaret::nsCaret()
: mOverrideOffset(0)
, mIsBlinkOn(false)
, mBlinkCount(-1)
, mHideCount(0)
, mIsBlinkOn(false)
, mVisible(false)
, mReadOnly(false)
, mShowDuringSelection(false)
@ -266,7 +267,7 @@ void nsCaret::SetVisible(bool inMakeVisible)
bool nsCaret::IsVisible()
{
if (!mVisible) {
if (!mVisible || mHideCount) {
return false;
}
@ -303,6 +304,25 @@ bool nsCaret::IsVisible()
return true;
}
void nsCaret::AddForceHide()
{
MOZ_ASSERT(mHideCount < UINT32_MAX);
if (++mHideCount > 1) {
return;
}
ResetBlinking();
SchedulePaint();
}
void nsCaret::RemoveForceHide()
{
if (!mHideCount || --mHideCount) {
return;
}
ResetBlinking();
SchedulePaint();
}
void nsCaret::SetCaretReadOnly(bool inMakeReadonly)
{
mReadOnly = inMakeReadonly;
@ -622,7 +642,7 @@ void nsCaret::ResetBlinking()
{
mIsBlinkOn = true;
if (mReadOnly || !mVisible) {
if (mReadOnly || !mVisible || mHideCount) {
StopBlinking();
return;
}

Просмотреть файл

@ -78,6 +78,21 @@ class nsCaret final : public nsISelectionListener
* because we're in non-editable/disabled content.
*/
bool IsVisible();
/**
* AddForceHide() increases mHideCount and hide the caret even if
* SetVisible(true) has been or will be called. This is useful when the
* caller wants to hide caret temporarily and it needs to cancel later.
* Especially, in the latter case, it's too difficult to decide if the
* caret should be actually visible or not because caret visible state
* is set from a lot of event handlers. So, it's very stateful.
*/
void AddForceHide();
/**
* RemoveForceHide() decreases mHideCount if it's over 0.
* If the value becomes 0, this may show the caret if SetVisible(true)
* has been called.
*/
void RemoveForceHide();
/** SetCaretReadOnly set the appearance of the caret
* @param inMakeReadonly true to show the caret in a 'read only' state,
* false to show the caret in normal, editing state
@ -201,17 +216,22 @@ protected:
* Ignored if mOverrideContent is null.
*/
int32_t mOverrideOffset;
/**
* mIsBlinkOn is true when we're in a blink cycle where the caret is on.
*/
bool mIsBlinkOn;
/**
* mBlinkCount is used to control the number of times to blink the caret
* before stopping the blink. This is reset each time we reset the
* blinking.
*/
int32_t mBlinkCount;
/**
* mHideCount is not 0, it means that somebody doesn't want the caret
* to be visible. See AddForceHide() and RemoveForceHide().
*/
uint32_t mHideCount;
/**
* mIsBlinkOn is true when we're in a blink cycle where the caret is on.
*/
bool mIsBlinkOn;
/**
* mIsVisible is true when SetVisible was last called with 'true'.
*/