michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* vim: set ts=2 et sw=2 tw=80: */ 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 file, michael@0: * You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef mozilla_Selection_h__ michael@0: #define mozilla_Selection_h__ michael@0: michael@0: #include "nsIWeakReference.h" michael@0: michael@0: #include "nsISelection.h" michael@0: #include "nsISelectionController.h" michael@0: #include "nsISelectionPrivate.h" michael@0: #include "nsRange.h" michael@0: #include "nsThreadUtils.h" michael@0: #include "mozilla/TextRange.h" michael@0: #include "nsWrapperCache.h" michael@0: michael@0: struct CachedOffsetForFrame; michael@0: class nsAutoScrollTimer; michael@0: class nsIContentIterator; michael@0: class nsIFrame; michael@0: class nsFrameSelection; michael@0: struct SelectionDetails; michael@0: michael@0: namespace mozilla { michael@0: class ErrorResult; michael@0: } michael@0: michael@0: struct RangeData michael@0: { michael@0: RangeData(nsRange* aRange) michael@0: : mRange(aRange) michael@0: {} michael@0: michael@0: nsRefPtr mRange; michael@0: mozilla::TextRangeStyle mTextRangeStyle; michael@0: }; michael@0: michael@0: // Note, the ownership of mozilla::dom::Selection depends on which way the michael@0: // object is created. When nsFrameSelection has created Selection, michael@0: // addreffing/releasing the Selection object is aggregated to nsFrameSelection. michael@0: // Otherwise normal addref/release is used. This ensures that nsFrameSelection michael@0: // is never deleted before its Selections. michael@0: namespace mozilla { michael@0: namespace dom { michael@0: michael@0: class Selection : public nsISelectionPrivate, michael@0: public nsWrapperCache, michael@0: public nsSupportsWeakReference michael@0: { michael@0: public: michael@0: Selection(); michael@0: Selection(nsFrameSelection *aList); michael@0: virtual ~Selection(); michael@0: michael@0: NS_DECL_CYCLE_COLLECTING_ISUPPORTS michael@0: NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(Selection, nsISelectionPrivate) michael@0: NS_DECL_NSISELECTION michael@0: NS_DECL_NSISELECTIONPRIVATE michael@0: michael@0: nsIDocument* GetParentObject() const; michael@0: michael@0: // utility methods for scrolling the selection into view michael@0: nsPresContext* GetPresContext() const; michael@0: nsIPresShell* GetPresShell() const; michael@0: nsFrameSelection* GetFrameSelection() const { return mFrameSelection; } michael@0: // Returns a rect containing the selection region, and frame that that michael@0: // position is relative to. For SELECTION_ANCHOR_REGION or michael@0: // SELECTION_FOCUS_REGION the rect is a zero-width rectangle. For michael@0: // SELECTION_WHOLE_SELECTION the rect contains both the anchor and focus michael@0: // region rects. michael@0: nsIFrame* GetSelectionAnchorGeometry(SelectionRegion aRegion, nsRect *aRect); michael@0: // Returns the position of the region (SELECTION_ANCHOR_REGION or michael@0: // SELECTION_FOCUS_REGION only), and frame that that position is relative to. michael@0: // The 'position' is a zero-width rectangle. michael@0: nsIFrame* GetSelectionEndPointGeometry(SelectionRegion aRegion, nsRect *aRect); michael@0: michael@0: nsresult PostScrollSelectionIntoViewEvent( michael@0: SelectionRegion aRegion, michael@0: int32_t aFlags, michael@0: nsIPresShell::ScrollAxis aVertical, michael@0: nsIPresShell::ScrollAxis aHorizontal); michael@0: enum { michael@0: SCROLL_SYNCHRONOUS = 1<<1, michael@0: SCROLL_FIRST_ANCESTOR_ONLY = 1<<2, michael@0: SCROLL_DO_FLUSH = 1<<3, michael@0: SCROLL_OVERFLOW_HIDDEN = 1<<5 michael@0: }; michael@0: // aDoFlush only matters if aIsSynchronous is true. If not, we'll just flush michael@0: // when the scroll event fires so we make sure to scroll to the right place. michael@0: nsresult ScrollIntoView(SelectionRegion aRegion, michael@0: nsIPresShell::ScrollAxis aVertical = michael@0: nsIPresShell::ScrollAxis(), michael@0: nsIPresShell::ScrollAxis aHorizontal = michael@0: nsIPresShell::ScrollAxis(), michael@0: int32_t aFlags = 0); michael@0: nsresult SubtractRange(RangeData* aRange, nsRange* aSubtract, michael@0: nsTArray* aOutput); michael@0: nsresult AddItem(nsRange *aRange, int32_t* aOutIndex); michael@0: nsresult RemoveItem(nsRange *aRange); michael@0: nsresult RemoveCollapsedRanges(); michael@0: nsresult Clear(nsPresContext* aPresContext); michael@0: nsresult Collapse(nsINode* aParentNode, int32_t aOffset); michael@0: nsresult Extend(nsINode* aParentNode, int32_t aOffset); michael@0: nsRange* GetRangeAt(int32_t aIndex); michael@0: int32_t GetRangeCount() { return mRanges.Length(); } michael@0: michael@0: // Get the anchor-to-focus range if we don't care which end is michael@0: // anchor and which end is focus. michael@0: const nsRange* GetAnchorFocusRange() const { michael@0: return mAnchorFocusRange; michael@0: } michael@0: michael@0: nsDirection GetDirection(){return mDirection;} michael@0: void SetDirection(nsDirection aDir){mDirection = aDir;} michael@0: nsresult SetAnchorFocusToRange(nsRange *aRange); michael@0: void ReplaceAnchorFocusRange(nsRange *aRange); michael@0: michael@0: // NS_IMETHOD GetPrimaryFrameForRangeEndpoint(nsIDOMNode *aNode, int32_t aOffset, bool aIsEndNode, nsIFrame **aResultFrame); michael@0: NS_IMETHOD GetPrimaryFrameForAnchorNode(nsIFrame **aResultFrame); michael@0: NS_IMETHOD GetPrimaryFrameForFocusNode(nsIFrame **aResultFrame, int32_t *aOffset, bool aVisual); michael@0: NS_IMETHOD LookUpSelection(nsIContent *aContent, int32_t aContentOffset, int32_t aContentLength, michael@0: SelectionDetails **aReturnDetails, SelectionType aType, bool aSlowCheck); michael@0: NS_IMETHOD Repaint(nsPresContext* aPresContext); michael@0: michael@0: // Note: StartAutoScrollTimer might destroy arbitrary frames etc. michael@0: nsresult StartAutoScrollTimer(nsIFrame *aFrame, michael@0: nsPoint& aPoint, michael@0: uint32_t aDelay); michael@0: michael@0: nsresult StopAutoScrollTimer(); michael@0: michael@0: JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE; michael@0: michael@0: // WebIDL methods michael@0: nsINode* GetAnchorNode(); michael@0: uint32_t AnchorOffset(); michael@0: nsINode* GetFocusNode(); michael@0: uint32_t FocusOffset(); michael@0: michael@0: bool IsCollapsed(); michael@0: void Collapse(nsINode& aNode, uint32_t aOffset, mozilla::ErrorResult& aRv); michael@0: void CollapseToStart(mozilla::ErrorResult& aRv); michael@0: void CollapseToEnd(mozilla::ErrorResult& aRv); michael@0: michael@0: void Extend(nsINode& aNode, uint32_t aOffset, mozilla::ErrorResult& aRv); michael@0: michael@0: void SelectAllChildren(nsINode& aNode, mozilla::ErrorResult& aRv); michael@0: void DeleteFromDocument(mozilla::ErrorResult& aRv); michael@0: michael@0: uint32_t RangeCount() const michael@0: { michael@0: return mRanges.Length(); michael@0: } michael@0: nsRange* GetRangeAt(uint32_t aIndex, mozilla::ErrorResult& aRv); michael@0: void AddRange(nsRange& aRange, mozilla::ErrorResult& aRv); michael@0: void RemoveRange(nsRange& aRange, mozilla::ErrorResult& aRv); michael@0: void RemoveAllRanges(mozilla::ErrorResult& aRv); michael@0: michael@0: void Stringify(nsAString& aResult); michael@0: michael@0: bool ContainsNode(nsINode* aNode, bool aPartlyContained, mozilla::ErrorResult& aRv); michael@0: michael@0: void Modify(const nsAString& aAlter, const nsAString& aDirection, michael@0: const nsAString& aGranularity, mozilla::ErrorResult& aRv); michael@0: michael@0: bool GetInterlinePosition(mozilla::ErrorResult& aRv); michael@0: void SetInterlinePosition(bool aValue, mozilla::ErrorResult& aRv); michael@0: michael@0: void ToStringWithFormat(const nsAString& aFormatType, michael@0: uint32_t aFlags, michael@0: int32_t aWrapColumn, michael@0: nsAString& aReturn, michael@0: mozilla::ErrorResult& aRv); michael@0: void AddSelectionListener(nsISelectionListener* aListener, michael@0: mozilla::ErrorResult& aRv); michael@0: void RemoveSelectionListener(nsISelectionListener* aListener, michael@0: mozilla::ErrorResult& aRv); michael@0: michael@0: int16_t Type() const { return mType; } michael@0: michael@0: void GetRangesForInterval(nsINode& aBeginNode, int32_t aBeginOffset, michael@0: nsINode& aEndNode, int32_t aEndOffset, michael@0: bool aAllowAdjacent, michael@0: nsTArray>& aReturn, michael@0: mozilla::ErrorResult& aRv); michael@0: michael@0: void ScrollIntoView(int16_t aRegion, bool aIsSynchronous, michael@0: int16_t aVPercent, int16_t aHPercent, michael@0: mozilla::ErrorResult& aRv); michael@0: michael@0: private: michael@0: friend class ::nsAutoScrollTimer; michael@0: michael@0: // Note: DoAutoScroll might destroy arbitrary frames etc. michael@0: nsresult DoAutoScroll(nsIFrame *aFrame, nsPoint& aPoint); michael@0: michael@0: public: michael@0: SelectionType GetType(){return mType;} michael@0: void SetType(SelectionType aType){mType = aType;} michael@0: michael@0: nsresult NotifySelectionListeners(); michael@0: michael@0: private: michael@0: michael@0: class ScrollSelectionIntoViewEvent; michael@0: friend class ScrollSelectionIntoViewEvent; michael@0: michael@0: class ScrollSelectionIntoViewEvent : public nsRunnable { michael@0: public: michael@0: NS_DECL_NSIRUNNABLE michael@0: ScrollSelectionIntoViewEvent(Selection* aSelection, michael@0: SelectionRegion aRegion, michael@0: nsIPresShell::ScrollAxis aVertical, michael@0: nsIPresShell::ScrollAxis aHorizontal, michael@0: int32_t aFlags) michael@0: : mSelection(aSelection), michael@0: mRegion(aRegion), michael@0: mVerticalScroll(aVertical), michael@0: mHorizontalScroll(aHorizontal), michael@0: mFlags(aFlags) { michael@0: NS_ASSERTION(aSelection, "null parameter"); michael@0: } michael@0: void Revoke() { mSelection = nullptr; } michael@0: private: michael@0: Selection *mSelection; michael@0: SelectionRegion mRegion; michael@0: nsIPresShell::ScrollAxis mVerticalScroll; michael@0: nsIPresShell::ScrollAxis mHorizontalScroll; michael@0: int32_t mFlags; michael@0: }; michael@0: michael@0: void setAnchorFocusRange(int32_t aIndex); // pass in index into mRanges; michael@0: // negative value clears michael@0: // mAnchorFocusRange michael@0: nsresult SelectAllFramesForContent(nsIContentIterator *aInnerIter, michael@0: nsIContent *aContent, michael@0: bool aSelected); michael@0: nsresult selectFrames(nsPresContext* aPresContext, nsRange *aRange, bool aSelect); michael@0: nsresult getTableCellLocationFromRange(nsRange *aRange, int32_t *aSelectionType, int32_t *aRow, int32_t *aCol); michael@0: nsresult addTableCellRange(nsRange *aRange, bool *aDidAddRange, int32_t *aOutIndex); michael@0: michael@0: nsresult FindInsertionPoint( michael@0: nsTArray* aElementArray, michael@0: nsINode* aPointNode, int32_t aPointOffset, michael@0: nsresult (*aComparator)(nsINode*,int32_t,nsRange*,int32_t*), michael@0: int32_t* aPoint); michael@0: bool EqualsRangeAtPoint(nsINode* aBeginNode, int32_t aBeginOffset, michael@0: nsINode* aEndNode, int32_t aEndOffset, michael@0: int32_t aRangeIndex); michael@0: nsresult GetIndicesForInterval(nsINode* aBeginNode, int32_t aBeginOffset, michael@0: nsINode* aEndNode, int32_t aEndOffset, michael@0: bool aAllowAdjacent, michael@0: int32_t* aStartIndex, int32_t* aEndIndex); michael@0: RangeData* FindRangeData(nsIDOMRange* aRange); michael@0: michael@0: // These are the ranges inside this selection. They are kept sorted in order michael@0: // of DOM start position. michael@0: // michael@0: // This data structure is sorted by the range beginnings. As the ranges are michael@0: // disjoint, it is also implicitly sorted by the range endings. This allows michael@0: // us to perform binary searches when searching for existence of a range, michael@0: // giving us O(log n) search time. michael@0: // michael@0: // Inserting a new range requires finding the overlapping interval, requiring michael@0: // two binary searches plus up to an additional 6 DOM comparisons. If this michael@0: // proves to be a performance concern, then an interval tree may be a michael@0: // possible solution, allowing the calculation of the overlap interval in michael@0: // O(log n) time, though this would require rebalancing and other overhead. michael@0: nsTArray mRanges; michael@0: michael@0: nsRefPtr mAnchorFocusRange; michael@0: nsRefPtr mFrameSelection; michael@0: nsRefPtr mAutoScrollTimer; michael@0: nsCOMArray mSelectionListeners; michael@0: nsRevocableEventPtr mScrollEvent; michael@0: CachedOffsetForFrame *mCachedOffsetForFrame; michael@0: nsDirection mDirection; michael@0: SelectionType mType; michael@0: }; michael@0: michael@0: } // namespace dom michael@0: } // namespace mozilla michael@0: michael@0: #endif // mozilla_Selection_h__