tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

nsCaret.h (8556B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 /* the caret is the text cursor used, e.g., when editing */
      8 
      9 #ifndef nsCaret_h__
     10 #define nsCaret_h__
     11 
     12 #include "mozilla/MemoryReporting.h"
     13 #include "mozilla/SelectionMovementUtils.h"
     14 #include "nsCoord.h"
     15 #include "nsIFrame.h"
     16 #include "nsISelectionListener.h"
     17 #include "nsPoint.h"
     18 #include "nsRect.h"
     19 
     20 class nsFrameSelection;
     21 class nsIContent;
     22 class nsIFrame;
     23 class nsINode;
     24 class nsITimer;
     25 
     26 namespace mozilla {
     27 class PresShell;
     28 enum class CaretAssociationHint;
     29 namespace gfx {
     30 class DrawTarget;
     31 }  // namespace gfx
     32 }  // namespace mozilla
     33 
     34 //-----------------------------------------------------------------------------
     35 class nsCaret final : public nsISelectionListener {
     36  typedef mozilla::gfx::DrawTarget DrawTarget;
     37 
     38 public:
     39  nsCaret();
     40 
     41 protected:
     42  virtual ~nsCaret();
     43 
     44 public:
     45  NS_DECL_ISUPPORTS
     46 
     47  using CaretAssociationHint = mozilla::CaretAssociationHint;
     48 
     49  nsresult Init(mozilla::PresShell*);
     50  void Terminate();
     51 
     52  void SetSelection(mozilla::dom::Selection*);
     53  mozilla::dom::Selection* GetSelection();
     54 
     55  /**
     56   * SetVisible will set the visibility of the caret
     57   *  @param aVisible true to show the caret, false to hide it
     58   */
     59  void SetVisible(bool aVisible);
     60  /**
     61   * IsVisible will get the visibility of the caret.
     62   * It does not take account of blinking or the caret being hidden because
     63   * we're in non-editable/disabled content.
     64   */
     65  bool IsVisible() const;
     66 
     67  /**
     68   * AddForceHide() increases mHideCount and hide the caret even if
     69   * SetVisible(true) has been or will be called.  This is useful when the
     70   * caller wants to hide caret temporarily and it needs to cancel later.
     71   * Especially, in the latter case, it's too difficult to decide if the
     72   * caret should be actually visible or not because caret visible state
     73   * is set from a lot of event handlers.  So, it's very stateful.
     74   */
     75  void AddForceHide();
     76  /**
     77   * RemoveForceHide() decreases mHideCount if it's over 0.
     78   * If the value becomes 0, this may show the caret if SetVisible(true)
     79   * has been called.
     80   */
     81  void RemoveForceHide();
     82  /** SetCaretReadOnly set the appearance of the caret
     83   *  @param inMakeReadonly true to show the caret in a 'read only' state,
     84   *         false to show the caret in normal, editing state
     85   */
     86  void SetCaretReadOnly(bool aReadOnly);
     87  /**
     88   * @param aVisibility true if the caret should be visible even when the
     89   * selection is not collapsed.
     90   */
     91  void SetVisibilityDuringSelection(bool aVisibility);
     92 
     93  /**
     94   * Set the caret's position explicitly to the specified node and offset
     95   * instead of tracking its selection.
     96   * Passing null for aNode would set the caret to track its selection again.
     97   **/
     98  void SetCaretPosition(nsINode* aNode, int32_t aOffset);
     99 
    100  /**
    101   * Schedule a repaint for the frame where the caret would appear.
    102   * Does not check visibility etc.
    103   */
    104  void SchedulePaint();
    105 
    106  nsIFrame* GetLastPaintedFrame() { return mLastPaintedFrame; }
    107  void SetLastPaintedFrame(nsIFrame* aFrame) { mLastPaintedFrame = aFrame; }
    108 
    109  /**
    110   * Returns a frame to paint in, and optionally the bounds of the painted caret
    111   * relative to that frame. The rectangle includes bidi decorations.
    112   * Returns null if the caret should not be drawn (including if it's blinked
    113   * off).
    114   */
    115  nsIFrame* GetPaintGeometry();
    116  nsIFrame* GetPaintGeometry(nsRect* aRect);
    117 
    118  /**
    119   * Same as the overload above, but returns the caret and hook rects
    120   * separately, and also computes the color if requested.
    121   */
    122  nsIFrame* GetPaintGeometry(nsRect* aCaretRect, nsRect* aHookRect,
    123                             nscolor* aCaretColor = nullptr);
    124  /**
    125   * A simple wrapper around GetGeometry. Does not take any caret state into
    126   * account other than the current selection.
    127   */
    128  nsIFrame* GetGeometry(nsRect* aRect) {
    129    return GetGeometry(GetSelection(), aRect);
    130  }
    131 
    132  /** PaintCaret
    133   *  Actually paint the caret onto the given rendering context.
    134   */
    135  void PaintCaret(DrawTarget& aDrawTarget, nsIFrame* aForFrame,
    136                  const nsPoint& aOffset);
    137 
    138  // nsISelectionListener interface
    139  NS_DECL_NSISELECTIONLISTENER
    140 
    141  /** The current caret position. */
    142  struct CaretPosition {
    143    nsCOMPtr<nsINode> mContent;
    144    int32_t mOffset = 0;
    145    CaretAssociationHint mHint{0};
    146    mozilla::intl::BidiEmbeddingLevel mBidiLevel;
    147 
    148    bool operator==(const CaretPosition& aOther) const = default;
    149 
    150    explicit operator bool() const { return !!mContent; }
    151  };
    152 
    153  static CaretPosition CaretPositionFor(const mozilla::dom::Selection*);
    154 
    155  /**
    156   * Gets the position and size of the caret that would be drawn for
    157   * the focus node/offset of aSelection (assuming it would be drawn,
    158   * i.e., disregarding blink status). The geometry is stored in aRect,
    159   * and we return the frame aRect is relative to.
    160   * Only looks at the focus node of aSelection, so you can call it even if
    161   * aSelection is not collapsed.
    162   * This rect does not include any extra decorations for bidi.
    163   * @param aRect must be non-null
    164   */
    165  static nsIFrame* GetGeometry(const mozilla::dom::Selection* aSelection,
    166                               nsRect* aRect);
    167 
    168  static nsRect GetGeometryForFrame(nsIFrame* aFrame, int32_t aFrameOffset,
    169                                    nscoord* aBidiIndicatorSize);
    170 
    171  // Get the frame and frame offset based on aPosition.
    172  static mozilla::CaretFrameData GetFrameAndOffset(
    173      const CaretPosition& aPosition);
    174 
    175  size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
    176 
    177 protected:
    178  static void CaretBlinkCallback(nsITimer* aTimer, void* aClosure);
    179 
    180  void CheckSelectionLanguageChange();
    181  void CaretVisibilityMaybeChanged();
    182 
    183  void ResetBlinking();
    184  void StopBlinking();
    185 
    186  struct Metrics {
    187    nscoord mBidiIndicatorSize;  // width and height of bidi indicator
    188    nscoord mCaretWidth;         // full caret width including bidi indicator
    189  };
    190  static Metrics ComputeMetrics(nsIFrame* aFrame, int32_t aOffset,
    191                                nscoord aCaretHeight);
    192  void ComputeCaretRects(nsIFrame* aFrame, int32_t aFrameOffset,
    193                         nsRect* aCaretRect, nsRect* aHookRect);
    194 
    195  // If we're tracking the selection, this updates the caret position and
    196  // invalidates paint as needed.
    197  void UpdateCaretPositionFromSelectionIfNeeded();
    198 
    199  mozilla::WeakPtr<mozilla::dom::Selection> mDomSelectionWeak;
    200 
    201  nsCOMPtr<nsITimer> mBlinkTimer;
    202  // Last time we reset the blink timer. We give it some slack to avoid
    203  // resetting it too often. This gets cleared when CaretBlinkCallback fires,
    204  // because the point of this variable is just to avoid resetting too many
    205  // times in a single blink cycle.
    206  mozilla::TimeStamp mLastBlinkTimerReset;
    207 
    208  CaretPosition mCaretPosition;
    209 
    210  // The last frame we painted the caret in.
    211  WeakFrame mLastPaintedFrame;
    212 
    213  /**
    214   * mBlinkCount is used to control the number of times to blink the caret
    215   * before stopping the blink. This is reset each time we reset the
    216   * blinking.
    217   */
    218  int32_t mBlinkCount = -1;
    219  /**
    220   * Current blink time (the value that LookAndFeel::CaretBlinkTime() gave us
    221   * when we most recently reset our blinking).
    222   */
    223  int32_t mBlinkTime = -1;
    224  /**
    225   * mHideCount is not 0, it means that somebody doesn't want the caret
    226   * to be visible.  See AddForceHide() and RemoveForceHide().
    227   */
    228  uint32_t mHideCount = 0;
    229 
    230  /**
    231   * mIsBlinkOn is true when we're in a blink cycle where the caret is on.
    232   */
    233  bool mIsBlinkOn = false;
    234  /**
    235   * mIsVisible is true when SetVisible was last called with 'true'.
    236   */
    237  bool mVisible = false;
    238  /**
    239   * mReadOnly is true when the caret is set to "read only" mode (i.e.,
    240   * it doesn't blink).
    241   */
    242  bool mReadOnly = false;
    243  /**
    244   * mShowDuringSelection is true when the caret should be shown even when
    245   * the selection is not collapsed.
    246   */
    247  bool mShowDuringSelection = false;
    248 
    249  /**
    250   * If the caret position is fixed, it's been overridden externally and it
    251   * will not track the selection.
    252   */
    253  bool mFixedCaretPosition = false;
    254 
    255  /**
    256   * If we're currently hiding the caret due to the selection not being
    257   * collapsed. Can only be true if mShowDuringSelection is false.
    258   */
    259  bool mHiddenDuringSelection = false;
    260 };
    261 
    262 #endif  // nsCaret_h__