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