gecko/layout/generic/nsTypedSelection.h

220 lines
9.1 KiB
C++

/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef nsTypedSelection_h
#define nsTypedSelection_h
#include "nsIWeakReference.h"
#include "nsISelection.h"
#include "nsISelectionController.h"
#include "nsISelectionPrivate.h"
struct CachedOffsetForFrame;
class nsAutoScrollTimer;
class nsIContentIterator;
class nsIFrame;
class nsRange;
struct SelectionDetails;
struct RangeData
{
RangeData(nsRange* aRange)
: mRange(aRange)
{}
nsRefPtr<nsRange> mRange;
nsTextRangeStyle mTextRangeStyle;
};
// Note, the ownership of nsTypedSelection depends on which way the object is
// created. When nsFrameSelection has created nsTypedSelection,
// addreffing/releasing nsTypedSelection object is aggregated to
// nsFrameSelection. Otherwise normal addref/release is used.
// This ensures that nsFrameSelection is never deleted before its
// nsTypedSelections.
class nsTypedSelection : public nsISelectionPrivate,
public nsSupportsWeakReference
{
public:
nsTypedSelection();
nsTypedSelection(nsFrameSelection *aList);
virtual ~nsTypedSelection();
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsTypedSelection, nsISelectionPrivate)
NS_DECL_NSISELECTION
NS_DECL_NSISELECTIONPRIVATE
// utility methods for scrolling the selection into view
nsresult GetPresContext(nsPresContext **aPresContext);
nsresult GetPresShell(nsIPresShell **aPresShell);
// Returns a rect containing the selection region, and frame that that
// position is relative to. For SELECTION_ANCHOR_REGION or
// SELECTION_FOCUS_REGION the rect is a zero-width rectangle. For
// SELECTION_WHOLE_SELECTION the rect contains both the anchor and focus
// region rects.
nsIFrame* GetSelectionAnchorGeometry(SelectionRegion aRegion, nsRect *aRect);
// Returns the position of the region (SELECTION_ANCHOR_REGION or
// SELECTION_FOCUS_REGION only), and frame that that position is relative to.
// The 'position' is a zero-width rectangle.
nsIFrame* GetSelectionEndPointGeometry(SelectionRegion aRegion, nsRect *aRect);
nsresult PostScrollSelectionIntoViewEvent(
SelectionRegion aRegion,
bool aFirstAncestorOnly,
nsIPresShell::ScrollAxis aVertical,
nsIPresShell::ScrollAxis aHorizontal);
enum {
SCROLL_SYNCHRONOUS = 1<<1,
SCROLL_FIRST_ANCESTOR_ONLY = 1<<2,
SCROLL_DO_FLUSH = 1<<3
};
// aDoFlush only matters if aIsSynchronous is true. If not, we'll just flush
// when the scroll event fires so we make sure to scroll to the right place.
nsresult ScrollIntoView(SelectionRegion aRegion,
nsIPresShell::ScrollAxis aVertical =
nsIPresShell::ScrollAxis(),
nsIPresShell::ScrollAxis aHorizontal =
nsIPresShell::ScrollAxis(),
PRInt32 aFlags = 0);
nsresult SubtractRange(RangeData* aRange, nsRange* aSubtract,
nsTArray<RangeData>* aOutput);
nsresult AddItem(nsRange *aRange, PRInt32* aOutIndex = nsnull);
nsresult RemoveItem(nsRange *aRange);
nsresult RemoveCollapsedRanges();
nsresult Clear(nsPresContext* aPresContext);
nsresult Collapse(nsINode* aParentNode, PRInt32 aOffset);
nsresult Extend(nsINode* aParentNode, PRInt32 aOffset);
nsRange* GetRangeAt(PRInt32 aIndex);
PRInt32 GetRangeCount() { return mRanges.Length(); }
// methods for convenience. Note, these don't addref
nsINode* GetAnchorNode();
PRInt32 GetAnchorOffset();
nsINode* GetFocusNode();
PRInt32 GetFocusOffset();
// Get the anchor-to-focus range if we don't care which end is
// anchor and which end is focus.
const nsRange* GetAnchorFocusRange() const {
return mAnchorFocusRange;
}
nsDirection GetDirection(){return mDirection;}
void SetDirection(nsDirection aDir){mDirection = aDir;}
nsresult SetAnchorFocusToRange(nsRange *aRange);
void ReplaceAnchorFocusRange(nsRange *aRange);
// NS_IMETHOD GetPrimaryFrameForRangeEndpoint(nsIDOMNode *aNode, PRInt32 aOffset, bool aIsEndNode, nsIFrame **aResultFrame);
NS_IMETHOD GetPrimaryFrameForAnchorNode(nsIFrame **aResultFrame);
NS_IMETHOD GetPrimaryFrameForFocusNode(nsIFrame **aResultFrame, PRInt32 *aOffset, bool aVisual);
NS_IMETHOD LookUpSelection(nsIContent *aContent, PRInt32 aContentOffset, PRInt32 aContentLength,
SelectionDetails **aReturnDetails, SelectionType aType, bool aSlowCheck);
NS_IMETHOD Repaint(nsPresContext* aPresContext);
// Note: StartAutoScrollTimer might destroy arbitrary frames etc.
nsresult StartAutoScrollTimer(nsIFrame *aFrame,
nsPoint& aPoint,
PRUint32 aDelay);
nsresult StopAutoScrollTimer();
private:
friend class nsAutoScrollTimer;
// Note: DoAutoScroll might destroy arbitrary frames etc.
nsresult DoAutoScroll(nsIFrame *aFrame, nsPoint& aPoint);
public:
SelectionType GetType(){return mType;}
void SetType(SelectionType aType){mType = aType;}
nsresult NotifySelectionListeners();
private:
friend class nsSelectionIterator;
class ScrollSelectionIntoViewEvent;
friend class ScrollSelectionIntoViewEvent;
class ScrollSelectionIntoViewEvent : public nsRunnable {
public:
NS_DECL_NSIRUNNABLE
ScrollSelectionIntoViewEvent(nsTypedSelection *aTypedSelection,
SelectionRegion aRegion,
nsIPresShell::ScrollAxis aVertical,
nsIPresShell::ScrollAxis aHorizontal,
bool aFirstAncestorOnly)
: mTypedSelection(aTypedSelection),
mRegion(aRegion),
mVerticalScroll(aVertical),
mHorizontalScroll(aHorizontal),
mFirstAncestorOnly(aFirstAncestorOnly) {
NS_ASSERTION(aTypedSelection, "null parameter");
}
void Revoke() { mTypedSelection = nsnull; }
private:
nsTypedSelection *mTypedSelection;
SelectionRegion mRegion;
nsIPresShell::ScrollAxis mVerticalScroll;
nsIPresShell::ScrollAxis mHorizontalScroll;
bool mFirstAncestorOnly;
};
void setAnchorFocusRange(PRInt32 aIndex); // pass in index into mRanges;
// negative value clears
// mAnchorFocusRange
nsresult SelectAllFramesForContent(nsIContentIterator *aInnerIter,
nsIContent *aContent,
bool aSelected);
nsresult selectFrames(nsPresContext* aPresContext, nsRange *aRange, bool aSelect);
nsresult getTableCellLocationFromRange(nsRange *aRange, PRInt32 *aSelectionType, PRInt32 *aRow, PRInt32 *aCol);
nsresult addTableCellRange(nsRange *aRange, bool *aDidAddRange, PRInt32 *aOutIndex);
nsresult FindInsertionPoint(
nsTArray<RangeData>* aElementArray,
nsINode* aPointNode, PRInt32 aPointOffset,
nsresult (*aComparator)(nsINode*,PRInt32,nsRange*,PRInt32*),
PRInt32* aPoint);
bool EqualsRangeAtPoint(nsINode* aBeginNode, PRInt32 aBeginOffset,
nsINode* aEndNode, PRInt32 aEndOffset,
PRInt32 aRangeIndex);
void GetIndicesForInterval(nsINode* aBeginNode, PRInt32 aBeginOffset,
nsINode* aEndNode, PRInt32 aEndOffset,
bool aAllowAdjacent,
PRInt32 *aStartIndex, PRInt32 *aEndIndex);
RangeData* FindRangeData(nsIDOMRange* aRange);
// These are the ranges inside this selection. They are kept sorted in order
// of DOM start position.
//
// This data structure is sorted by the range beginnings. As the ranges are
// disjoint, it is also implicitly sorted by the range endings. This allows
// us to perform binary searches when searching for existence of a range,
// giving us O(log n) search time.
//
// Inserting a new range requires finding the overlapping interval, requiring
// two binary searches plus up to an additional 6 DOM comparisons. If this
// proves to be a performance concern, then an interval tree may be a
// possible solution, allowing the calculation of the overlap interval in
// O(log n) time, though this would require rebalancing and other overhead.
nsTArray<RangeData> mRanges;
nsRefPtr<nsRange> mAnchorFocusRange;
nsRefPtr<nsFrameSelection> mFrameSelection;
nsWeakPtr mPresShellWeak;
nsRefPtr<nsAutoScrollTimer> mAutoScrollTimer;
nsCOMArray<nsISelectionListener> mSelectionListeners;
nsRevocableEventPtr<ScrollSelectionIntoViewEvent> mScrollEvent;
CachedOffsetForFrame *mCachedOffsetForFrame;
nsDirection mDirection;
SelectionType mType;
};
#endif // nsTypedSelection_h