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/. */ 6 7 #ifndef mozilla_a11y_TextRange_h__ 8 #define mozilla_a11y_TextRange_h__ 9 10 #include <utility> 11 12 #include "nsCaseTreatment.h" 13 #include "nsRect.h" 14 #include "nsTArray.h" 15 16 class nsIVariant; 17 class nsRange; 18 19 namespace mozilla { 20 namespace dom { 21 class Selection; 22 } // namespace dom 23 namespace a11y { 24 25 class LocalAccessible; 26 class HyperTextAccessible; 27 28 /** 29 * A text point (hyper text + offset), represents a boundary of text range. 30 */ 31 struct TextPoint final { TextPointfinal32 TextPoint(HyperTextAccessible* aContainer, int32_t aOffset) 33 : mContainer(aContainer), mOffset(aOffset) {} TextPointfinal34 TextPoint(const TextPoint& aPoint) 35 : mContainer(aPoint.mContainer), mOffset(aPoint.mOffset) {} 36 37 HyperTextAccessible* mContainer; 38 int32_t mOffset; 39 40 bool operator==(const TextPoint& aPoint) const { 41 return mContainer == aPoint.mContainer && mOffset == aPoint.mOffset; 42 } 43 bool operator<(const TextPoint& aPoint) const; 44 }; 45 46 /** 47 * Represents a text range within the text control or document. 48 */ 49 class TextRange final { 50 public: 51 TextRange(HyperTextAccessible* aRoot, HyperTextAccessible* aStartContainer, 52 int32_t aStartOffset, HyperTextAccessible* aEndContainer, 53 int32_t aEndOffset); TextRange()54 TextRange() : mStartOffset{0}, mEndOffset{0} {} TextRange(TextRange && aRange)55 TextRange(TextRange&& aRange) 56 : mRoot(std::move(aRange.mRoot)), 57 mStartContainer(std::move(aRange.mStartContainer)), 58 mEndContainer(std::move(aRange.mEndContainer)), 59 mStartOffset(aRange.mStartOffset), 60 mEndOffset(aRange.mEndOffset) {} 61 62 TextRange& operator=(TextRange&& aRange) { 63 mRoot = std::move(aRange.mRoot); 64 mStartContainer = std::move(aRange.mStartContainer); 65 mEndContainer = std::move(aRange.mEndContainer); 66 mStartOffset = aRange.mStartOffset; 67 mEndOffset = aRange.mEndOffset; 68 return *this; 69 } 70 StartContainer()71 HyperTextAccessible* StartContainer() const { return mStartContainer; } StartOffset()72 int32_t StartOffset() const { return mStartOffset; } EndContainer()73 HyperTextAccessible* EndContainer() const { return mEndContainer; } EndOffset()74 int32_t EndOffset() const { return mEndOffset; } 75 76 bool operator==(const TextRange& aRange) const { 77 return mStartContainer == aRange.mStartContainer && 78 mStartOffset == aRange.mStartOffset && 79 mEndContainer == aRange.mEndContainer && 80 mEndOffset == aRange.mEndOffset; 81 } 82 StartPoint()83 TextPoint StartPoint() const { 84 return TextPoint(mStartContainer, mStartOffset); 85 } EndPoint()86 TextPoint EndPoint() const { return TextPoint(mEndContainer, mEndOffset); } 87 88 /** 89 * Return a container containing both start and end points. 90 */ 91 LocalAccessible* Container() const; 92 93 /** 94 * Return a list of embedded objects enclosed by the text range (includes 95 * partially overlapped objects). 96 */ 97 void EmbeddedChildren(nsTArray<LocalAccessible*>* aChildren) const; 98 99 /** 100 * Return text enclosed by the range. 101 */ 102 void Text(nsAString& aText) const; 103 104 /** 105 * Return list of bounding rects of the text range by lines. 106 */ 107 void Bounds(nsTArray<nsIntRect> aRects) const; 108 109 enum ETextUnit { eFormat, eWord, eLine, eParagraph, ePage, eDocument }; 110 111 /** 112 * Move the range or its points on specified amount of given units. 113 */ Move(ETextUnit aUnit,int32_t aCount)114 void Move(ETextUnit aUnit, int32_t aCount) { 115 MoveEnd(aUnit, aCount); 116 MoveStart(aUnit, aCount); 117 } MoveStart(ETextUnit aUnit,int32_t aCount)118 void MoveStart(ETextUnit aUnit, int32_t aCount) { 119 MoveInternal(aUnit, aCount, *mStartContainer, mStartOffset, mEndContainer, 120 mEndOffset); 121 } MoveEnd(ETextUnit aUnit,int32_t aCount)122 void MoveEnd(ETextUnit aUnit, int32_t aCount) { 123 MoveInternal(aUnit, aCount, *mEndContainer, mEndOffset); 124 } 125 126 /** 127 * Move the range points to the closest unit boundaries. 128 */ 129 void Normalize(ETextUnit aUnit); 130 131 /** 132 * Crops the range if it overlaps the given accessible element boundaries, 133 * returns true if the range was cropped successfully. 134 */ 135 bool Crop(LocalAccessible* aContainer); 136 137 enum EDirection { eBackward, eForward }; 138 139 /** 140 * Return range enclosing the found text. 141 */ 142 void FindText(const nsAString& aText, EDirection aDirection, 143 nsCaseTreatment aCaseSensitive, TextRange* aFoundRange) const; 144 145 enum EAttr { 146 eAnimationStyleAttr, 147 eAnnotationObjectsAttr, 148 eAnnotationTypesAttr, 149 eBackgroundColorAttr, 150 eBulletStyleAttr, 151 eCapStyleAttr, 152 eCaretBidiModeAttr, 153 eCaretPositionAttr, 154 eCultureAttr, 155 eFontNameAttr, 156 eFontSizeAttr, 157 eFontWeightAttr, 158 eForegroundColorAttr, 159 eHorizontalTextAlignmentAttr, 160 eIndentationFirstLineAttr, 161 eIndentationLeadingAttr, 162 eIndentationTrailingAttr, 163 eIsActiveAttr, 164 eIsHiddenAttr, 165 eIsItalicAttr, 166 eIsReadOnlyAttr, 167 eIsSubscriptAttr, 168 eIsSuperscriptAttr, 169 eLinkAttr, 170 eMarginBottomAttr, 171 eMarginLeadingAttr, 172 eMarginTopAttr, 173 eMarginTrailingAttr, 174 eOutlineStylesAttr, 175 eOverlineColorAttr, 176 eOverlineStyleAttr, 177 eSelectionActiveEndAttr, 178 eStrikethroughColorAttr, 179 eStrikethroughStyleAttr, 180 eStyleIdAttr, 181 eStyleNameAttr, 182 eTabsAttr, 183 eTextFlowDirectionsAttr, 184 eUnderlineColorAttr, 185 eUnderlineStyleAttr 186 }; 187 188 /** 189 * Return range enclosing text having requested attribute. 190 */ 191 void FindAttr(EAttr aAttr, nsIVariant* aValue, EDirection aDirection, 192 TextRange* aFoundRange) const; 193 194 /** 195 * Add/remove the text range from selection. 196 */ 197 void AddToSelection() const; 198 void RemoveFromSelection() const; 199 MOZ_CAN_RUN_SCRIPT bool SetSelectionAt(int32_t aSelectionNum) const; 200 201 /** 202 * Scroll the text range into view. 203 */ 204 void ScrollIntoView(uint32_t aScrollType) const; 205 206 /** 207 * Convert stored hypertext offsets into DOM offsets and assign it to DOM 208 * range. 209 * 210 * Note that if start and/or end accessible offsets are in generated content 211 * such as ::before or 212 * ::after, the result range excludes the generated content. See also 213 * ClosestNotGeneratedDOMPoint() for more information. 214 * 215 * @param aRange [in, out] the range whose bounds to set 216 * @param aReversed [out] whether the start/end offsets were reversed. 217 * @return true if conversion was successful 218 */ 219 bool AssignDOMRange(nsRange* aRange, bool* aReversed = nullptr) const; 220 221 /** 222 * Return true if this TextRange object represents an actual range of text. 223 */ IsValid()224 bool IsValid() const { return mRoot; } 225 SetStartPoint(HyperTextAccessible * aContainer,int32_t aOffset)226 void SetStartPoint(HyperTextAccessible* aContainer, int32_t aOffset) { 227 mStartContainer = aContainer; 228 mStartOffset = aOffset; 229 } SetEndPoint(HyperTextAccessible * aContainer,int32_t aOffset)230 void SetEndPoint(HyperTextAccessible* aContainer, int32_t aOffset) { 231 mStartContainer = aContainer; 232 mStartOffset = aOffset; 233 } 234 235 static void TextRangesFromSelection(dom::Selection* aSelection, 236 nsTArray<TextRange>* aRanges); 237 238 private: 239 TextRange(const TextRange& aRange) = delete; 240 TextRange& operator=(const TextRange& aRange) = delete; 241 242 friend class HyperTextAccessible; 243 friend class xpcAccessibleTextRange; 244 245 void Set(HyperTextAccessible* aRoot, HyperTextAccessible* aStartContainer, 246 int32_t aStartOffset, HyperTextAccessible* aEndContainer, 247 int32_t aEndOffset); 248 249 /** 250 * Text() method helper. 251 * @param aText [in,out] calculated text 252 * @param aCurrent [in] currently traversed node 253 * @param aStartIntlOffset [in] start offset if current node is a text node 254 * @return true if calculation is not finished yet 255 */ 256 bool TextInternal(nsAString& aText, LocalAccessible* aCurrent, 257 uint32_t aStartIntlOffset) const; 258 259 void MoveInternal(ETextUnit aUnit, int32_t aCount, 260 HyperTextAccessible& aContainer, int32_t aOffset, 261 HyperTextAccessible* aStopContainer = nullptr, 262 int32_t aStopOffset = 0); 263 264 /** 265 * A helper method returning a common parent for two given accessible 266 * elements. 267 */ 268 LocalAccessible* CommonParent(LocalAccessible* aAcc1, LocalAccessible* aAcc2, 269 nsTArray<LocalAccessible*>* aParents1, 270 uint32_t* aPos1, 271 nsTArray<LocalAccessible*>* aParents2, 272 uint32_t* aPos2) const; 273 274 RefPtr<HyperTextAccessible> mRoot; 275 RefPtr<HyperTextAccessible> mStartContainer; 276 RefPtr<HyperTextAccessible> mEndContainer; 277 int32_t mStartOffset; 278 int32_t mEndOffset; 279 }; 280 281 } // namespace a11y 282 } // namespace mozilla 283 284 #endif 285