diff options
author | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
---|---|---|
committer | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
commit | 5f8de423f190bbb79a62f804151bc24824fa32d8 (patch) | |
tree | 10027f336435511475e392454359edea8e25895d /editor/libeditor/SelectionState.h | |
parent | 49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff) | |
download | UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.lz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.xz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.zip |
Add m-esr52 at 52.6.0
Diffstat (limited to 'editor/libeditor/SelectionState.h')
-rw-r--r-- | editor/libeditor/SelectionState.h | 357 |
1 files changed, 357 insertions, 0 deletions
diff --git a/editor/libeditor/SelectionState.h b/editor/libeditor/SelectionState.h new file mode 100644 index 000000000..36e7b7769 --- /dev/null +++ b/editor/libeditor/SelectionState.h @@ -0,0 +1,357 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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 mozilla_SelectionState_h +#define mozilla_SelectionState_h + +#include "nsCOMPtr.h" +#include "nsIDOMNode.h" +#include "nsINode.h" +#include "nsTArray.h" +#include "nscore.h" + +class nsCycleCollectionTraversalCallback; +class nsIDOMCharacterData; +class nsRange; +namespace mozilla { +class RangeUpdater; +namespace dom { +class Selection; +class Text; +} // namespace dom + +/** + * A helper struct for saving/setting ranges. + */ +struct RangeItem final +{ + RangeItem(); + +private: + // Private destructor, to discourage deletion outside of Release(): + ~RangeItem(); + +public: + void StoreRange(nsRange* aRange); + already_AddRefed<nsRange> GetRange(); + + NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(RangeItem) + NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(RangeItem) + + nsCOMPtr<nsINode> startNode; + int32_t startOffset; + nsCOMPtr<nsINode> endNode; + int32_t endOffset; +}; + +/** + * mozilla::SelectionState + * + * Class for recording selection info. Stores selection as collection of + * { {startnode, startoffset} , {endnode, endoffset} } tuples. Can't store + * ranges since dom gravity will possibly change the ranges. + */ + +class SelectionState final +{ +public: + SelectionState(); + ~SelectionState(); + + void SaveSelection(dom::Selection *aSel); + nsresult RestoreSelection(dom::Selection* aSel); + bool IsCollapsed(); + bool IsEqual(SelectionState *aSelState); + void MakeEmpty(); + bool IsEmpty(); +private: + nsTArray<RefPtr<RangeItem>> mArray; + + friend class RangeUpdater; + friend void ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback&, + SelectionState&, + const char*, + uint32_t); + friend void ImplCycleCollectionUnlink(SelectionState&); +}; + +inline void +ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback, + SelectionState& aField, + const char* aName, + uint32_t aFlags = 0) +{ + ImplCycleCollectionTraverse(aCallback, aField.mArray, aName, aFlags); +} + +inline void +ImplCycleCollectionUnlink(SelectionState& aField) +{ + ImplCycleCollectionUnlink(aField.mArray); +} + +class RangeUpdater final +{ +public: + RangeUpdater(); + ~RangeUpdater(); + + void RegisterRangeItem(RangeItem* aRangeItem); + void DropRangeItem(RangeItem* aRangeItem); + nsresult RegisterSelectionState(SelectionState& aSelState); + nsresult DropSelectionState(SelectionState& aSelState); + + // editor selection gravity routines. Note that we can't always depend on + // DOM Range gravity to do what we want to the "real" selection. For instance, + // if you move a node, that corresponds to deleting it and reinserting it. + // DOM Range gravity will promote the selection out of the node on deletion, + // which is not what you want if you know you are reinserting it. + nsresult SelAdjCreateNode(nsINode* aParent, int32_t aPosition); + nsresult SelAdjCreateNode(nsIDOMNode* aParent, int32_t aPosition); + nsresult SelAdjInsertNode(nsINode* aParent, int32_t aPosition); + nsresult SelAdjInsertNode(nsIDOMNode* aParent, int32_t aPosition); + void SelAdjDeleteNode(nsINode* aNode); + void SelAdjDeleteNode(nsIDOMNode* aNode); + nsresult SelAdjSplitNode(nsIContent& aOldRightNode, int32_t aOffset, + nsIContent* aNewLeftNode); + nsresult SelAdjJoinNodes(nsINode& aLeftNode, + nsINode& aRightNode, + nsINode& aParent, + int32_t aOffset, + int32_t aOldLeftNodeLength); + void SelAdjInsertText(dom::Text& aTextNode, int32_t aOffset, + const nsAString &aString); + nsresult SelAdjDeleteText(nsIContent* aTextNode, int32_t aOffset, + int32_t aLength); + nsresult SelAdjDeleteText(nsIDOMCharacterData* aTextNode, + int32_t aOffset, int32_t aLength); + // the following gravity routines need will/did sandwiches, because the other + // gravity routines will be called inside of these sandwiches, but should be + // ignored. + nsresult WillReplaceContainer(); + nsresult DidReplaceContainer(dom::Element* aOriginalNode, + dom::Element* aNewNode); + nsresult WillRemoveContainer(); + nsresult DidRemoveContainer(nsINode* aNode, nsINode* aParent, + int32_t aOffset, uint32_t aNodeOrigLen); + nsresult DidRemoveContainer(nsIDOMNode* aNode, nsIDOMNode* aParent, + int32_t aOffset, uint32_t aNodeOrigLen); + nsresult WillInsertContainer(); + nsresult DidInsertContainer(); + void WillMoveNode(); + void DidMoveNode(nsINode* aOldParent, int32_t aOldOffset, + nsINode* aNewParent, int32_t aNewOffset); + +private: + friend void ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback&, + RangeUpdater&, + const char*, + uint32_t); + friend void ImplCycleCollectionUnlink(RangeUpdater& aField); + + nsTArray<RefPtr<RangeItem>> mArray; + bool mLock; +}; + +inline void +ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback, + RangeUpdater& aField, + const char* aName, + uint32_t aFlags = 0) +{ + ImplCycleCollectionTraverse(aCallback, aField.mArray, aName, aFlags); +} + +inline void +ImplCycleCollectionUnlink(RangeUpdater& aField) +{ + ImplCycleCollectionUnlink(aField.mArray); +} + +/** + * Helper class for using SelectionState. Stack based class for doing + * preservation of dom points across editor actions. + */ + +class MOZ_STACK_CLASS AutoTrackDOMPoint final +{ +private: + RangeUpdater& mRangeUpdater; + // Allow tracking either nsIDOMNode or nsINode until nsIDOMNode is gone + nsCOMPtr<nsINode>* mNode; + nsCOMPtr<nsIDOMNode>* mDOMNode; + int32_t* mOffset; + RefPtr<RangeItem> mRangeItem; + +public: + AutoTrackDOMPoint(RangeUpdater& aRangeUpdater, + nsCOMPtr<nsINode>* aNode, int32_t* aOffset) + : mRangeUpdater(aRangeUpdater) + , mNode(aNode) + , mDOMNode(nullptr) + , mOffset(aOffset) + { + mRangeItem = new RangeItem(); + mRangeItem->startNode = *mNode; + mRangeItem->endNode = *mNode; + mRangeItem->startOffset = *mOffset; + mRangeItem->endOffset = *mOffset; + mRangeUpdater.RegisterRangeItem(mRangeItem); + } + + AutoTrackDOMPoint(RangeUpdater& aRangeUpdater, + nsCOMPtr<nsIDOMNode>* aNode, int32_t* aOffset) + : mRangeUpdater(aRangeUpdater) + , mNode(nullptr) + , mDOMNode(aNode) + , mOffset(aOffset) + { + mRangeItem = new RangeItem(); + mRangeItem->startNode = do_QueryInterface(*mDOMNode); + mRangeItem->endNode = do_QueryInterface(*mDOMNode); + mRangeItem->startOffset = *mOffset; + mRangeItem->endOffset = *mOffset; + mRangeUpdater.RegisterRangeItem(mRangeItem); + } + + ~AutoTrackDOMPoint() + { + mRangeUpdater.DropRangeItem(mRangeItem); + if (mNode) { + *mNode = mRangeItem->startNode; + } else { + *mDOMNode = GetAsDOMNode(mRangeItem->startNode); + } + *mOffset = mRangeItem->startOffset; + } +}; + +/** + * Another helper class for SelectionState. Stack based class for doing + * Will/DidReplaceContainer() + */ + +class MOZ_STACK_CLASS AutoReplaceContainerSelNotify final +{ +private: + RangeUpdater& mRangeUpdater; + dom::Element* mOriginalElement; + dom::Element* mNewElement; + +public: + AutoReplaceContainerSelNotify(RangeUpdater& aRangeUpdater, + dom::Element* aOriginalElement, + dom::Element* aNewElement) + : mRangeUpdater(aRangeUpdater) + , mOriginalElement(aOriginalElement) + , mNewElement(aNewElement) + { + mRangeUpdater.WillReplaceContainer(); + } + + ~AutoReplaceContainerSelNotify() + { + mRangeUpdater.DidReplaceContainer(mOriginalElement, mNewElement); + } +}; + +/** + * Another helper class for SelectionState. Stack based class for doing + * Will/DidRemoveContainer() + */ + +class MOZ_STACK_CLASS AutoRemoveContainerSelNotify final +{ +private: + RangeUpdater& mRangeUpdater; + nsIDOMNode* mNode; + nsIDOMNode* mParent; + int32_t mOffset; + uint32_t mNodeOrigLen; + +public: + AutoRemoveContainerSelNotify(RangeUpdater& aRangeUpdater, + nsINode* aNode, + nsINode* aParent, + int32_t aOffset, + uint32_t aNodeOrigLen) + : mRangeUpdater(aRangeUpdater) + , mNode(aNode->AsDOMNode()) + , mParent(aParent->AsDOMNode()) + , mOffset(aOffset) + , mNodeOrigLen(aNodeOrigLen) + { + mRangeUpdater.WillRemoveContainer(); + } + + ~AutoRemoveContainerSelNotify() + { + mRangeUpdater.DidRemoveContainer(mNode, mParent, mOffset, mNodeOrigLen); + } +}; + +/** + * Another helper class for SelectionState. Stack based class for doing + * Will/DidInsertContainer() + */ + +class MOZ_STACK_CLASS AutoInsertContainerSelNotify final +{ +private: + RangeUpdater& mRangeUpdater; + +public: + explicit AutoInsertContainerSelNotify(RangeUpdater& aRangeUpdater) + : mRangeUpdater(aRangeUpdater) + { + mRangeUpdater.WillInsertContainer(); + } + + ~AutoInsertContainerSelNotify() + { + mRangeUpdater.DidInsertContainer(); + } +}; + +/** + * Another helper class for SelectionState. Stack based class for doing + * Will/DidMoveNode() + */ + +class MOZ_STACK_CLASS AutoMoveNodeSelNotify final +{ +private: + RangeUpdater& mRangeUpdater; + nsINode* mOldParent; + nsINode* mNewParent; + int32_t mOldOffset; + int32_t mNewOffset; + +public: + AutoMoveNodeSelNotify(RangeUpdater& aRangeUpdater, + nsINode* aOldParent, + int32_t aOldOffset, + nsINode* aNewParent, + int32_t aNewOffset) + : mRangeUpdater(aRangeUpdater) + , mOldParent(aOldParent) + , mNewParent(aNewParent) + , mOldOffset(aOldOffset) + , mNewOffset(aNewOffset) + { + MOZ_ASSERT(aOldParent); + MOZ_ASSERT(aNewParent); + mRangeUpdater.WillMoveNode(); + } + + ~AutoMoveNodeSelNotify() + { + mRangeUpdater.DidMoveNode(mOldParent, mOldOffset, mNewParent, mNewOffset); + } +}; + +} // namespace mozilla + +#endif // #ifndef mozilla_SelectionState_h |