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