Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
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_a11y_HyperTextAccessible_h__
7 #define mozilla_a11y_HyperTextAccessible_h__
9 #include "AccessibleWrap.h"
10 #include "nsIAccessibleTypes.h"
11 #include "xpcAccessibleHyperText.h"
13 #include "nsFrameSelection.h"
14 #include "nsISelectionController.h"
16 namespace mozilla {
17 namespace a11y {
19 class TextRange;
21 struct DOMPoint {
22 DOMPoint() : node(nullptr), idx(0) { }
23 DOMPoint(nsINode* aNode, int32_t aIdx) : node(aNode), idx(aIdx) { }
25 nsINode* node;
26 int32_t idx;
27 };
29 // This character marks where in the text returned via nsIAccessibleText(),
30 // that embedded object characters exist
31 const char16_t kEmbeddedObjectChar = 0xfffc;
32 const char16_t kImaginaryEmbeddedObjectChar = ' ';
33 const char16_t kForcedNewLineChar = '\n';
35 /**
36 * Special Accessible that knows how contain both text and embedded objects
37 */
38 class HyperTextAccessible : public AccessibleWrap,
39 public xpcAccessibleHyperText
40 {
41 public:
42 HyperTextAccessible(nsIContent* aContent, DocAccessible* aDoc);
43 virtual ~HyperTextAccessible() { }
45 NS_DECL_ISUPPORTS_INHERITED
47 // Accessible
48 virtual int32_t GetLevelInternal();
49 virtual already_AddRefed<nsIPersistentProperties> NativeAttributes() MOZ_OVERRIDE;
50 virtual mozilla::a11y::role NativeRole();
51 virtual uint64_t NativeState();
53 virtual void InvalidateChildren();
54 virtual bool RemoveChild(Accessible* aAccessible);
56 // HyperTextAccessible (static helper method)
58 // Convert content offset to rendered text offset
59 nsresult ContentToRenderedOffset(nsIFrame *aFrame, int32_t aContentOffset,
60 uint32_t *aRenderedOffset) const;
62 // Convert rendered text offset to content offset
63 nsresult RenderedToContentOffset(nsIFrame *aFrame, uint32_t aRenderedOffset,
64 int32_t *aContentOffset) const;
66 //////////////////////////////////////////////////////////////////////////////
67 // HyperLinkAccessible
69 /**
70 * Return link count within this hypertext accessible.
71 */
72 uint32_t LinkCount()
73 { return EmbeddedChildCount(); }
75 /**
76 * Return link accessible at the given index.
77 */
78 Accessible* LinkAt(uint32_t aIndex)
79 {
80 return GetEmbeddedChildAt(aIndex);
81 }
83 /**
84 * Return index for the given link accessible.
85 */
86 int32_t LinkIndexOf(Accessible* aLink)
87 {
88 return GetIndexOfEmbeddedChild(aLink);
89 }
91 /**
92 * Return link accessible at the given text offset.
93 */
94 int32_t LinkIndexAtOffset(uint32_t aOffset)
95 {
96 Accessible* child = GetChildAtOffset(aOffset);
97 return child ? LinkIndexOf(child) : -1;
98 }
100 //////////////////////////////////////////////////////////////////////////////
101 // HyperTextAccessible: DOM point to text offset conversions.
103 /**
104 * Turn a DOM point (node and offset) into a character offset of this
105 * hypertext. Will look for closest match when the DOM node does not have
106 * an accessible object associated with it. Will return an offset for the end
107 * of the string if the node is not found.
108 *
109 * @param aNode [in] the node to look for
110 * @param aNodeOffset [in] the offset to look for
111 * if -1 just look directly for the node
112 * if >=0 and aNode is text, this represents a char offset
113 * if >=0 and aNode is not text, this represents a child node offset
114 * @param aIsEndOffset [in] if true, then then this offset is not inclusive. The character
115 * indicated by the offset returned is at [offset - 1]. This means
116 * if the passed-in offset is really in a descendant, then the offset returned
117 * will come just after the relevant embedded object characer.
118 * If false, then the offset is inclusive. The character indicated
119 * by the offset returned is at [offset]. If the passed-in offset in inside a
120 * descendant, then the returned offset will be on the relevant embedded object char.
121 */
122 int32_t DOMPointToOffset(nsINode* aNode, int32_t aNodeOffset,
123 bool aIsEndOffset = false) const;
125 /**
126 * Transform the given a11y point into the offset relative this hypertext.
127 */
128 int32_t TransformOffset(Accessible* aDescendant, int32_t aOffset,
129 bool aIsEndOffset) const;
131 /**
132 * Convert start and end hypertext offsets into DOM range.
133 *
134 * @param aStartOffset [in] the given start hypertext offset
135 * @param aEndOffset [in] the given end hypertext offset
136 * @param aRange [in, out] the range whose bounds to set
137 * @return true if conversion was successful
138 */
139 bool OffsetsToDOMRange(int32_t aStartOffset, int32_t aEndOffset,
140 nsRange* aRange);
142 /**
143 * Convert the given offset into DOM point.
144 *
145 * If offset is at text leaf then DOM point is (text node, offsetInTextNode),
146 * if before embedded object then (parent node, indexInParent), if after then
147 * (parent node, indexInParent + 1).
148 */
149 DOMPoint OffsetToDOMPoint(int32_t aOffset);
151 /**
152 * Return true if the used ARIA role (if any) allows the hypertext accessible
153 * to expose text interfaces.
154 */
155 bool IsTextRole();
157 //////////////////////////////////////////////////////////////////////////////
158 // TextAccessible
160 /**
161 * Return character count within the hypertext accessible.
162 */
163 uint32_t CharacterCount() const
164 { return GetChildOffset(ChildCount()); }
166 /**
167 * Get a character at the given offset (don't support magic offsets).
168 */
169 bool CharAt(int32_t aOffset, nsAString& aChar,
170 int32_t* aStartOffset = nullptr, int32_t* aEndOffset = nullptr)
171 {
172 NS_ASSERTION(!aStartOffset == !aEndOffset,
173 "Offsets should be both defined or both undefined!");
175 int32_t childIdx = GetChildIndexAtOffset(aOffset);
176 if (childIdx == -1)
177 return false;
179 Accessible* child = GetChildAt(childIdx);
180 child->AppendTextTo(aChar, aOffset - GetChildOffset(childIdx), 1);
182 if (aStartOffset && aEndOffset) {
183 *aStartOffset = aOffset;
184 *aEndOffset = aOffset + aChar.Length();
185 }
186 return true;
187 }
189 char16_t CharAt(int32_t aOffset)
190 {
191 nsAutoString charAtOffset;
192 CharAt(aOffset, charAtOffset);
193 return charAtOffset.CharAt(0);
194 }
196 /**
197 * Return true if char at the given offset equals to given char.
198 */
199 bool IsCharAt(int32_t aOffset, char16_t aChar)
200 { return CharAt(aOffset) == aChar; }
202 /**
203 * Return true if terminal char is at the given offset.
204 */
205 bool IsLineEndCharAt(int32_t aOffset)
206 { return IsCharAt(aOffset, '\n'); }
208 /**
209 * Return text between given offsets.
210 */
211 void TextSubstring(int32_t aStartOffset, int32_t aEndOffset, nsAString& aText);
213 /**
214 * Return text before/at/after the given offset corresponding to
215 * the boundary type.
216 */
217 void TextBeforeOffset(int32_t aOffset, AccessibleTextBoundary aBoundaryType,
218 int32_t* aStartOffset, int32_t* aEndOffset,
219 nsAString& aText);
220 void TextAtOffset(int32_t aOffset, AccessibleTextBoundary aBoundaryType,
221 int32_t* aStartOffset, int32_t* aEndOffset,
222 nsAString& aText);
223 void TextAfterOffset(int32_t aOffset, AccessibleTextBoundary aBoundaryType,
224 int32_t* aStartOffset, int32_t* aEndOffset,
225 nsAString& aText);
227 /**
228 * Return text attributes for the given text range.
229 */
230 already_AddRefed<nsIPersistentProperties>
231 TextAttributes(bool aIncludeDefAttrs, int32_t aOffset,
232 int32_t* aStartOffset, int32_t* aEndOffset);
234 /**
235 * Return text attributes applied to the accessible.
236 */
237 already_AddRefed<nsIPersistentProperties> DefaultTextAttributes();
239 /**
240 * Return text offset of the given child accessible within hypertext
241 * accessible.
242 *
243 * @param aChild [in] accessible child to get text offset for
244 * @param aInvalidateAfter [in, optional] indicates whether invalidate
245 * cached offsets for next siblings of the child
246 */
247 int32_t GetChildOffset(Accessible* aChild,
248 bool aInvalidateAfter = false) const
249 {
250 int32_t index = GetIndexOf(aChild);
251 return index == -1 ? -1 : GetChildOffset(index, aInvalidateAfter);
252 }
254 /**
255 * Return text offset for the child accessible index.
256 */
257 int32_t GetChildOffset(uint32_t aChildIndex,
258 bool aInvalidateAfter = false) const;
260 /**
261 * Return child accessible at the given text offset.
262 *
263 * @param aOffset [in] the given text offset
264 */
265 int32_t GetChildIndexAtOffset(uint32_t aOffset) const;
267 /**
268 * Return child accessible at the given text offset.
269 *
270 * @param aOffset [in] the given text offset
271 */
272 Accessible* GetChildAtOffset(uint32_t aOffset) const
273 {
274 return GetChildAt(GetChildIndexAtOffset(aOffset));
275 }
277 /**
278 * Return true if the given offset/range is valid.
279 */
280 bool IsValidOffset(int32_t aOffset);
281 bool IsValidRange(int32_t aStartOffset, int32_t aEndOffset);
283 /**
284 * Return an offset at the given point.
285 */
286 int32_t OffsetAtPoint(int32_t aX, int32_t aY, uint32_t aCoordType);
288 /**
289 * Return a rect of the given text range relative given coordinate system.
290 */
291 nsIntRect TextBounds(int32_t aStartOffset, int32_t aEndOffset,
292 uint32_t aCoordType = nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE);
294 /**
295 * Return a rect for character at given offset relative given coordinate
296 * system.
297 */
298 nsIntRect CharBounds(int32_t aOffset, uint32_t aCoordType)
299 { return TextBounds(aOffset, aOffset + 1, aCoordType); }
301 /**
302 * Get/set caret offset, if no caret then -1.
303 */
304 int32_t CaretOffset() const;
305 void SetCaretOffset(int32_t aOffset) { SetSelectionRange(aOffset, aOffset); }
307 /**
308 * Provide the line number for the caret.
309 * @return 1-based index for the line number with the caret
310 */
311 int32_t CaretLineNumber();
313 /**
314 * Return the caret rect and the widget containing the caret within this
315 * text accessible.
316 *
317 * @param [out] the widget containing the caret
318 * @return the caret rect
319 */
320 nsIntRect GetCaretRect(nsIWidget** aWidget);
322 /**
323 * Return selected regions count within the accessible.
324 */
325 int32_t SelectionCount();
327 /**
328 * Return the start and end offset of the specified selection.
329 */
330 bool SelectionBoundsAt(int32_t aSelectionNum,
331 int32_t* aStartOffset, int32_t* aEndOffset);
333 /*
334 * Changes the start and end offset of the specified selection.
335 * @return true if succeeded
336 */
337 bool SetSelectionBoundsAt(int32_t aSelectionNum,
338 int32_t aStartOffset, int32_t aEndOffset);
340 /**
341 * Adds a selection bounded by the specified offsets.
342 * @return true if succeeded
343 */
344 bool AddToSelection(int32_t aStartOffset, int32_t aEndOffset);
346 /*
347 * Removes the specified selection.
348 * @return true if succeeded
349 */
350 bool RemoveFromSelection(int32_t aSelectionNum);
352 /**
353 * Scroll the given text range into view.
354 */
355 void ScrollSubstringTo(int32_t aStartOffset, int32_t aEndOffset,
356 uint32_t aScrollType);
358 /**
359 * Scroll the given text range to the given point.
360 */
361 void ScrollSubstringToPoint(int32_t aStartOffset,
362 int32_t aEndOffset,
363 uint32_t aCoordinateType,
364 int32_t aX, int32_t aY);
366 /**
367 * Return a range that encloses the text control or the document this
368 * accessible belongs to.
369 */
370 void EnclosingRange(TextRange& aRange) const;
372 /**
373 * Return an array of disjoint ranges for selected text within the text control
374 * or the document this accessible belongs to.
375 */
376 void SelectionRanges(nsTArray<TextRange>* aRanges) const;
378 /**
379 * Return an array of disjoint ranges of visible text within the text control
380 * or the document this accessible belongs to.
381 */
382 void VisibleRanges(nsTArray<TextRange>* aRanges) const;
384 /**
385 * Return a range containing the given accessible.
386 */
387 void RangeByChild(Accessible* aChild, TextRange& aRange) const;
389 /**
390 * Return a range containing an accessible at the given point.
391 */
392 void RangeAtPoint(int32_t aX, int32_t aY, TextRange& aRange) const;
394 //////////////////////////////////////////////////////////////////////////////
395 // EditableTextAccessible
397 void ReplaceText(const nsAString& aText);
398 void InsertText(const nsAString& aText, int32_t aPosition);
399 void CopyText(int32_t aStartPos, int32_t aEndPos);
400 void CutText(int32_t aStartPos, int32_t aEndPos);
401 void DeleteText(int32_t aStartPos, int32_t aEndPos);
402 void PasteText(int32_t aPosition);
404 /**
405 * Return the editor associated with the accessible.
406 */
407 virtual already_AddRefed<nsIEditor> GetEditor() const;
409 protected:
410 // Accessible
411 virtual ENameValueFlag NativeName(nsString& aName) MOZ_OVERRIDE;
412 virtual void CacheChildren() MOZ_OVERRIDE;
414 // HyperTextAccessible
416 /**
417 * Transform magic offset into text offset.
418 */
419 int32_t ConvertMagicOffset(int32_t aOffset);
421 /**
422 * Adjust an offset the caret stays at to get a text by line boundary.
423 */
424 int32_t AdjustCaretOffset(int32_t aOffset) const;
426 /**
427 * Return true if caret is at end of line.
428 */
429 bool IsCaretAtEndOfLine() const;
431 /**
432 * Return true if the given offset points to terminal empty line if any.
433 */
434 bool IsEmptyLastLineOffset(int32_t aOffset)
435 {
436 return aOffset == static_cast<int32_t>(CharacterCount()) &&
437 IsLineEndCharAt(aOffset - 1);
438 }
440 /**
441 * Return an offset of the found word boundary.
442 */
443 int32_t FindWordBoundary(int32_t aOffset, nsDirection aDirection,
444 EWordMovementType aWordMovementType)
445 {
446 return FindOffset(aOffset, aDirection, eSelectWord, aWordMovementType);
447 }
449 /**
450 * Used to get begin/end of previous/this/next line. Note: end of line
451 * is an offset right before '\n' character if any, the offset is right after
452 * '\n' character is begin of line. In case of wrap word breaks these offsets
453 * are equal.
454 */
455 enum EWhichLineBoundary {
456 ePrevLineBegin,
457 ePrevLineEnd,
458 eThisLineBegin,
459 eThisLineEnd,
460 eNextLineBegin,
461 eNextLineEnd
462 };
464 /**
465 * Return an offset for requested line boundary. See constants above.
466 */
467 int32_t FindLineBoundary(int32_t aOffset,
468 EWhichLineBoundary aWhichLineBoundary);
470 /**
471 * Return an offset corresponding to the given direction and selection amount
472 * relative the given offset. A helper used to find word or line boundaries.
473 */
474 int32_t FindOffset(int32_t aOffset, nsDirection aDirection,
475 nsSelectionAmount aAmount,
476 EWordMovementType aWordMovementType = eDefaultBehavior);
478 /**
479 * Return the boundaries of the substring in case of textual frame or
480 * frame boundaries in case of non textual frame, offsets are ignored.
481 */
482 nsIntRect GetBoundsInFrame(nsIFrame* aFrame,
483 uint32_t aStartRenderedOffset,
484 uint32_t aEndRenderedOffset);
486 // Selection helpers
488 /**
489 * Return frame/DOM selection object for the accessible.
490 */
491 already_AddRefed<nsFrameSelection> FrameSelection() const;
492 dom::Selection* DOMSelection() const;
494 /**
495 * Return selection ranges within the accessible subtree.
496 */
497 void GetSelectionDOMRanges(int16_t aType, nsTArray<nsRange*>* aRanges);
499 nsresult SetSelectionRange(int32_t aStartPos, int32_t aEndPos);
501 // Helpers
502 nsresult GetDOMPointByFrameOffset(nsIFrame* aFrame, int32_t aOffset,
503 Accessible* aAccessible,
504 mozilla::a11y::DOMPoint* aPoint);
506 /**
507 * Set 'misspelled' text attribute and return range offsets where the
508 * attibute is stretched. If the text is not misspelled at the given offset
509 * then we expose only range offsets where text is not misspelled. The method
510 * is used by TextAttributes() method.
511 *
512 * @param aIncludeDefAttrs [in] points whether text attributes having default
513 * values of attributes should be included
514 * @param aSourceNode [in] the node we start to traverse from
515 * @param aStartOffset [in, out] the start offset
516 * @param aEndOffset [in, out] the end offset
517 * @param aAttributes [out, optional] result attributes
518 */
519 nsresult GetSpellTextAttribute(nsINode* aNode, int32_t aNodeOffset,
520 int32_t *aStartOffset,
521 int32_t *aEndOffset,
522 nsIPersistentProperties *aAttributes);
524 private:
525 /**
526 * End text offsets array.
527 */
528 mutable nsTArray<uint32_t> mOffsets;
529 };
532 ////////////////////////////////////////////////////////////////////////////////
533 // Accessible downcasting method
535 inline HyperTextAccessible*
536 Accessible::AsHyperText()
537 {
538 return IsHyperText() ? static_cast<HyperTextAccessible*>(this) : nullptr;
539 }
541 } // namespace a11y
542 } // namespace mozilla
544 #endif