Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/layout/base/nsCaret.h
Line
Count
Source (jump to first uncovered line)
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/dom/Selection.h"
14
#include "nsCoord.h"
15
#include "nsISelectionListener.h"
16
#include "nsIWeakReferenceUtils.h"
17
#include "CaretAssociationHint.h"
18
#include "nsPoint.h"
19
#include "nsRect.h"
20
21
class nsDisplayListBuilder;
22
class nsFrameSelection;
23
class nsIContent;
24
class nsIFrame;
25
class nsINode;
26
class nsIPresShell;
27
class nsITimer;
28
29
namespace mozilla {
30
namespace gfx {
31
class DrawTarget;
32
} // namespace gfx
33
} // namespace mozilla
34
35
//-----------------------------------------------------------------------------
36
class nsCaret final : public nsISelectionListener
37
{
38
    typedef mozilla::gfx::DrawTarget DrawTarget;
39
40
  public:
41
    nsCaret();
42
43
  protected:
44
    virtual ~nsCaret();
45
46
  public:
47
    NS_DECL_ISUPPORTS
48
49
    typedef mozilla::CaretAssociationHint CaretAssociationHint;
50
51
    nsresult Init(nsIPresShell *inPresShell);
52
    void Terminate();
53
54
    void SetSelection(mozilla::dom::Selection *aDOMSel);
55
    mozilla::dom::Selection* GetSelection();
56
57
    /**
58
     * Sets whether the caret should only be visible in nodes that are not
59
     * user-modify: read-only, or whether it should be visible in all nodes.
60
     *
61
     * @param aIgnoreUserModify true to have the cursor visible in all nodes,
62
     *                          false to have it visible in all nodes except
63
     *                          those with user-modify: read-only
64
     */
65
    void SetIgnoreUserModify(bool aIgnoreUserModify);
66
    /** SetVisible will set the visibility of the caret
67
     *  @param inMakeVisible true to show the caret, false to hide it
68
     */
69
    void SetVisible(bool intMakeVisible);
70
    /** IsVisible will get the visibility of the caret.
71
     *  This returns false if the caret is hidden because it was set
72
     *  to not be visible, or because the selection is not collapsed, or
73
     *  because an open popup is hiding the caret.
74
     *  It does not take account of blinking or the caret being hidden
75
     *  because we're in non-editable/disabled content.
76
     */
77
    bool IsVisible(mozilla::dom::Selection* aSelection = nullptr)
78
0
    {
79
0
      if (!mVisible || mHideCount) {
80
0
        return false;
81
0
      }
82
0
83
0
      if (!mShowDuringSelection) {
84
0
        mozilla::dom::Selection* selection;
85
0
        if (aSelection) {
86
0
          selection = aSelection;
87
0
        } else {
88
0
          selection = GetSelection();
89
0
        }
90
0
        if (!selection || !selection->IsCollapsed()) {
91
0
          return false;
92
0
        }
93
0
      }
94
0
95
0
      if (IsMenuPopupHidingCaret()) {
96
0
        return false;
97
0
      }
98
0
99
0
      return true;
100
0
    }
101
    /**
102
     * AddForceHide() increases mHideCount and hide the caret even if
103
     * SetVisible(true) has been or will be called.  This is useful when the
104
     * caller wants to hide caret temporarily and it needs to cancel later.
105
     * Especially, in the latter case, it's too difficult to decide if the
106
     * caret should be actually visible or not because caret visible state
107
     * is set from a lot of event handlers.  So, it's very stateful.
108
     */
109
    void AddForceHide();
110
    /**
111
     * RemoveForceHide() decreases mHideCount if it's over 0.
112
     * If the value becomes 0, this may show the caret if SetVisible(true)
113
     * has been called.
114
     */
115
    void RemoveForceHide();
116
    /** SetCaretReadOnly set the appearance of the caret
117
     *  @param inMakeReadonly true to show the caret in a 'read only' state,
118
     *         false to show the caret in normal, editing state
119
     */
120
    void SetCaretReadOnly(bool inMakeReadonly);
121
    /**
122
     * @param aVisibility true if the caret should be visible even when the
123
     * selection is not collapsed.
124
     */
125
    void SetVisibilityDuringSelection(bool aVisibility);
126
127
    /**
128
     * Set the caret's position explicitly to the specified node and offset
129
     * instead of tracking its selection.
130
     * Passing null for aNode would set the caret to track its selection again.
131
     **/
132
    void SetCaretPosition(nsINode* aNode, int32_t aOffset);
133
134
    /**
135
     * Schedule a repaint for the frame where the caret would appear.
136
     * Does not check visibility etc.
137
     */
138
    void SchedulePaint(mozilla::dom::Selection* aSelection = nullptr);
139
140
    /**
141
     * Returns a frame to paint in, and the bounds of the painted caret
142
     * relative to that frame.
143
     * The rectangle includes bidi decorations.
144
     * Returns null if the caret should not be drawn (including if it's blinked
145
     * off).
146
     */
147
    nsIFrame* GetPaintGeometry(nsRect* aRect);
148
    /**
149
     * A simple wrapper around GetGeometry. Does not take any caret state into
150
     * account other than the current selection.
151
     */
152
    nsIFrame* GetGeometry(nsRect* aRect)
153
0
    {
154
0
      return GetGeometry(GetSelection(), aRect);
155
0
    }
156
157
    /** PaintCaret
158
     *  Actually paint the caret onto the given rendering context.
159
     */
160
    void PaintCaret(DrawTarget& aDrawTarget,
161
                    nsIFrame *aForFrame,
162
                    const nsPoint &aOffset);
163
164
    //nsISelectionListener interface
165
    NS_DECL_NSISELECTIONLISTENER
166
167
    /**
168
     * Gets the position and size of the caret that would be drawn for
169
     * the focus node/offset of aSelection (assuming it would be drawn,
170
     * i.e., disregarding blink status). The geometry is stored in aRect,
171
     * and we return the frame aRect is relative to.
172
     * Only looks at the focus node of aSelection, so you can call it even if
173
     * aSelection is not collapsed.
174
     * This rect does not include any extra decorations for bidi.
175
     * @param aRect must be non-null
176
     */
177
    static nsIFrame* GetGeometry(mozilla::dom::Selection* aSelection,
178
                                 nsRect* aRect);
179
    static nsresult GetCaretFrameForNodeOffset(nsFrameSelection* aFrameSelection,
180
                                               nsIContent* aContentNode,
181
                                               int32_t aOffset,
182
                                               CaretAssociationHint aFrameHint,
183
                                               uint8_t aBidiLevel,
184
                                               nsIFrame** aReturnFrame,
185
                                               int32_t* aReturnOffset);
186
    static nsRect GetGeometryForFrame(nsIFrame* aFrame,
187
                                      int32_t   aFrameOffset,
188
                                      nscoord*  aBidiIndicatorSize);
189
190
    // Get the frame and frame offset based on the focus node and focus offset
191
    // of aSelection. If aOverrideNode and aOverride are provided, use them
192
    // instead.
193
    // @param aFrameOffset return the frame offset if non-null.
194
    // @return the frame of the focus node.
195
    static nsIFrame* GetFrameAndOffset(mozilla::dom::Selection* aSelection,
196
                                       nsINode* aOverrideNode,
197
                                       int32_t aOverrideOffset,
198
                                       int32_t* aFrameOffset);
199
200
    size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
201
202
    nsIFrame*     GetFrame(int32_t* aContentOffset);
203
    void          ComputeCaretRects(nsIFrame* aFrame, int32_t aFrameOffset,
204
                                    nsRect* aCaretRect, nsRect* aHookRect);
205
206
protected:
207
    static void   CaretBlinkCallback(nsITimer *aTimer, void *aClosure);
208
209
    void          CheckSelectionLanguageChange();
210
211
    void          ResetBlinking();
212
    void          StopBlinking();
213
214
    struct Metrics {
215
      nscoord mBidiIndicatorSize; // width and height of bidi indicator
216
      nscoord mCaretWidth;        // full caret width including bidi indicator
217
    };
218
    static Metrics ComputeMetrics(nsIFrame* aFrame, int32_t aOffset,
219
                                  nscoord aCaretHeight);
220
221
    // Returns true if we should not draw the caret because of XUL menu popups.
222
    // The caret should be hidden if:
223
    // 1. An open popup contains the caret, but a menu popup exists before the
224
    //    caret-owning popup in the popup list (i.e. a menu is in front of the
225
    //    popup with the caret). If the menu itself contains the caret we don't
226
    //    hide it.
227
    // 2. A menu popup is open, but there is no caret present in any popup.
228
    // 3. The caret selection is empty.
229
    bool IsMenuPopupHidingCaret();
230
231
    nsWeakPtr             mPresShell;
232
    mozilla::WeakPtr<mozilla::dom::Selection> mDomSelectionWeak;
233
234
    nsCOMPtr<nsITimer>    mBlinkTimer;
235
236
    /**
237
     * The content to draw the caret at. If null, we use mDomSelectionWeak's
238
     * focus node instead.
239
     */
240
    nsCOMPtr<nsINode>     mOverrideContent;
241
    /**
242
     * The character offset to draw the caret at.
243
     * Ignored if mOverrideContent is null.
244
     */
245
    int32_t               mOverrideOffset;
246
    /**
247
     * mBlinkCount is used to control the number of times to blink the caret
248
     * before stopping the blink. This is reset each time we reset the
249
     * blinking.
250
     */
251
    int32_t               mBlinkCount;
252
    /**
253
     * mBlinkRate is the rate of the caret blinking the last time we read it.
254
     * It is used as a way to optimize whether we need to reset the blinking
255
     * timer.
256
     */
257
    uint32_t              mBlinkRate;
258
    /**
259
     * mHideCount is not 0, it means that somebody doesn't want the caret
260
     * to be visible.  See AddForceHide() and RemoveForceHide().
261
     */
262
    uint32_t              mHideCount;
263
264
    /**
265
     * mIsBlinkOn is true when we're in a blink cycle where the caret is on.
266
     */
267
    bool                  mIsBlinkOn;
268
    /**
269
     * mIsVisible is true when SetVisible was last called with 'true'.
270
     */
271
    bool                  mVisible;
272
    /**
273
     * mReadOnly is true when the caret is set to "read only" mode (i.e.,
274
     * it doesn't blink).
275
     */
276
    bool                  mReadOnly;
277
    /**
278
     * mShowDuringSelection is true when the caret should be shown even when
279
     * the selection is not collapsed.
280
     */
281
    bool                  mShowDuringSelection;
282
    /**
283
     * mIgnoreUserModify is true when the caret should be shown even when
284
     * it's in non-user-modifiable content.
285
     */
286
    bool                  mIgnoreUserModify;
287
};
288
289
#endif //nsCaret_h__