From f326e14b4bd6a8d2b79bb170527c0a0e0f259fd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Wed, 12 Feb 2025 11:41:01 +0000 Subject: [PATCH] Bug 1947508 - Give some slack to the caret blink timer. r=dholbert Something like this perhaps? Given the usual caret blink rate this should be enough. We can reduce the slack if needed. Differential Revision: https://phabricator.services.mozilla.com/D237768 --- layout/base/nsCaret.cpp | 24 +++++++++++++++++++++--- layout/base/nsCaret.h | 10 ++++++++++ 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/layout/base/nsCaret.cpp b/layout/base/nsCaret.cpp index f76e54f844f3..53180d86ef66 100644 --- a/layout/base/nsCaret.cpp +++ b/layout/base/nsCaret.cpp @@ -601,6 +601,11 @@ nsCaret::NotifySelectionChanged(Document*, Selection* aDomSel, int16_t aReason, } void nsCaret::ResetBlinking() { + // How many milliseconds we allow the timer to get off-sync when resetting + // blinking too often. 50 is not likely to be user observable in practice, + // it's ~4 animation frames at 60fps. + static const auto kBlinkTimerSlack = TimeDuration::FromMilliseconds(50); + mIsBlinkOn = true; if (mReadOnly || !IsVisible()) { @@ -608,17 +613,28 @@ void nsCaret::ResetBlinking() { return; } - const auto blinkTime = LookAndFeel::CaretBlinkTime(); - if (blinkTime <= 0) { + const int32_t oldBlinkTime = mBlinkTime; + mBlinkTime = LookAndFeel::CaretBlinkTime(); + if (mBlinkTime <= 0) { StopBlinking(); return; } mBlinkCount = LookAndFeel::CaretBlinkCount(); + + const auto now = TimeStamp::NowLoRes(); + const bool mustResetTimer = mBlinkTime != oldBlinkTime || + mLastBlinkTimerReset.IsNull() || + (now - mLastBlinkTimerReset) > kBlinkTimerSlack; + if (!mustResetTimer) { + return; + } + if (!mBlinkTimer) { mBlinkTimer = NS_NewTimer(); } - mBlinkTimer->InitWithNamedFuncCallback(CaretBlinkCallback, this, blinkTime, + mLastBlinkTimerReset = now; + mBlinkTimer->InitWithNamedFuncCallback(CaretBlinkCallback, this, mBlinkTime, nsITimer::TYPE_REPEATING_SLACK, "CaretBlinkCallback"); } @@ -626,6 +642,7 @@ void nsCaret::ResetBlinking() { void nsCaret::StopBlinking() { if (mBlinkTimer) { mBlinkTimer->Cancel(); + mLastBlinkTimerReset = TimeStamp(); } } @@ -696,6 +713,7 @@ void nsCaret::CaretBlinkCallback(nsITimer* aTimer, void* aClosure) { if (!theCaret) { return; } + theCaret->mLastBlinkTimerReset = TimeStamp(); theCaret->mIsBlinkOn = !theCaret->mIsBlinkOn; theCaret->SchedulePaint(); diff --git a/layout/base/nsCaret.h b/layout/base/nsCaret.h index e4f7521aa005..686bc9daa0f4 100644 --- a/layout/base/nsCaret.h +++ b/layout/base/nsCaret.h @@ -202,6 +202,11 @@ class nsCaret final : public nsISelectionListener { mozilla::WeakPtr mDomSelectionWeak; nsCOMPtr mBlinkTimer; + // Last time we reset the blink timer. We give it some slack to avoid + // resetting it too often. This gets cleared when CaretBlinkCallback fires, + // because the point of this variable is just to avoid resetting too many + // times in a single blink cycle. + mozilla::TimeStamp mLastBlinkTimerReset; CaretPosition mCaretPosition; @@ -214,6 +219,11 @@ class nsCaret final : public nsISelectionListener { * blinking. */ int32_t mBlinkCount = -1; + /** + * Current blink time (the value that LookAndFeel::CaretBlinkTime() gave us + * when we most recently reset our blinking). + */ + int32_t mBlinkTime = -1; /** * mHideCount is not 0, it means that somebody doesn't want the caret * to be visible. See AddForceHide() and RemoveForceHide().