michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* vim: set ts=2 sw=2 et tw=78: */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: /* the caret is the text cursor used, e.g., when editing */ michael@0: michael@0: #ifndef nsCaret_h__ michael@0: #define nsCaret_h__ michael@0: michael@0: #include "nsCoord.h" michael@0: #include "nsISelectionListener.h" michael@0: #include "nsIWeakReferenceUtils.h" michael@0: #include "nsFrameSelection.h" michael@0: michael@0: class nsRenderingContext; michael@0: class nsDisplayListBuilder; michael@0: class nsITimer; michael@0: michael@0: //----------------------------------------------------------------------------- michael@0: class nsCaret : public nsISelectionListener michael@0: { michael@0: public: michael@0: michael@0: nsCaret(); michael@0: virtual ~nsCaret(); michael@0: michael@0: enum EViewCoordinates { michael@0: eTopLevelWindowCoordinates, michael@0: eRenderingViewCoordinates, michael@0: eClosestViewCoordinates michael@0: }; michael@0: michael@0: public: michael@0: michael@0: NS_DECL_ISUPPORTS michael@0: michael@0: nsresult Init(nsIPresShell *inPresShell); michael@0: void Terminate(); michael@0: michael@0: nsISelection* GetCaretDOMSelection(); michael@0: nsresult SetCaretDOMSelection(nsISelection *inDOMSel); michael@0: michael@0: /** GetCaretVisible will get the visibility of the caret michael@0: * This function is virtual so that it can be used by nsCaretAccessible michael@0: * without linking michael@0: * @param inMakeVisible true it is shown, false it is hidden michael@0: * @return false if and only if inMakeVisible is null, otherwise true michael@0: */ michael@0: virtual nsresult GetCaretVisible(bool *outMakeVisible); michael@0: michael@0: /** SetCaretVisible will set the visibility of the caret michael@0: * @param inMakeVisible true to show the caret, false to hide it michael@0: */ michael@0: void SetCaretVisible(bool intMakeVisible); michael@0: michael@0: /** SetCaretReadOnly set the appearance of the caret michael@0: * @param inMakeReadonly true to show the caret in a 'read only' state, michael@0: * false to show the caret in normal, editing state michael@0: */ michael@0: void SetCaretReadOnly(bool inMakeReadonly); michael@0: michael@0: /** GetCaretReadOnly get the appearance of the caret michael@0: * @return true if the caret is in 'read only' state, otherwise, michael@0: * returns false michael@0: */ michael@0: bool GetCaretReadOnly() michael@0: { michael@0: return mReadOnly; michael@0: } michael@0: michael@0: /** michael@0: * Gets the position and size of the caret that would be drawn for michael@0: * the focus node/offset of aSelection (assuming it would be drawn, michael@0: * i.e., disregarding blink status). The geometry is stored in aRect, michael@0: * and we return the frame aRect is relative to. michael@0: * @param aRect must be non-null michael@0: * @param aBidiIndicatorSize if non-null, set to the bidi indicator size. michael@0: */ michael@0: virtual nsIFrame* GetGeometry(nsISelection* aSelection, michael@0: nsRect* aRect, michael@0: nscoord* aBidiIndicatorSize = nullptr); michael@0: michael@0: /** EraseCaret michael@0: * this will erase the caret if its drawn and reset drawn status michael@0: */ michael@0: void EraseCaret(); michael@0: michael@0: void SetVisibilityDuringSelection(bool aVisibility); michael@0: michael@0: /** DrawAtPosition michael@0: * michael@0: * Draw the caret explicitly, at the specified node and offset. michael@0: * To avoid drawing glitches, you should call EraseCaret() michael@0: * after each call to DrawAtPosition(). michael@0: * michael@0: * Note: This call breaks the caret's ability to blink at all. michael@0: **/ michael@0: nsresult DrawAtPosition(nsIDOMNode* aNode, int32_t aOffset); michael@0: michael@0: /** GetCaretFrame michael@0: * Get the current frame that the caret should be drawn in. If the caret is michael@0: * not currently visible (i.e., it is between blinks), then this will michael@0: * return null. michael@0: * michael@0: * @param aOffset is result of the caret offset in the content. michael@0: */ michael@0: nsIFrame* GetCaretFrame(int32_t *aOffset = nullptr); michael@0: michael@0: /** GetCaretRect michael@0: * Get the current caret rect. Only call this when GetCaretFrame returns michael@0: * non-null. michael@0: */ michael@0: nsRect GetCaretRect() michael@0: { michael@0: nsRect r; michael@0: r.UnionRect(mCaretRect, GetHookRect()); michael@0: return r; michael@0: } michael@0: michael@0: /** InvalidateOutsideCaret michael@0: * Invalidate the area that the caret currently occupies if the caret is michael@0: * outside of its frame's overflow area. This is used when the content that michael@0: * the caret is currently drawn is is being deleted or reflowed. michael@0: */ michael@0: void InvalidateOutsideCaret(); michael@0: michael@0: /** UpdateCaretPosition michael@0: * Update the caret's current frame and rect, but don't draw yet. This is michael@0: * useful for flickerless moving of the caret (e.g., when the frame the michael@0: * caret is in reflows and is moved). michael@0: */ michael@0: void UpdateCaretPosition(); michael@0: michael@0: /** PaintCaret michael@0: * Actually paint the caret onto the given rendering context. michael@0: */ michael@0: void PaintCaret(nsDisplayListBuilder *aBuilder, michael@0: nsRenderingContext *aCtx, michael@0: nsIFrame *aForFrame, michael@0: const nsPoint &aOffset); michael@0: /** michael@0: * Sets whether the caret should only be visible in nodes that are not michael@0: * user-modify: read-only, or whether it should be visible in all nodes. michael@0: * michael@0: * @param aIgnoreUserModify true to have the cursor visible in all nodes, michael@0: * false to have it visible in all nodes except michael@0: * those with user-modify: read-only michael@0: */ michael@0: michael@0: void SetIgnoreUserModify(bool aIgnoreUserModify); michael@0: michael@0: //nsISelectionListener interface michael@0: NS_DECL_NSISELECTIONLISTENER michael@0: michael@0: static void CaretBlinkCallback(nsITimer *aTimer, void *aClosure); michael@0: michael@0: nsresult GetCaretFrameForNodeOffset(nsIContent* aContentNode, michael@0: int32_t aOffset, michael@0: nsFrameSelection::HINT aFrameHint, michael@0: uint8_t aBidiLevel, michael@0: nsIFrame** aReturnFrame, michael@0: int32_t* aReturnOffset); michael@0: michael@0: void CheckCaretDrawingState(); michael@0: michael@0: protected: michael@0: michael@0: void KillTimer(); michael@0: nsresult PrimeTimer(); michael@0: michael@0: void StartBlinking(); michael@0: void StopBlinking(); michael@0: michael@0: bool DrawAtPositionWithHint(nsIDOMNode* aNode, michael@0: int32_t aOffset, michael@0: nsFrameSelection::HINT aFrameHint, michael@0: uint8_t aBidiLevel, michael@0: bool aInvalidate); michael@0: michael@0: struct Metrics { michael@0: nscoord mBidiIndicatorSize; // width and height of bidi indicator michael@0: nscoord mCaretWidth; // full caret width including bidi indicator michael@0: }; michael@0: Metrics ComputeMetrics(nsIFrame* aFrame, int32_t aOffset, nscoord aCaretHeight); michael@0: nsresult GetGeometryForFrame(nsIFrame* aFrame, michael@0: int32_t aFrameOffset, michael@0: nsRect* aRect, michael@0: nscoord* aBidiIndicatorSize); michael@0: michael@0: // Returns true if the caret should be drawn. When |mDrawn| is true, michael@0: // this returns true, so that we erase the drawn caret. If |aIgnoreDrawnState| michael@0: // is true, we don't take into account whether the caret is currently michael@0: // drawn or not. This can be used to determine if the caret is drawn when michael@0: // it shouldn't be. michael@0: bool MustDrawCaret(bool aIgnoreDrawnState); michael@0: michael@0: void DrawCaret(bool aInvalidate); michael@0: void DrawCaretAfterBriefDelay(); michael@0: bool UpdateCaretRects(nsIFrame* aFrame, int32_t aFrameOffset); michael@0: nsRect GetHookRect() michael@0: { michael@0: return mHookRect; michael@0: } michael@0: void ToggleDrawnStatus() { mDrawn = !mDrawn; } michael@0: michael@0: nsFrameSelection* GetFrameSelection(); michael@0: michael@0: // Returns true if we should not draw the caret because of XUL menu popups. michael@0: // The caret should be hidden if: michael@0: // 1. An open popup contains the caret, but a menu popup exists before the michael@0: // caret-owning popup in the popup list (i.e. a menu is in front of the michael@0: // popup with the caret). If the menu itself contains the caret we don't michael@0: // hide it. michael@0: // 2. A menu popup is open, but there is no caret present in any popup. michael@0: // 3. The caret selection is empty. michael@0: bool IsMenuPopupHidingCaret(); michael@0: michael@0: protected: michael@0: michael@0: nsWeakPtr mPresShell; michael@0: nsWeakPtr mDomSelectionWeak; michael@0: michael@0: nsCOMPtr mBlinkTimer; michael@0: michael@0: // XXX these fields should go away and the values be acquired as needed, michael@0: // probably by ComputeMetrics. michael@0: uint32_t mBlinkRate; // time for one cyle (on then off), in milliseconds michael@0: nscoord mCaretWidthCSSPx; // caret width in CSS pixels michael@0: float mCaretAspectRatio; // caret width/height aspect ratio michael@0: michael@0: bool mVisible; // is the caret blinking michael@0: michael@0: bool mDrawn; // Denotes when the caret is physically drawn on the screen. michael@0: bool mPendingDraw; // True when the last on-state draw was suppressed. michael@0: michael@0: bool mReadOnly; // it the caret in readonly state (draws differently) michael@0: bool mShowDuringSelection; // show when text is selected michael@0: michael@0: bool mIgnoreUserModify; michael@0: michael@0: bool mKeyboardRTL; // is the keyboard language right-to-left michael@0: bool mBidiUI; // is bidi UI turned on michael@0: nsRect mHookRect; // directional hook on the caret michael@0: uint8_t mLastBidiLevel; // saved bidi level of the last draw request, to use when we erase michael@0: nsRect mCaretRect; // the last caret rect, in the coodinates of the last frame. michael@0: michael@0: nsCOMPtr mLastContent; // store the content the caret was last requested to be drawn michael@0: // in (by DrawAtPosition()/DrawCaret()), michael@0: // note that this can be different than where it was michael@0: // actually drawn (anon
in text control) michael@0: int32_t mLastContentOffset; // the offset for the last request michael@0: michael@0: nsFrameSelection::HINT mLastHint; // the hint associated with the last request, see also michael@0: // mLastBidiLevel below michael@0: michael@0: }; michael@0: michael@0: #endif //nsCaret_h__