1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/accessible/src/generic/HyperTextAccessible.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,545 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#ifndef mozilla_a11y_HyperTextAccessible_h__ 1.10 +#define mozilla_a11y_HyperTextAccessible_h__ 1.11 + 1.12 +#include "AccessibleWrap.h" 1.13 +#include "nsIAccessibleTypes.h" 1.14 +#include "xpcAccessibleHyperText.h" 1.15 + 1.16 +#include "nsFrameSelection.h" 1.17 +#include "nsISelectionController.h" 1.18 + 1.19 +namespace mozilla { 1.20 +namespace a11y { 1.21 + 1.22 +class TextRange; 1.23 + 1.24 +struct DOMPoint { 1.25 + DOMPoint() : node(nullptr), idx(0) { } 1.26 + DOMPoint(nsINode* aNode, int32_t aIdx) : node(aNode), idx(aIdx) { } 1.27 + 1.28 + nsINode* node; 1.29 + int32_t idx; 1.30 +}; 1.31 + 1.32 +// This character marks where in the text returned via nsIAccessibleText(), 1.33 +// that embedded object characters exist 1.34 +const char16_t kEmbeddedObjectChar = 0xfffc; 1.35 +const char16_t kImaginaryEmbeddedObjectChar = ' '; 1.36 +const char16_t kForcedNewLineChar = '\n'; 1.37 + 1.38 +/** 1.39 + * Special Accessible that knows how contain both text and embedded objects 1.40 + */ 1.41 +class HyperTextAccessible : public AccessibleWrap, 1.42 + public xpcAccessibleHyperText 1.43 +{ 1.44 +public: 1.45 + HyperTextAccessible(nsIContent* aContent, DocAccessible* aDoc); 1.46 + virtual ~HyperTextAccessible() { } 1.47 + 1.48 + NS_DECL_ISUPPORTS_INHERITED 1.49 + 1.50 + // Accessible 1.51 + virtual int32_t GetLevelInternal(); 1.52 + virtual already_AddRefed<nsIPersistentProperties> NativeAttributes() MOZ_OVERRIDE; 1.53 + virtual mozilla::a11y::role NativeRole(); 1.54 + virtual uint64_t NativeState(); 1.55 + 1.56 + virtual void InvalidateChildren(); 1.57 + virtual bool RemoveChild(Accessible* aAccessible); 1.58 + 1.59 + // HyperTextAccessible (static helper method) 1.60 + 1.61 + // Convert content offset to rendered text offset 1.62 + nsresult ContentToRenderedOffset(nsIFrame *aFrame, int32_t aContentOffset, 1.63 + uint32_t *aRenderedOffset) const; 1.64 + 1.65 + // Convert rendered text offset to content offset 1.66 + nsresult RenderedToContentOffset(nsIFrame *aFrame, uint32_t aRenderedOffset, 1.67 + int32_t *aContentOffset) const; 1.68 + 1.69 + ////////////////////////////////////////////////////////////////////////////// 1.70 + // HyperLinkAccessible 1.71 + 1.72 + /** 1.73 + * Return link count within this hypertext accessible. 1.74 + */ 1.75 + uint32_t LinkCount() 1.76 + { return EmbeddedChildCount(); } 1.77 + 1.78 + /** 1.79 + * Return link accessible at the given index. 1.80 + */ 1.81 + Accessible* LinkAt(uint32_t aIndex) 1.82 + { 1.83 + return GetEmbeddedChildAt(aIndex); 1.84 + } 1.85 + 1.86 + /** 1.87 + * Return index for the given link accessible. 1.88 + */ 1.89 + int32_t LinkIndexOf(Accessible* aLink) 1.90 + { 1.91 + return GetIndexOfEmbeddedChild(aLink); 1.92 + } 1.93 + 1.94 + /** 1.95 + * Return link accessible at the given text offset. 1.96 + */ 1.97 + int32_t LinkIndexAtOffset(uint32_t aOffset) 1.98 + { 1.99 + Accessible* child = GetChildAtOffset(aOffset); 1.100 + return child ? LinkIndexOf(child) : -1; 1.101 + } 1.102 + 1.103 + ////////////////////////////////////////////////////////////////////////////// 1.104 + // HyperTextAccessible: DOM point to text offset conversions. 1.105 + 1.106 + /** 1.107 + * Turn a DOM point (node and offset) into a character offset of this 1.108 + * hypertext. Will look for closest match when the DOM node does not have 1.109 + * an accessible object associated with it. Will return an offset for the end 1.110 + * of the string if the node is not found. 1.111 + * 1.112 + * @param aNode [in] the node to look for 1.113 + * @param aNodeOffset [in] the offset to look for 1.114 + * if -1 just look directly for the node 1.115 + * if >=0 and aNode is text, this represents a char offset 1.116 + * if >=0 and aNode is not text, this represents a child node offset 1.117 + * @param aIsEndOffset [in] if true, then then this offset is not inclusive. The character 1.118 + * indicated by the offset returned is at [offset - 1]. This means 1.119 + * if the passed-in offset is really in a descendant, then the offset returned 1.120 + * will come just after the relevant embedded object characer. 1.121 + * If false, then the offset is inclusive. The character indicated 1.122 + * by the offset returned is at [offset]. If the passed-in offset in inside a 1.123 + * descendant, then the returned offset will be on the relevant embedded object char. 1.124 + */ 1.125 + int32_t DOMPointToOffset(nsINode* aNode, int32_t aNodeOffset, 1.126 + bool aIsEndOffset = false) const; 1.127 + 1.128 + /** 1.129 + * Transform the given a11y point into the offset relative this hypertext. 1.130 + */ 1.131 + int32_t TransformOffset(Accessible* aDescendant, int32_t aOffset, 1.132 + bool aIsEndOffset) const; 1.133 + 1.134 + /** 1.135 + * Convert start and end hypertext offsets into DOM range. 1.136 + * 1.137 + * @param aStartOffset [in] the given start hypertext offset 1.138 + * @param aEndOffset [in] the given end hypertext offset 1.139 + * @param aRange [in, out] the range whose bounds to set 1.140 + * @return true if conversion was successful 1.141 + */ 1.142 + bool OffsetsToDOMRange(int32_t aStartOffset, int32_t aEndOffset, 1.143 + nsRange* aRange); 1.144 + 1.145 + /** 1.146 + * Convert the given offset into DOM point. 1.147 + * 1.148 + * If offset is at text leaf then DOM point is (text node, offsetInTextNode), 1.149 + * if before embedded object then (parent node, indexInParent), if after then 1.150 + * (parent node, indexInParent + 1). 1.151 + */ 1.152 + DOMPoint OffsetToDOMPoint(int32_t aOffset); 1.153 + 1.154 + /** 1.155 + * Return true if the used ARIA role (if any) allows the hypertext accessible 1.156 + * to expose text interfaces. 1.157 + */ 1.158 + bool IsTextRole(); 1.159 + 1.160 + ////////////////////////////////////////////////////////////////////////////// 1.161 + // TextAccessible 1.162 + 1.163 + /** 1.164 + * Return character count within the hypertext accessible. 1.165 + */ 1.166 + uint32_t CharacterCount() const 1.167 + { return GetChildOffset(ChildCount()); } 1.168 + 1.169 + /** 1.170 + * Get a character at the given offset (don't support magic offsets). 1.171 + */ 1.172 + bool CharAt(int32_t aOffset, nsAString& aChar, 1.173 + int32_t* aStartOffset = nullptr, int32_t* aEndOffset = nullptr) 1.174 + { 1.175 + NS_ASSERTION(!aStartOffset == !aEndOffset, 1.176 + "Offsets should be both defined or both undefined!"); 1.177 + 1.178 + int32_t childIdx = GetChildIndexAtOffset(aOffset); 1.179 + if (childIdx == -1) 1.180 + return false; 1.181 + 1.182 + Accessible* child = GetChildAt(childIdx); 1.183 + child->AppendTextTo(aChar, aOffset - GetChildOffset(childIdx), 1); 1.184 + 1.185 + if (aStartOffset && aEndOffset) { 1.186 + *aStartOffset = aOffset; 1.187 + *aEndOffset = aOffset + aChar.Length(); 1.188 + } 1.189 + return true; 1.190 + } 1.191 + 1.192 + char16_t CharAt(int32_t aOffset) 1.193 + { 1.194 + nsAutoString charAtOffset; 1.195 + CharAt(aOffset, charAtOffset); 1.196 + return charAtOffset.CharAt(0); 1.197 + } 1.198 + 1.199 + /** 1.200 + * Return true if char at the given offset equals to given char. 1.201 + */ 1.202 + bool IsCharAt(int32_t aOffset, char16_t aChar) 1.203 + { return CharAt(aOffset) == aChar; } 1.204 + 1.205 + /** 1.206 + * Return true if terminal char is at the given offset. 1.207 + */ 1.208 + bool IsLineEndCharAt(int32_t aOffset) 1.209 + { return IsCharAt(aOffset, '\n'); } 1.210 + 1.211 + /** 1.212 + * Return text between given offsets. 1.213 + */ 1.214 + void TextSubstring(int32_t aStartOffset, int32_t aEndOffset, nsAString& aText); 1.215 + 1.216 + /** 1.217 + * Return text before/at/after the given offset corresponding to 1.218 + * the boundary type. 1.219 + */ 1.220 + void TextBeforeOffset(int32_t aOffset, AccessibleTextBoundary aBoundaryType, 1.221 + int32_t* aStartOffset, int32_t* aEndOffset, 1.222 + nsAString& aText); 1.223 + void TextAtOffset(int32_t aOffset, AccessibleTextBoundary aBoundaryType, 1.224 + int32_t* aStartOffset, int32_t* aEndOffset, 1.225 + nsAString& aText); 1.226 + void TextAfterOffset(int32_t aOffset, AccessibleTextBoundary aBoundaryType, 1.227 + int32_t* aStartOffset, int32_t* aEndOffset, 1.228 + nsAString& aText); 1.229 + 1.230 + /** 1.231 + * Return text attributes for the given text range. 1.232 + */ 1.233 + already_AddRefed<nsIPersistentProperties> 1.234 + TextAttributes(bool aIncludeDefAttrs, int32_t aOffset, 1.235 + int32_t* aStartOffset, int32_t* aEndOffset); 1.236 + 1.237 + /** 1.238 + * Return text attributes applied to the accessible. 1.239 + */ 1.240 + already_AddRefed<nsIPersistentProperties> DefaultTextAttributes(); 1.241 + 1.242 + /** 1.243 + * Return text offset of the given child accessible within hypertext 1.244 + * accessible. 1.245 + * 1.246 + * @param aChild [in] accessible child to get text offset for 1.247 + * @param aInvalidateAfter [in, optional] indicates whether invalidate 1.248 + * cached offsets for next siblings of the child 1.249 + */ 1.250 + int32_t GetChildOffset(Accessible* aChild, 1.251 + bool aInvalidateAfter = false) const 1.252 + { 1.253 + int32_t index = GetIndexOf(aChild); 1.254 + return index == -1 ? -1 : GetChildOffset(index, aInvalidateAfter); 1.255 + } 1.256 + 1.257 + /** 1.258 + * Return text offset for the child accessible index. 1.259 + */ 1.260 + int32_t GetChildOffset(uint32_t aChildIndex, 1.261 + bool aInvalidateAfter = false) const; 1.262 + 1.263 + /** 1.264 + * Return child accessible at the given text offset. 1.265 + * 1.266 + * @param aOffset [in] the given text offset 1.267 + */ 1.268 + int32_t GetChildIndexAtOffset(uint32_t aOffset) const; 1.269 + 1.270 + /** 1.271 + * Return child accessible at the given text offset. 1.272 + * 1.273 + * @param aOffset [in] the given text offset 1.274 + */ 1.275 + Accessible* GetChildAtOffset(uint32_t aOffset) const 1.276 + { 1.277 + return GetChildAt(GetChildIndexAtOffset(aOffset)); 1.278 + } 1.279 + 1.280 + /** 1.281 + * Return true if the given offset/range is valid. 1.282 + */ 1.283 + bool IsValidOffset(int32_t aOffset); 1.284 + bool IsValidRange(int32_t aStartOffset, int32_t aEndOffset); 1.285 + 1.286 + /** 1.287 + * Return an offset at the given point. 1.288 + */ 1.289 + int32_t OffsetAtPoint(int32_t aX, int32_t aY, uint32_t aCoordType); 1.290 + 1.291 + /** 1.292 + * Return a rect of the given text range relative given coordinate system. 1.293 + */ 1.294 + nsIntRect TextBounds(int32_t aStartOffset, int32_t aEndOffset, 1.295 + uint32_t aCoordType = nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE); 1.296 + 1.297 + /** 1.298 + * Return a rect for character at given offset relative given coordinate 1.299 + * system. 1.300 + */ 1.301 + nsIntRect CharBounds(int32_t aOffset, uint32_t aCoordType) 1.302 + { return TextBounds(aOffset, aOffset + 1, aCoordType); } 1.303 + 1.304 + /** 1.305 + * Get/set caret offset, if no caret then -1. 1.306 + */ 1.307 + int32_t CaretOffset() const; 1.308 + void SetCaretOffset(int32_t aOffset) { SetSelectionRange(aOffset, aOffset); } 1.309 + 1.310 + /** 1.311 + * Provide the line number for the caret. 1.312 + * @return 1-based index for the line number with the caret 1.313 + */ 1.314 + int32_t CaretLineNumber(); 1.315 + 1.316 + /** 1.317 + * Return the caret rect and the widget containing the caret within this 1.318 + * text accessible. 1.319 + * 1.320 + * @param [out] the widget containing the caret 1.321 + * @return the caret rect 1.322 + */ 1.323 + nsIntRect GetCaretRect(nsIWidget** aWidget); 1.324 + 1.325 + /** 1.326 + * Return selected regions count within the accessible. 1.327 + */ 1.328 + int32_t SelectionCount(); 1.329 + 1.330 + /** 1.331 + * Return the start and end offset of the specified selection. 1.332 + */ 1.333 + bool SelectionBoundsAt(int32_t aSelectionNum, 1.334 + int32_t* aStartOffset, int32_t* aEndOffset); 1.335 + 1.336 + /* 1.337 + * Changes the start and end offset of the specified selection. 1.338 + * @return true if succeeded 1.339 + */ 1.340 + bool SetSelectionBoundsAt(int32_t aSelectionNum, 1.341 + int32_t aStartOffset, int32_t aEndOffset); 1.342 + 1.343 + /** 1.344 + * Adds a selection bounded by the specified offsets. 1.345 + * @return true if succeeded 1.346 + */ 1.347 + bool AddToSelection(int32_t aStartOffset, int32_t aEndOffset); 1.348 + 1.349 + /* 1.350 + * Removes the specified selection. 1.351 + * @return true if succeeded 1.352 + */ 1.353 + bool RemoveFromSelection(int32_t aSelectionNum); 1.354 + 1.355 + /** 1.356 + * Scroll the given text range into view. 1.357 + */ 1.358 + void ScrollSubstringTo(int32_t aStartOffset, int32_t aEndOffset, 1.359 + uint32_t aScrollType); 1.360 + 1.361 + /** 1.362 + * Scroll the given text range to the given point. 1.363 + */ 1.364 + void ScrollSubstringToPoint(int32_t aStartOffset, 1.365 + int32_t aEndOffset, 1.366 + uint32_t aCoordinateType, 1.367 + int32_t aX, int32_t aY); 1.368 + 1.369 + /** 1.370 + * Return a range that encloses the text control or the document this 1.371 + * accessible belongs to. 1.372 + */ 1.373 + void EnclosingRange(TextRange& aRange) const; 1.374 + 1.375 + /** 1.376 + * Return an array of disjoint ranges for selected text within the text control 1.377 + * or the document this accessible belongs to. 1.378 + */ 1.379 + void SelectionRanges(nsTArray<TextRange>* aRanges) const; 1.380 + 1.381 + /** 1.382 + * Return an array of disjoint ranges of visible text within the text control 1.383 + * or the document this accessible belongs to. 1.384 + */ 1.385 + void VisibleRanges(nsTArray<TextRange>* aRanges) const; 1.386 + 1.387 + /** 1.388 + * Return a range containing the given accessible. 1.389 + */ 1.390 + void RangeByChild(Accessible* aChild, TextRange& aRange) const; 1.391 + 1.392 + /** 1.393 + * Return a range containing an accessible at the given point. 1.394 + */ 1.395 + void RangeAtPoint(int32_t aX, int32_t aY, TextRange& aRange) const; 1.396 + 1.397 + ////////////////////////////////////////////////////////////////////////////// 1.398 + // EditableTextAccessible 1.399 + 1.400 + void ReplaceText(const nsAString& aText); 1.401 + void InsertText(const nsAString& aText, int32_t aPosition); 1.402 + void CopyText(int32_t aStartPos, int32_t aEndPos); 1.403 + void CutText(int32_t aStartPos, int32_t aEndPos); 1.404 + void DeleteText(int32_t aStartPos, int32_t aEndPos); 1.405 + void PasteText(int32_t aPosition); 1.406 + 1.407 + /** 1.408 + * Return the editor associated with the accessible. 1.409 + */ 1.410 + virtual already_AddRefed<nsIEditor> GetEditor() const; 1.411 + 1.412 +protected: 1.413 + // Accessible 1.414 + virtual ENameValueFlag NativeName(nsString& aName) MOZ_OVERRIDE; 1.415 + virtual void CacheChildren() MOZ_OVERRIDE; 1.416 + 1.417 + // HyperTextAccessible 1.418 + 1.419 + /** 1.420 + * Transform magic offset into text offset. 1.421 + */ 1.422 + int32_t ConvertMagicOffset(int32_t aOffset); 1.423 + 1.424 + /** 1.425 + * Adjust an offset the caret stays at to get a text by line boundary. 1.426 + */ 1.427 + int32_t AdjustCaretOffset(int32_t aOffset) const; 1.428 + 1.429 + /** 1.430 + * Return true if caret is at end of line. 1.431 + */ 1.432 + bool IsCaretAtEndOfLine() const; 1.433 + 1.434 + /** 1.435 + * Return true if the given offset points to terminal empty line if any. 1.436 + */ 1.437 + bool IsEmptyLastLineOffset(int32_t aOffset) 1.438 + { 1.439 + return aOffset == static_cast<int32_t>(CharacterCount()) && 1.440 + IsLineEndCharAt(aOffset - 1); 1.441 + } 1.442 + 1.443 + /** 1.444 + * Return an offset of the found word boundary. 1.445 + */ 1.446 + int32_t FindWordBoundary(int32_t aOffset, nsDirection aDirection, 1.447 + EWordMovementType aWordMovementType) 1.448 + { 1.449 + return FindOffset(aOffset, aDirection, eSelectWord, aWordMovementType); 1.450 + } 1.451 + 1.452 + /** 1.453 + * Used to get begin/end of previous/this/next line. Note: end of line 1.454 + * is an offset right before '\n' character if any, the offset is right after 1.455 + * '\n' character is begin of line. In case of wrap word breaks these offsets 1.456 + * are equal. 1.457 + */ 1.458 + enum EWhichLineBoundary { 1.459 + ePrevLineBegin, 1.460 + ePrevLineEnd, 1.461 + eThisLineBegin, 1.462 + eThisLineEnd, 1.463 + eNextLineBegin, 1.464 + eNextLineEnd 1.465 + }; 1.466 + 1.467 + /** 1.468 + * Return an offset for requested line boundary. See constants above. 1.469 + */ 1.470 + int32_t FindLineBoundary(int32_t aOffset, 1.471 + EWhichLineBoundary aWhichLineBoundary); 1.472 + 1.473 + /** 1.474 + * Return an offset corresponding to the given direction and selection amount 1.475 + * relative the given offset. A helper used to find word or line boundaries. 1.476 + */ 1.477 + int32_t FindOffset(int32_t aOffset, nsDirection aDirection, 1.478 + nsSelectionAmount aAmount, 1.479 + EWordMovementType aWordMovementType = eDefaultBehavior); 1.480 + 1.481 + /** 1.482 + * Return the boundaries of the substring in case of textual frame or 1.483 + * frame boundaries in case of non textual frame, offsets are ignored. 1.484 + */ 1.485 + nsIntRect GetBoundsInFrame(nsIFrame* aFrame, 1.486 + uint32_t aStartRenderedOffset, 1.487 + uint32_t aEndRenderedOffset); 1.488 + 1.489 + // Selection helpers 1.490 + 1.491 + /** 1.492 + * Return frame/DOM selection object for the accessible. 1.493 + */ 1.494 + already_AddRefed<nsFrameSelection> FrameSelection() const; 1.495 + dom::Selection* DOMSelection() const; 1.496 + 1.497 + /** 1.498 + * Return selection ranges within the accessible subtree. 1.499 + */ 1.500 + void GetSelectionDOMRanges(int16_t aType, nsTArray<nsRange*>* aRanges); 1.501 + 1.502 + nsresult SetSelectionRange(int32_t aStartPos, int32_t aEndPos); 1.503 + 1.504 + // Helpers 1.505 + nsresult GetDOMPointByFrameOffset(nsIFrame* aFrame, int32_t aOffset, 1.506 + Accessible* aAccessible, 1.507 + mozilla::a11y::DOMPoint* aPoint); 1.508 + 1.509 + /** 1.510 + * Set 'misspelled' text attribute and return range offsets where the 1.511 + * attibute is stretched. If the text is not misspelled at the given offset 1.512 + * then we expose only range offsets where text is not misspelled. The method 1.513 + * is used by TextAttributes() method. 1.514 + * 1.515 + * @param aIncludeDefAttrs [in] points whether text attributes having default 1.516 + * values of attributes should be included 1.517 + * @param aSourceNode [in] the node we start to traverse from 1.518 + * @param aStartOffset [in, out] the start offset 1.519 + * @param aEndOffset [in, out] the end offset 1.520 + * @param aAttributes [out, optional] result attributes 1.521 + */ 1.522 + nsresult GetSpellTextAttribute(nsINode* aNode, int32_t aNodeOffset, 1.523 + int32_t *aStartOffset, 1.524 + int32_t *aEndOffset, 1.525 + nsIPersistentProperties *aAttributes); 1.526 + 1.527 +private: 1.528 + /** 1.529 + * End text offsets array. 1.530 + */ 1.531 + mutable nsTArray<uint32_t> mOffsets; 1.532 +}; 1.533 + 1.534 + 1.535 +//////////////////////////////////////////////////////////////////////////////// 1.536 +// Accessible downcasting method 1.537 + 1.538 +inline HyperTextAccessible* 1.539 +Accessible::AsHyperText() 1.540 +{ 1.541 + return IsHyperText() ? static_cast<HyperTextAccessible*>(this) : nullptr; 1.542 +} 1.543 + 1.544 +} // namespace a11y 1.545 +} // namespace mozilla 1.546 + 1.547 +#endif 1.548 +