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