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