1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef mozilla_a11y_TextLeafRange_h__
8 #define mozilla_a11y_TextLeafRange_h__
12 #include "AccAttributes.h"
13 #include "nsDirection.h"
14 #include "nsIAccessibleText.h"
24 class LocalAccessible
;
27 * Represents a point within accessible text.
28 * This is stored as a leaf Accessible and an offset into that Accessible.
29 * For an empty Accessible, the offset will always be 0.
30 * This will eventually replace TextPoint. Unlike TextPoint, this does not
31 * use HyperTextAccessible offsets.
33 class TextLeafPoint final
{
35 TextLeafPoint(Accessible
* aAcc
, int32_t aOffset
);
38 * Constructs an invalid TextPoint (mAcc is null).
39 * A TextLeafPoint in this state will evaluate to false.
40 * mAcc can be set later. Alternatively, this can be used to indicate an error
41 * (e.g. if a requested point couldn't be found).
43 TextLeafPoint() : mAcc(nullptr), mOffset(0) {}
46 * Construct a TextLeafPoint representing the caret.
48 static TextLeafPoint
GetCaret(Accessible
* aAcc
);
54 * True if this point is the insertion point at the end of a line. This is the
55 * point where the caret is positioned when pressing the end key, for example.
56 * On the very last line, mOffset will be equal to the length of the text.
57 * However, where text wraps across lines, this line end insertion point
58 * doesn't have its own offset, so mOffset will be the offset for the first
59 * character on the next line. This is where this flag becomes important.
60 * Otherwise, for example, commanding a screen reader to read the current line
61 * would read the next line instead of the current line in this case.
63 bool mIsEndOfLineInsertionPoint
= false;
65 bool operator==(const TextLeafPoint
& aPoint
) const {
66 return mAcc
== aPoint
.mAcc
&& mOffset
== aPoint
.mOffset
;
69 bool operator!=(const TextLeafPoint
& aPoint
) const {
70 return !(*this == aPoint
);
73 bool operator<(const TextLeafPoint
& aPoint
) const;
75 bool operator<=(const TextLeafPoint
& aPoint
) const;
78 * A valid TextLeafPoint evaluates to true. An invalid TextLeafPoint
81 explicit operator bool() const { return !!mAcc
; }
83 enum class BoundaryFlags
: uint32_t {
84 eDefaultBoundaryFlags
= 0,
85 // Return point unchanged if it is at the given boundary type.
86 eIncludeOrigin
= 1 << 0,
87 // If current point is in editable, return point within samme editable.
88 eStopInEditable
= 1 << 1,
89 // Skip over list items in searches and don't consider them line or
91 eIgnoreListItemMarker
= 1 << 2,
95 * Find a boundary (word start, line start, etc.) in a specific direction.
96 * If no boundary is found, the start/end of the document is returned
97 * (depending on the direction).
99 TextLeafPoint
FindBoundary(
100 AccessibleTextBoundary aBoundaryType
, nsDirection aDirection
,
101 BoundaryFlags aFlags
= BoundaryFlags::eDefaultBoundaryFlags
) const;
104 * These two functions find a line start boundary within the same
105 * LocalAccessible as this. That is, they do not cross Accessibles. If no
106 * boundary is found, an invalid TextLeafPoint is returned.
107 * These are used by FindBoundary. Most callers will want FindBoundary
110 TextLeafPoint
FindPrevLineStartSameLocalAcc(bool aIncludeOrigin
) const;
111 TextLeafPoint
FindNextLineStartSameLocalAcc(bool aIncludeOrigin
) const;
114 * These two functions find a word start boundary within the same
115 * Accessible as this. That is, they do not cross Accessibles. If no
116 * boundary is found, an invalid TextLeafPoint is returned.
117 * These are used by FindBoundary. Most callers will want FindBoundary
120 TextLeafPoint
FindPrevWordStartSameAcc(bool aIncludeOrigin
) const;
121 TextLeafPoint
FindNextWordStartSameAcc(bool aIncludeOrigin
) const;
124 * Get the text attributes at this point.
125 * If aIncludeDefaults is true, default attributes on the HyperTextAccessible
128 already_AddRefed
<AccAttributes
> GetTextAttributes(
129 bool aIncludeDefaults
= true) const;
132 * Get Get the text attributes at this point in a LocalAccessible.
133 * This is used by GetTextAttributes. Most callers will want GetTextAttributes
136 already_AddRefed
<AccAttributes
> GetTextAttributesLocalAcc(
137 bool aIncludeDefaults
= true) const;
140 * Get all the attributes that apply to offset ranges in a given text leaf
141 * LocalAccessible. This should only be used when pushing the cache. Most
142 * callers will want FindTextAttrsStart instead.
144 static nsTArray
<TextOffsetAttribute
> GetTextOffsetAttributes(
145 LocalAccessible
* aAcc
);
148 * Queue a cache update for text offset attributes in a given DOM range.
150 static void UpdateCachedTextOffsetAttributes(
151 dom::Document
* aDocument
, const dom::AbstractRange
& aRange
);
154 * Find the start of a run of text attributes in a specific direction.
155 * A text attributes run is a span of text where the attributes are the same.
156 * If no boundary is found, the start/end of the container is returned
157 * (depending on the direction).
158 * If aIncludeorigin is true and this is at a boundary, this will be
159 * returned unchanged.
161 TextLeafPoint
FindTextAttrsStart(nsDirection aDirection
,
162 bool aIncludeOrigin
= false) const;
165 * Returns a rect (in dev pixels) describing position and size of
166 * the character at mOffset in mAcc. This rect is screen-relative.
167 * This function only works on remote accessibles, and assumes caching
170 LayoutDeviceIntRect
CharBounds();
173 * Returns true if the given point (in screen coords) is contained
174 * in the char bounds of the current TextLeafPoint. Returns false otherwise.
175 * If the current point is an empty container, we use the acc's bounds instead
176 * of char bounds. Because this depends on CharBounds, this function only
177 * works on remote accessibles, and assumes caching is enabled.
179 bool ContainsPoint(int32_t aX
, int32_t aY
);
181 bool IsLineFeedChar() const { return GetChar() == '\n'; }
183 bool IsSpace() const;
185 bool IsParagraphStart(bool aIgnoreListItemMarker
= false) const {
186 return mOffset
== 0 &&
187 FindParagraphSameAcc(eDirPrevious
, true, aIgnoreListItemMarker
);
191 * Translate given TextLeafPoint into a DOM point.
193 MOZ_CAN_RUN_SCRIPT
std::pair
<nsIContent
*, int32_t> ToDOMPoint(
194 bool aIncludeGenerated
= true) const;
198 * If this is the insertion point at the end of a line, return an adjusted
199 * point such that word and line boundaries can be calculated correctly.
201 TextLeafPoint
AdjustEndOfLine() const;
203 bool IsEmptyLastLine() const;
205 bool IsDocEdge(nsDirection aDirection
) const;
207 bool IsLeafAfterListItemMarker() const;
209 char16_t
GetChar() const;
211 TextLeafPoint
FindLineStartSameRemoteAcc(nsDirection aDirection
,
212 bool aIncludeOrigin
) const;
215 * Helper which just calls the appropriate function based on whether mAcc
218 TextLeafPoint
FindLineStartSameAcc(nsDirection aDirection
,
220 bool aIgnoreListItemMarker
= false) const;
222 TextLeafPoint
FindLineEnd(nsDirection aDirection
, BoundaryFlags aFlags
) const;
223 TextLeafPoint
FindWordEnd(nsDirection aDirection
, BoundaryFlags aFlags
) const;
225 TextLeafPoint
FindParagraphSameAcc(nsDirection aDirection
,
227 bool aIgnoreListItemMarker
= false) const;
229 TextLeafPoint
FindClusterSameAcc(nsDirection aDirection
,
230 bool aIncludeOrigin
) const;
232 void AddTextOffsetAttributes(AccAttributes
* aAttrs
) const;
235 * Find a text offset attribute boundary in the same Accessible. This function
236 * searches for either start or end points, since either means a change in
237 * text attributes. This only considers attributes such as spelling errors
238 * which are mapped to DOM selections. Most callers will want
239 * FindTextAttrsStart instead.
241 TextLeafPoint
FindTextOffsetAttributeSameAcc(nsDirection aDirection
,
242 bool aIncludeOrigin
) const;
244 // Return the point immediately succeeding or preceding this leaf depending
245 // on given direction.
246 TextLeafPoint
NeighborLeafPoint(nsDirection aDirection
, bool aIsEditable
,
247 bool aIgnoreListItemMarker
) const;
250 * This function assumes mAcc is a LocalAccessible.
251 * It iterates the continuations of mAcc's primary frame until it locates
252 * the continuation containing mOffset (a rendered offset). It then uses
253 * GetScreenRectInAppUnits to compute screen coords for the frame, resizing
254 * such that the resulting rect contains only one character.
256 LayoutDeviceIntRect
ComputeBoundsFromFrame() const;
259 MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(TextLeafPoint::BoundaryFlags
)
262 * Represents a range of accessible text.
263 * This will eventually replace TextRange.
265 class TextLeafRange final
{
267 TextLeafRange(const TextLeafPoint
& aStart
, const TextLeafPoint
& aEnd
)
268 : mStart(aStart
), mEnd(aEnd
) {}
269 explicit TextLeafRange(const TextLeafPoint
& aStart
)
270 : mStart(aStart
), mEnd(aStart
) {}
271 explicit TextLeafRange() {}
274 * A valid TextLeafRange evaluates to true. An invalid TextLeafRange
275 * evaluates to false.
277 explicit operator bool() const { return !!mStart
&& !!mEnd
; }
279 bool operator!=(const TextLeafRange
& aOther
) const {
280 return mEnd
!= aOther
.mEnd
|| mStart
!= aOther
.mStart
;
283 bool operator==(const TextLeafRange
& aOther
) const {
284 return mEnd
== aOther
.mEnd
&& mStart
== aOther
.mStart
;
287 TextLeafPoint
Start() const { return mStart
; }
288 void SetStart(const TextLeafPoint
& aStart
) { mStart
= aStart
; }
289 TextLeafPoint
End() const { return mEnd
; }
290 void SetEnd(const TextLeafPoint
& aEnd
) { mEnd
= aEnd
; }
292 bool Crop(Accessible
* aContainer
);
295 * Returns a union rect (in dev pixels) of all character bounds in this range.
296 * This rect is screen-relative and inclusive of mEnd. This function only
297 * works on remote accessibles, and assumes caching is enabled.
299 LayoutDeviceIntRect
Bounds() const;
302 * Get the ranges of text that are selected within this Accessible. The caret
303 * is not included as a collapsed range.
305 static void GetSelection(Accessible
* aAcc
, nsTArray
<TextLeafRange
>& aRanges
);
308 * Set range as DOM selection.
309 * aSelectionNum is the selection index to use. If aSelectionNum is
310 * out of bounds for current selection ranges, or is -1, a new selection
313 MOZ_CAN_RUN_SCRIPT
bool SetSelection(int32_t aSelectionNum
) const;
315 MOZ_CAN_RUN_SCRIPT
void ScrollIntoView(uint32_t aScrollType
) const;
318 TextLeafPoint mStart
;
323 * A TextLeafRange iterator will iterate through single leaf segments of the
329 Iterator(Iterator
&& aOther
)
330 : mRange(aOther
.mRange
),
331 mSegmentStart(aOther
.mSegmentStart
),
332 mSegmentEnd(aOther
.mSegmentEnd
) {}
334 static Iterator
BeginIterator(const TextLeafRange
& aRange
);
336 static Iterator
EndIterator(const TextLeafRange
& aRange
);
338 Iterator
& operator++();
340 bool operator!=(const Iterator
& aOther
) const {
341 return mRange
!= aOther
.mRange
|| mSegmentStart
!= aOther
.mSegmentStart
||
342 mSegmentEnd
!= aOther
.mSegmentEnd
;
345 TextLeafRange
operator*() {
346 return TextLeafRange(mSegmentStart
, mSegmentEnd
);
350 explicit Iterator(const TextLeafRange
& aRange
) : mRange(aRange
) {}
353 Iterator(const Iterator
&) = delete;
354 Iterator
& operator=(const Iterator
&) = delete;
355 Iterator
& operator=(const Iterator
&&) = delete;
357 const TextLeafRange
& mRange
;
358 TextLeafPoint mSegmentStart
;
359 TextLeafPoint mSegmentEnd
;
362 Iterator
begin() const { return Iterator::BeginIterator(*this); }
363 Iterator
end() const { return Iterator::EndIterator(*this); }
367 } // namespace mozilla