|
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 "nsCoord.h" |
|
13 #include "nsISelectionListener.h" |
|
14 #include "nsIWeakReferenceUtils.h" |
|
15 #include "nsFrameSelection.h" |
|
16 |
|
17 class nsRenderingContext; |
|
18 class nsDisplayListBuilder; |
|
19 class nsITimer; |
|
20 |
|
21 //----------------------------------------------------------------------------- |
|
22 class nsCaret : public nsISelectionListener |
|
23 { |
|
24 public: |
|
25 |
|
26 nsCaret(); |
|
27 virtual ~nsCaret(); |
|
28 |
|
29 enum EViewCoordinates { |
|
30 eTopLevelWindowCoordinates, |
|
31 eRenderingViewCoordinates, |
|
32 eClosestViewCoordinates |
|
33 }; |
|
34 |
|
35 public: |
|
36 |
|
37 NS_DECL_ISUPPORTS |
|
38 |
|
39 nsresult Init(nsIPresShell *inPresShell); |
|
40 void Terminate(); |
|
41 |
|
42 nsISelection* GetCaretDOMSelection(); |
|
43 nsresult SetCaretDOMSelection(nsISelection *inDOMSel); |
|
44 |
|
45 /** GetCaretVisible will get the visibility of the caret |
|
46 * This function is virtual so that it can be used by nsCaretAccessible |
|
47 * without linking |
|
48 * @param inMakeVisible true it is shown, false it is hidden |
|
49 * @return false if and only if inMakeVisible is null, otherwise true |
|
50 */ |
|
51 virtual nsresult GetCaretVisible(bool *outMakeVisible); |
|
52 |
|
53 /** SetCaretVisible will set the visibility of the caret |
|
54 * @param inMakeVisible true to show the caret, false to hide it |
|
55 */ |
|
56 void SetCaretVisible(bool intMakeVisible); |
|
57 |
|
58 /** SetCaretReadOnly set the appearance of the caret |
|
59 * @param inMakeReadonly true to show the caret in a 'read only' state, |
|
60 * false to show the caret in normal, editing state |
|
61 */ |
|
62 void SetCaretReadOnly(bool inMakeReadonly); |
|
63 |
|
64 /** GetCaretReadOnly get the appearance of the caret |
|
65 * @return true if the caret is in 'read only' state, otherwise, |
|
66 * returns false |
|
67 */ |
|
68 bool GetCaretReadOnly() |
|
69 { |
|
70 return mReadOnly; |
|
71 } |
|
72 |
|
73 /** |
|
74 * Gets the position and size of the caret that would be drawn for |
|
75 * the focus node/offset of aSelection (assuming it would be drawn, |
|
76 * i.e., disregarding blink status). The geometry is stored in aRect, |
|
77 * and we return the frame aRect is relative to. |
|
78 * @param aRect must be non-null |
|
79 * @param aBidiIndicatorSize if non-null, set to the bidi indicator size. |
|
80 */ |
|
81 virtual nsIFrame* GetGeometry(nsISelection* aSelection, |
|
82 nsRect* aRect, |
|
83 nscoord* aBidiIndicatorSize = nullptr); |
|
84 |
|
85 /** EraseCaret |
|
86 * this will erase the caret if its drawn and reset drawn status |
|
87 */ |
|
88 void EraseCaret(); |
|
89 |
|
90 void SetVisibilityDuringSelection(bool aVisibility); |
|
91 |
|
92 /** DrawAtPosition |
|
93 * |
|
94 * Draw the caret explicitly, at the specified node and offset. |
|
95 * To avoid drawing glitches, you should call EraseCaret() |
|
96 * after each call to DrawAtPosition(). |
|
97 * |
|
98 * Note: This call breaks the caret's ability to blink at all. |
|
99 **/ |
|
100 nsresult DrawAtPosition(nsIDOMNode* aNode, int32_t aOffset); |
|
101 |
|
102 /** GetCaretFrame |
|
103 * Get the current frame that the caret should be drawn in. If the caret is |
|
104 * not currently visible (i.e., it is between blinks), then this will |
|
105 * return null. |
|
106 * |
|
107 * @param aOffset is result of the caret offset in the content. |
|
108 */ |
|
109 nsIFrame* GetCaretFrame(int32_t *aOffset = nullptr); |
|
110 |
|
111 /** GetCaretRect |
|
112 * Get the current caret rect. Only call this when GetCaretFrame returns |
|
113 * non-null. |
|
114 */ |
|
115 nsRect GetCaretRect() |
|
116 { |
|
117 nsRect r; |
|
118 r.UnionRect(mCaretRect, GetHookRect()); |
|
119 return r; |
|
120 } |
|
121 |
|
122 /** InvalidateOutsideCaret |
|
123 * Invalidate the area that the caret currently occupies if the caret is |
|
124 * outside of its frame's overflow area. This is used when the content that |
|
125 * the caret is currently drawn is is being deleted or reflowed. |
|
126 */ |
|
127 void InvalidateOutsideCaret(); |
|
128 |
|
129 /** UpdateCaretPosition |
|
130 * Update the caret's current frame and rect, but don't draw yet. This is |
|
131 * useful for flickerless moving of the caret (e.g., when the frame the |
|
132 * caret is in reflows and is moved). |
|
133 */ |
|
134 void UpdateCaretPosition(); |
|
135 |
|
136 /** PaintCaret |
|
137 * Actually paint the caret onto the given rendering context. |
|
138 */ |
|
139 void PaintCaret(nsDisplayListBuilder *aBuilder, |
|
140 nsRenderingContext *aCtx, |
|
141 nsIFrame *aForFrame, |
|
142 const nsPoint &aOffset); |
|
143 /** |
|
144 * Sets whether the caret should only be visible in nodes that are not |
|
145 * user-modify: read-only, or whether it should be visible in all nodes. |
|
146 * |
|
147 * @param aIgnoreUserModify true to have the cursor visible in all nodes, |
|
148 * false to have it visible in all nodes except |
|
149 * those with user-modify: read-only |
|
150 */ |
|
151 |
|
152 void SetIgnoreUserModify(bool aIgnoreUserModify); |
|
153 |
|
154 //nsISelectionListener interface |
|
155 NS_DECL_NSISELECTIONLISTENER |
|
156 |
|
157 static void CaretBlinkCallback(nsITimer *aTimer, void *aClosure); |
|
158 |
|
159 nsresult GetCaretFrameForNodeOffset(nsIContent* aContentNode, |
|
160 int32_t aOffset, |
|
161 nsFrameSelection::HINT aFrameHint, |
|
162 uint8_t aBidiLevel, |
|
163 nsIFrame** aReturnFrame, |
|
164 int32_t* aReturnOffset); |
|
165 |
|
166 void CheckCaretDrawingState(); |
|
167 |
|
168 protected: |
|
169 |
|
170 void KillTimer(); |
|
171 nsresult PrimeTimer(); |
|
172 |
|
173 void StartBlinking(); |
|
174 void StopBlinking(); |
|
175 |
|
176 bool DrawAtPositionWithHint(nsIDOMNode* aNode, |
|
177 int32_t aOffset, |
|
178 nsFrameSelection::HINT aFrameHint, |
|
179 uint8_t aBidiLevel, |
|
180 bool aInvalidate); |
|
181 |
|
182 struct Metrics { |
|
183 nscoord mBidiIndicatorSize; // width and height of bidi indicator |
|
184 nscoord mCaretWidth; // full caret width including bidi indicator |
|
185 }; |
|
186 Metrics ComputeMetrics(nsIFrame* aFrame, int32_t aOffset, nscoord aCaretHeight); |
|
187 nsresult GetGeometryForFrame(nsIFrame* aFrame, |
|
188 int32_t aFrameOffset, |
|
189 nsRect* aRect, |
|
190 nscoord* aBidiIndicatorSize); |
|
191 |
|
192 // Returns true if the caret should be drawn. When |mDrawn| is true, |
|
193 // this returns true, so that we erase the drawn caret. If |aIgnoreDrawnState| |
|
194 // is true, we don't take into account whether the caret is currently |
|
195 // drawn or not. This can be used to determine if the caret is drawn when |
|
196 // it shouldn't be. |
|
197 bool MustDrawCaret(bool aIgnoreDrawnState); |
|
198 |
|
199 void DrawCaret(bool aInvalidate); |
|
200 void DrawCaretAfterBriefDelay(); |
|
201 bool UpdateCaretRects(nsIFrame* aFrame, int32_t aFrameOffset); |
|
202 nsRect GetHookRect() |
|
203 { |
|
204 return mHookRect; |
|
205 } |
|
206 void ToggleDrawnStatus() { mDrawn = !mDrawn; } |
|
207 |
|
208 nsFrameSelection* GetFrameSelection(); |
|
209 |
|
210 // Returns true if we should not draw the caret because of XUL menu popups. |
|
211 // The caret should be hidden if: |
|
212 // 1. An open popup contains the caret, but a menu popup exists before the |
|
213 // caret-owning popup in the popup list (i.e. a menu is in front of the |
|
214 // popup with the caret). If the menu itself contains the caret we don't |
|
215 // hide it. |
|
216 // 2. A menu popup is open, but there is no caret present in any popup. |
|
217 // 3. The caret selection is empty. |
|
218 bool IsMenuPopupHidingCaret(); |
|
219 |
|
220 protected: |
|
221 |
|
222 nsWeakPtr mPresShell; |
|
223 nsWeakPtr mDomSelectionWeak; |
|
224 |
|
225 nsCOMPtr<nsITimer> mBlinkTimer; |
|
226 |
|
227 // XXX these fields should go away and the values be acquired as needed, |
|
228 // probably by ComputeMetrics. |
|
229 uint32_t mBlinkRate; // time for one cyle (on then off), in milliseconds |
|
230 nscoord mCaretWidthCSSPx; // caret width in CSS pixels |
|
231 float mCaretAspectRatio; // caret width/height aspect ratio |
|
232 |
|
233 bool mVisible; // is the caret blinking |
|
234 |
|
235 bool mDrawn; // Denotes when the caret is physically drawn on the screen. |
|
236 bool mPendingDraw; // True when the last on-state draw was suppressed. |
|
237 |
|
238 bool mReadOnly; // it the caret in readonly state (draws differently) |
|
239 bool mShowDuringSelection; // show when text is selected |
|
240 |
|
241 bool mIgnoreUserModify; |
|
242 |
|
243 bool mKeyboardRTL; // is the keyboard language right-to-left |
|
244 bool mBidiUI; // is bidi UI turned on |
|
245 nsRect mHookRect; // directional hook on the caret |
|
246 uint8_t mLastBidiLevel; // saved bidi level of the last draw request, to use when we erase |
|
247 nsRect mCaretRect; // the last caret rect, in the coodinates of the last frame. |
|
248 |
|
249 nsCOMPtr<nsIContent> mLastContent; // store the content the caret was last requested to be drawn |
|
250 // in (by DrawAtPosition()/DrawCaret()), |
|
251 // note that this can be different than where it was |
|
252 // actually drawn (anon <BR> in text control) |
|
253 int32_t mLastContentOffset; // the offset for the last request |
|
254 |
|
255 nsFrameSelection::HINT mLastHint; // the hint associated with the last request, see also |
|
256 // mLastBidiLevel below |
|
257 |
|
258 }; |
|
259 |
|
260 #endif //nsCaret_h__ |