1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #ifndef mozilla_TextServicesDocument_h
7 #define mozilla_TextServicesDocument_h
10 #include "nsCycleCollectionParticipant.h"
11 #include "nsIEditActionListener.h"
12 #include "nsISupportsImpl.h"
13 #include "nsStringFwd.h"
20 class nsISelectionController
;
25 class FilteredContentIterator
;
35 * The TextServicesDocument presents the document in as a bunch of flattened
36 * text blocks. Each text block can be retrieved as an nsString.
38 class TextServicesDocument final
: public nsIEditActionListener
{
40 enum class IteratorStatus
: uint8_t {
41 // No iterator (I), or iterator doesn't point to anything valid.
43 // I points to first text node (TN) in current block (CB).
45 // No TN in CB, I points to first TN in prev block.
47 // No TN in CB, I points to first TN in next block.
51 RefPtr
<dom::Document
> mDocument
;
52 nsCOMPtr
<nsISelectionController
> mSelCon
;
53 RefPtr
<TextEditor
> mTextEditor
;
54 RefPtr
<FilteredContentIterator
> mFilteredIter
;
55 nsCOMPtr
<nsIContent
> mPrevTextBlock
;
56 nsCOMPtr
<nsIContent
> mNextTextBlock
;
57 nsTArray
<OffsetEntry
*> mOffsetTable
;
58 RefPtr
<nsRange
> mExtent
;
59 uint32_t mTxtSvcFilterType
;
61 int32_t mSelStartIndex
;
62 int32_t mSelStartOffset
;
64 int32_t mSelEndOffset
;
66 IteratorStatus mIteratorStatus
;
69 virtual ~TextServicesDocument();
72 TextServicesDocument();
74 NS_DECL_CYCLE_COLLECTING_ISUPPORTS
75 NS_DECL_CYCLE_COLLECTION_CLASS(TextServicesDocument
)
78 * Initializes the text services document to use a particular editor. The
79 * text services document will use the DOM document and presentation shell
82 * @param aEditor The editor to use.
84 nsresult
InitWithEditor(nsIEditor
* aEditor
);
87 * Sets the range/extent over which the text services document will iterate.
88 * Note that InitWithEditor() should have been called prior to calling this
89 * method. If this method is never called, the text services defaults to
90 * iterating over the entire document.
92 * @param aDOMRange The range to use. aDOMRange must point to a
95 nsresult
SetExtent(nsRange
* aRange
);
98 * Expands the end points of the range so that it spans complete words. This
99 * call does not change any internal state of the text services document.
101 * @param aDOMRange The range to be expanded/adjusted.
103 nsresult
ExpandRangeToWordBoundaries(nsRange
* aRange
);
106 * Sets the filter type to be used while iterating over content.
107 * This will clear the current filter type if it's not either
108 * FILTERTYPE_NORMAL or FILTERTYPE_MAIL.
110 * @param aFilterType The filter type to be used while iterating over
113 nsresult
SetFilterType(uint32_t aFilterType
);
116 * Returns the text in the current text block.
118 * @param aStr [OUT] This will contain the text.
120 nsresult
GetCurrentTextBlock(nsString
* aStr
);
123 * Tells the document to point to the first text block in the document. This
124 * method does not adjust the current cursor position or selection.
126 nsresult
FirstBlock();
128 enum class BlockSelectionStatus
{
129 // There is no text block (TB) in or before the selection (S).
131 // No TB in S, but found one before/after S.
133 // S extends beyond the start and end of TB.
135 // TB contains entire S.
137 // S begins or ends in TB but extends outside of TB.
142 * Tells the document to point to the last text block that contains the
143 * current selection or caret.
145 * @param aSelectionStatus [OUT] This will contain the text block
147 * @param aSelectionOffset [OUT] This will contain the offset into the
148 * string returned by GetCurrentTextBlock() where
149 * the selection begins.
150 * @param aLength [OUT] This will contain the number of
151 * characters that are selected in the string.
153 nsresult
LastSelectedBlock(BlockSelectionStatus
* aSelStatus
,
154 int32_t* aSelOffset
, int32_t* aSelLength
);
157 * Tells the document to point to the text block before the current one.
158 * This method will return NS_OK, even if there is no previous block.
159 * Callers should call IsDone() to check if we have gone beyond the first
160 * text block in the document.
162 nsresult
PrevBlock();
165 * Tells the document to point to the text block after the current one.
166 * This method will return NS_OK, even if there is no next block. Callers
167 * should call IsDone() to check if we have gone beyond the last text block
170 nsresult
NextBlock();
173 * IsDone() will always set aIsDone == false unless the document contains
174 * no text, PrevBlock() was called while the document was already pointing
175 * to the first text block in the document, or NextBlock() was called while
176 * the document was already pointing to the last text block in the document.
178 * @param aIsDone [OUT] This will contain the result.
180 nsresult
IsDone(bool* aIsDone
);
183 * SetSelection() allows the caller to set the selection based on an offset
184 * into the string returned by GetCurrentTextBlock(). A length of zero
185 * places the cursor at that offset. A positive non-zero length "n" selects
186 * n characters in the string.
188 * @param aOffset Offset into string returned by
189 * GetCurrentTextBlock().
190 * @param aLength Number of characters selected.
192 nsresult
SetSelection(int32_t aOffset
, int32_t aLength
);
195 * Scrolls the document so that the current selection is visible.
197 nsresult
ScrollSelectionIntoView();
200 * Deletes the text selected by SetSelection(). Calling DeleteSelection()
201 * with nothing selected, or with a collapsed selection (cursor) does
202 * nothing and returns NS_OK.
204 nsresult
DeleteSelection();
207 * Inserts the given text at the current cursor position. If there is a
208 * selection, it will be deleted before the text is inserted.
210 nsresult
InsertText(const nsString
* aText
);
213 * nsIEditActionListener method implementations.
215 NS_DECL_NSIEDITACTIONLISTENER
218 * Actual edit action listeners. When you add new method here for listening
219 * to new edit action, you need to make it called by EditorBase.
220 * Additionally, you need to call it from proper method of
221 * nsIEditActionListener too because if this is created not for inline
222 * spell checker of the editor, edit actions will be notified via
223 * nsIEditActionListener (slow path, though).
225 void DidDeleteNode(nsINode
* aChild
);
226 void DidJoinNodes(nsINode
& aLeftNode
, nsINode
& aRightNode
);
228 static nsresult
GetRangeEndPoints(nsRange
* aRange
, nsINode
** aStartContainer
,
229 int32_t* aStartOffset
,
230 nsINode
** aEndContainer
,
231 int32_t* aEndOffset
);
234 nsresult
CreateFilteredContentIterator(
235 nsRange
* aRange
, FilteredContentIterator
** aFilteredIter
);
237 dom::Element
* GetDocumentContentRootNode() const;
238 already_AddRefed
<nsRange
> CreateDocumentContentRange();
239 already_AddRefed
<nsRange
> CreateDocumentContentRootToNodeOffsetRange(
240 nsINode
* aParent
, uint32_t aOffset
, bool aToStart
);
241 nsresult
CreateDocumentContentIterator(
242 FilteredContentIterator
** aFilteredIter
);
244 nsresult
AdjustContentIterator();
246 static nsresult
FirstTextNode(FilteredContentIterator
* aFilteredIter
,
247 IteratorStatus
* aIteratorStatus
);
248 static nsresult
LastTextNode(FilteredContentIterator
* aFilteredIter
,
249 IteratorStatus
* aIteratorStatus
);
251 static nsresult
FirstTextNodeInCurrentBlock(
252 FilteredContentIterator
* aFilteredIter
);
253 static nsresult
FirstTextNodeInPrevBlock(
254 FilteredContentIterator
* aFilteredIter
);
255 static nsresult
FirstTextNodeInNextBlock(
256 FilteredContentIterator
* aFilteredIter
);
258 nsresult
GetFirstTextNodeInPrevBlock(nsIContent
** aContent
);
259 nsresult
GetFirstTextNodeInNextBlock(nsIContent
** aContent
);
261 static bool IsBlockNode(nsIContent
* aContent
);
262 static bool IsTextNode(nsIContent
* aContent
);
264 static bool DidSkip(FilteredContentIterator
* aFilteredIter
);
265 static void ClearDidSkip(FilteredContentIterator
* aFilteredIter
);
267 static bool HasSameBlockNodeParent(nsIContent
* aContent1
,
268 nsIContent
* aContent2
);
270 nsresult
SetSelectionInternal(int32_t aOffset
, int32_t aLength
,
272 nsresult
GetSelection(BlockSelectionStatus
* aSelStatus
, int32_t* aSelOffset
,
273 int32_t* aSelLength
);
274 nsresult
GetCollapsedSelection(BlockSelectionStatus
* aSelStatus
,
275 int32_t* aSelOffset
, int32_t* aSelLength
);
276 nsresult
GetUncollapsedSelection(BlockSelectionStatus
* aSelStatus
,
277 int32_t* aSelOffset
, int32_t* aSelLength
);
279 bool SelectionIsCollapsed();
280 bool SelectionIsValid();
282 static nsresult
CreateOffsetTable(nsTArray
<OffsetEntry
*>* aOffsetTable
,
283 FilteredContentIterator
* aFilteredIter
,
284 IteratorStatus
* aIteratorStatus
,
285 nsRange
* aIterRange
, nsString
* aStr
);
286 static nsresult
ClearOffsetTable(nsTArray
<OffsetEntry
*>* aOffsetTable
);
288 static nsresult
NodeHasOffsetEntry(nsTArray
<OffsetEntry
*>* aOffsetTable
,
289 nsINode
* aNode
, bool* aHasEntry
,
290 int32_t* aEntryIndex
);
292 nsresult
RemoveInvalidOffsetEntries();
293 nsresult
SplitOffsetEntry(int32_t aTableIndex
, int32_t aOffsetIntoEntry
);
295 static nsresult
FindWordBounds(nsTArray
<OffsetEntry
*>* aOffsetTable
,
296 nsString
* aBlockStr
, nsINode
* aNode
,
297 int32_t aNodeOffset
, nsINode
** aWordStartNode
,
298 int32_t* aWordStartOffset
,
299 nsINode
** aWordEndNode
,
300 int32_t* aWordEndOffset
);
303 } // namespace mozilla
305 #endif // #ifndef mozilla_TextServicesDocument_h