summaryrefslogtreecommitdiffstats
path: root/layout/base/nsCaret.h
diff options
context:
space:
mode:
Diffstat (limited to 'layout/base/nsCaret.h')
-rw-r--r--layout/base/nsCaret.h143
1 files changed, 67 insertions, 76 deletions
diff --git a/layout/base/nsCaret.h b/layout/base/nsCaret.h
index 43329c827f..cba719962c 100644
--- a/layout/base/nsCaret.h
+++ b/layout/base/nsCaret.h
@@ -10,10 +10,10 @@
#define nsCaret_h__
#include "mozilla/MemoryReporting.h"
-#include "mozilla/dom/Selection.h"
+#include "mozilla/SelectionMovementUtils.h"
#include "nsCoord.h"
+#include "nsIFrame.h"
#include "nsISelectionListener.h"
-#include "nsIWeakReferenceUtils.h"
#include "nsPoint.h"
#include "nsRect.h"
@@ -46,10 +46,10 @@ class nsCaret final : public nsISelectionListener {
using CaretAssociationHint = mozilla::CaretAssociationHint;
- nsresult Init(mozilla::PresShell* aPresShell);
+ nsresult Init(mozilla::PresShell*);
void Terminate();
- void SetSelection(mozilla::dom::Selection* aDOMSel);
+ void SetSelection(mozilla::dom::Selection*);
mozilla::dom::Selection* GetSelection();
/**
@@ -61,40 +61,18 @@ class nsCaret final : public nsISelectionListener {
* those with user-modify: read-only
*/
void SetIgnoreUserModify(bool aIgnoreUserModify);
- /** SetVisible will set the visibility of the caret
- * @param inMakeVisible true to show the caret, false to hide it
+ /**
+ * SetVisible will set the visibility of the caret
+ * @param aVisible true to show the caret, false to hide it
*/
- void SetVisible(bool intMakeVisible);
- /** IsVisible will get the visibility of the caret.
- * This returns false if the caret is hidden because it was set
- * to not be visible, or because the selection is not collapsed, or
- * because an open popup is hiding the caret.
- * It does not take account of blinking or the caret being hidden
- * because we're in non-editable/disabled content.
+ void SetVisible(bool aVisible);
+ /**
+ * IsVisible will get the visibility of the caret.
+ * It does not take account of blinking or the caret being hidden because
+ * we're in non-editable/disabled content.
*/
- bool IsVisible(mozilla::dom::Selection* aSelection = nullptr) {
- if (!mVisible || mHideCount) {
- return false;
- }
-
- if (!mShowDuringSelection) {
- mozilla::dom::Selection* selection;
- if (aSelection) {
- selection = aSelection;
- } else {
- selection = GetSelection();
- }
- if (!selection || !selection->IsCollapsed()) {
- return false;
- }
- }
-
- if (IsMenuPopupHidingCaret()) {
- return false;
- }
+ bool IsVisible() const;
- return true;
- }
/**
* AddForceHide() increases mHideCount and hide the caret even if
* SetVisible(true) has been or will be called. This is useful when the
@@ -114,7 +92,7 @@ class nsCaret final : public nsISelectionListener {
* @param inMakeReadonly true to show the caret in a 'read only' state,
* false to show the caret in normal, editing state
*/
- void SetCaretReadOnly(bool inMakeReadonly);
+ void SetCaretReadOnly(bool aReadOnly);
/**
* @param aVisibility true if the caret should be visible even when the
* selection is not collapsed.
@@ -132,7 +110,10 @@ class nsCaret final : public nsISelectionListener {
* Schedule a repaint for the frame where the caret would appear.
* Does not check visibility etc.
*/
- void SchedulePaint(mozilla::dom::Selection* aSelection = nullptr);
+ void SchedulePaint();
+
+ nsIFrame* GetLastPaintedFrame() { return mLastPaintedFrame; }
+ void SetLastPaintedFrame(nsIFrame* aFrame) { mLastPaintedFrame = aFrame; }
/**
* Returns a frame to paint in, and the bounds of the painted caret
@@ -142,6 +123,7 @@ class nsCaret final : public nsISelectionListener {
* off).
*/
nsIFrame* GetPaintGeometry(nsRect* aRect);
+
/**
* Same as the overload above, but returns the caret and hook rects
* separately, and also computes the color if requested.
@@ -165,6 +147,22 @@ class nsCaret final : public nsISelectionListener {
// nsISelectionListener interface
NS_DECL_NSISELECTIONLISTENER
+ /** The current caret position. */
+ struct CaretPosition {
+ nsCOMPtr<nsINode> mContent;
+ int32_t mOffset = 0;
+ CaretAssociationHint mHint{0};
+ mozilla::intl::BidiEmbeddingLevel mBidiLevel;
+
+ bool operator==(const CaretPosition& aOther) const {
+ return mContent == aOther.mContent && mOffset == aOther.mOffset &&
+ mHint == aOther.mHint && mBidiLevel == aOther.mBidiLevel;
+ }
+ explicit operator bool() const { return !!mContent; }
+ };
+
+ static CaretPosition CaretPositionFor(const mozilla::dom::Selection*);
+
/**
* Gets the position and size of the caret that would be drawn for
* the focus node/offset of aSelection (assuming it would be drawn,
@@ -181,18 +179,9 @@ class nsCaret final : public nsISelectionListener {
static nsRect GetGeometryForFrame(nsIFrame* aFrame, int32_t aFrameOffset,
nscoord* aBidiIndicatorSize);
- // Get the frame and frame offset based on the focus node and focus offset
- // of aSelection. If aOverrideNode and aOverride are provided, use them
- // instead.
- // @param aFrameOffset return the frame offset if non-null.
- // @param aUnadjustedFrame return the original frame that the selection is
- // targeting, without any adjustment for painting.
- // @return the frame of the focus node.
- static nsIFrame* GetFrameAndOffset(const mozilla::dom::Selection* aSelection,
- nsINode* aOverrideNode,
- int32_t aOverrideOffset,
- int32_t* aFrameOffset,
- nsIFrame** aUnadjustedFrame = nullptr);
+ // Get the frame and frame offset based on aPosition.
+ static mozilla::CaretFrameData GetFrameAndOffset(
+ const CaretPosition& aPosition);
size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
@@ -200,6 +189,7 @@ class nsCaret final : public nsISelectionListener {
static void CaretBlinkCallback(nsITimer* aTimer, void* aClosure);
void CheckSelectionLanguageChange();
+ void CaretVisibilityMaybeChanged();
void ResetBlinking();
void StopBlinking();
@@ -213,72 +203,73 @@ class nsCaret final : public nsISelectionListener {
void ComputeCaretRects(nsIFrame* aFrame, int32_t aFrameOffset,
nsRect* aCaretRect, nsRect* aHookRect);
- // Returns true if we should not draw the caret because of XUL menu popups.
- // The caret should be hidden if:
- // 1. An open popup contains the caret, but a menu popup exists before the
- // caret-owning popup in the popup list (i.e. a menu is in front of the
- // popup with the caret). If the menu itself contains the caret we don't
- // hide it.
- // 2. A menu popup is open, but there is no caret present in any popup.
- // 3. The caret selection is empty.
- bool IsMenuPopupHidingCaret();
+ // If we're tracking the selection, this updates the caret position and
+ // invalidates paint as needed.
+ void UpdateCaretPositionFromSelectionIfNeeded();
nsWeakPtr mPresShell;
mozilla::WeakPtr<mozilla::dom::Selection> mDomSelectionWeak;
nsCOMPtr<nsITimer> mBlinkTimer;
- /**
- * The content to draw the caret at. If null, we use mDomSelectionWeak's
- * focus node instead.
- */
- nsCOMPtr<nsINode> mOverrideContent;
- /**
- * The character offset to draw the caret at.
- * Ignored if mOverrideContent is null.
- */
- int32_t mOverrideOffset;
+ CaretPosition mCaretPosition;
+
+ // The last frame we painted the caret in.
+ WeakFrame mLastPaintedFrame;
+
/**
* 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;
+ int32_t mBlinkCount = -1;
/**
* mBlinkRate is the rate of the caret blinking the last time we read it.
* It is used as a way to optimize whether we need to reset the blinking
* timer. 0 or a negative value means no blinking.
*/
- int32_t mBlinkRate;
+ int32_t mBlinkRate = 0;
/**
* mHideCount is not 0, it means that somebody doesn't want the caret
* to be visible. See AddForceHide() and RemoveForceHide().
*/
- uint32_t mHideCount;
+ uint32_t mHideCount = 0;
/**
* mIsBlinkOn is true when we're in a blink cycle where the caret is on.
*/
- bool mIsBlinkOn;
+ bool mIsBlinkOn = false;
/**
* mIsVisible is true when SetVisible was last called with 'true'.
*/
- bool mVisible;
+ bool mVisible = false;
/**
* mReadOnly is true when the caret is set to "read only" mode (i.e.,
* it doesn't blink).
*/
- bool mReadOnly;
+ bool mReadOnly = false;
/**
* mShowDuringSelection is true when the caret should be shown even when
* the selection is not collapsed.
*/
- bool mShowDuringSelection;
+ bool mShowDuringSelection = false;
/**
* mIgnoreUserModify is true when the caret should be shown even when
* it's in non-user-modifiable content.
*/
- bool mIgnoreUserModify;
+ bool mIgnoreUserModify = true;
+
+ /**
+ * If the caret position is fixed, it's been overridden externally and it
+ * will not track the selection.
+ */
+ bool mFixedCaretPosition = false;
+
+ /**
+ * If we're currently hiding the caret due to the selection not being
+ * collapsed. Can only be true if mShowDuringSelection is false.
+ */
+ bool mHiddenDuringSelection = false;
};
#endif // nsCaret_h__