Line data Source code
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 : #include "TextRange-inl.h"
8 :
9 : #include "Accessible-inl.h"
10 : #include "nsAccUtils.h"
11 :
12 : namespace mozilla {
13 : namespace a11y {
14 :
15 : ////////////////////////////////////////////////////////////////////////////////
16 : // TextPoint
17 :
18 : bool
19 0 : TextPoint::operator <(const TextPoint& aPoint) const
20 : {
21 0 : if (mContainer == aPoint.mContainer)
22 0 : return mOffset < aPoint.mOffset;
23 :
24 : // Build the chain of parents
25 0 : Accessible* p1 = mContainer;
26 0 : Accessible* p2 = aPoint.mContainer;
27 0 : AutoTArray<Accessible*, 30> parents1, parents2;
28 0 : do {
29 0 : parents1.AppendElement(p1);
30 0 : p1 = p1->Parent();
31 0 : } while (p1);
32 0 : do {
33 0 : parents2.AppendElement(p2);
34 0 : p2 = p2->Parent();
35 0 : } while (p2);
36 :
37 : // Find where the parent chain differs
38 0 : uint32_t pos1 = parents1.Length(), pos2 = parents2.Length();
39 0 : for (uint32_t len = std::min(pos1, pos2); len > 0; --len) {
40 0 : Accessible* child1 = parents1.ElementAt(--pos1);
41 0 : Accessible* child2 = parents2.ElementAt(--pos2);
42 0 : if (child1 != child2)
43 0 : return child1->IndexInParent() < child2->IndexInParent();
44 : }
45 :
46 0 : NS_ERROR("Broken tree?!");
47 0 : return false;
48 : }
49 :
50 : ////////////////////////////////////////////////////////////////////////////////
51 : // TextRange
52 :
53 0 : TextRange::TextRange(HyperTextAccessible* aRoot,
54 : HyperTextAccessible* aStartContainer, int32_t aStartOffset,
55 0 : HyperTextAccessible* aEndContainer, int32_t aEndOffset) :
56 : mRoot(aRoot), mStartContainer(aStartContainer), mEndContainer(aEndContainer),
57 0 : mStartOffset(aStartOffset), mEndOffset(aEndOffset)
58 : {
59 0 : }
60 :
61 : void
62 0 : TextRange::EmbeddedChildren(nsTArray<Accessible*>* aChildren) const
63 : {
64 0 : if (mStartContainer == mEndContainer) {
65 0 : int32_t startIdx = mStartContainer->GetChildIndexAtOffset(mStartOffset);
66 0 : int32_t endIdx = mStartContainer->GetChildIndexAtOffset(mEndOffset);
67 0 : for (int32_t idx = startIdx; idx <= endIdx; idx++) {
68 0 : Accessible* child = mStartContainer->GetChildAt(idx);
69 0 : if (!child->IsText()) {
70 0 : aChildren->AppendElement(child);
71 : }
72 : }
73 0 : return;
74 : }
75 :
76 0 : Accessible* p1 = mStartContainer->GetChildAtOffset(mStartOffset);
77 0 : Accessible* p2 = mEndContainer->GetChildAtOffset(mEndOffset);
78 :
79 0 : uint32_t pos1 = 0, pos2 = 0;
80 0 : AutoTArray<Accessible*, 30> parents1, parents2;
81 : Accessible* container =
82 0 : CommonParent(p1, p2, &parents1, &pos1, &parents2, &pos2);
83 :
84 : // Traverse the tree up to the container and collect embedded objects.
85 0 : for (uint32_t idx = 0; idx < pos1 - 1; idx++) {
86 0 : Accessible* parent = parents1[idx + 1];
87 0 : Accessible* child = parents1[idx];
88 0 : uint32_t childCount = parent->ChildCount();
89 0 : for (uint32_t childIdx = child->IndexInParent(); childIdx < childCount; childIdx++) {
90 0 : Accessible* next = parent->GetChildAt(childIdx);
91 0 : if (!next->IsText()) {
92 0 : aChildren->AppendElement(next);
93 : }
94 : }
95 : }
96 :
97 : // Traverse through direct children in the container.
98 0 : int32_t endIdx = parents2[pos2 - 1]->IndexInParent();
99 0 : int32_t childIdx = parents1[pos1 - 1]->IndexInParent() + 1;
100 0 : for (; childIdx < endIdx; childIdx++) {
101 0 : Accessible* next = container->GetChildAt(childIdx);
102 0 : if (!next->IsText()) {
103 0 : aChildren->AppendElement(next);
104 : }
105 : }
106 :
107 : // Traverse down from the container to end point.
108 0 : for (int32_t idx = pos2 - 2; idx > 0; idx--) {
109 0 : Accessible* parent = parents2[idx];
110 0 : Accessible* child = parents2[idx - 1];
111 0 : int32_t endIdx = child->IndexInParent();
112 0 : for (int32_t childIdx = 0; childIdx < endIdx; childIdx++) {
113 0 : Accessible* next = parent->GetChildAt(childIdx);
114 0 : if (!next->IsText()) {
115 0 : aChildren->AppendElement(next);
116 : }
117 : }
118 : }
119 : }
120 :
121 : void
122 0 : TextRange::Text(nsAString& aText) const
123 : {
124 0 : Accessible* current = mStartContainer->GetChildAtOffset(mStartOffset);
125 : uint32_t startIntlOffset =
126 0 : mStartOffset - mStartContainer->GetChildOffset(current);
127 :
128 0 : while (current && TextInternal(aText, current, startIntlOffset)) {
129 0 : current = current->Parent();
130 0 : if (!current)
131 0 : break;
132 :
133 0 : current = current->NextSibling();
134 : }
135 0 : }
136 :
137 : void
138 0 : TextRange::Bounds(nsTArray<nsIntRect> aRects) const
139 : {
140 :
141 0 : }
142 :
143 : void
144 0 : TextRange::Normalize(ETextUnit aUnit)
145 : {
146 :
147 0 : }
148 :
149 : bool
150 0 : TextRange::Crop(Accessible* aContainer)
151 : {
152 0 : uint32_t boundaryPos = 0, containerPos = 0;
153 0 : AutoTArray<Accessible*, 30> boundaryParents, containerParents;
154 :
155 : // Crop the start boundary.
156 0 : Accessible* container = nullptr;
157 0 : Accessible* boundary = mStartContainer->GetChildAtOffset(mStartOffset);
158 0 : if (boundary != aContainer) {
159 : CommonParent(boundary, aContainer, &boundaryParents, &boundaryPos,
160 0 : &containerParents, &containerPos);
161 :
162 0 : if (boundaryPos == 0) {
163 0 : if (containerPos != 0) {
164 : // The container is contained by the start boundary, reduce the range to
165 : // the point starting at the container.
166 0 : aContainer->ToTextPoint(mStartContainer.StartAssignment(), &mStartOffset);
167 0 : static_cast<Accessible*>(mStartContainer)->AddRef();
168 : }
169 : else {
170 : // The start boundary and the container are siblings.
171 0 : container = aContainer;
172 : }
173 : }
174 0 : else if (containerPos != 0) {
175 : // The container does not contain the start boundary.
176 0 : boundary = boundaryParents[boundaryPos];
177 0 : container = containerParents[containerPos];
178 : }
179 :
180 0 : if (container) {
181 : // If the range start is after the container, then make the range invalid.
182 0 : if (boundary->IndexInParent() > container->IndexInParent()) {
183 0 : return !!(mRoot = nullptr);
184 : }
185 :
186 : // If the range starts before the container, then reduce the range to
187 : // the point starting at the container.
188 0 : if (boundary->IndexInParent() < container->IndexInParent()) {
189 0 : container->ToTextPoint(mStartContainer.StartAssignment(), &mStartOffset);
190 0 : mStartContainer.get()->AddRef();
191 : }
192 : }
193 :
194 0 : boundaryParents.SetLengthAndRetainStorage(0);
195 0 : containerParents.SetLengthAndRetainStorage(0);
196 : }
197 :
198 0 : boundary = mEndContainer->GetChildAtOffset(mEndOffset);
199 0 : if (boundary == aContainer) {
200 0 : return true;
201 : }
202 :
203 : // Crop the end boundary.
204 0 : container = nullptr;
205 : CommonParent(boundary, aContainer, &boundaryParents, &boundaryPos,
206 0 : &containerParents, &containerPos);
207 :
208 0 : if (boundaryPos == 0) {
209 0 : if (containerPos != 0) {
210 0 : aContainer->ToTextPoint(mEndContainer.StartAssignment(), &mEndOffset, false);
211 0 : static_cast<Accessible*>(mEndContainer)->AddRef();
212 : }
213 : else {
214 0 : container = aContainer;
215 : }
216 : }
217 0 : else if (containerPos != 0) {
218 0 : boundary = boundaryParents[boundaryPos];
219 0 : container = containerParents[containerPos];
220 : }
221 :
222 0 : if (!container) {
223 0 : return true;
224 : }
225 :
226 0 : if (boundary->IndexInParent() < container->IndexInParent()) {
227 0 : return !!(mRoot = nullptr);
228 : }
229 :
230 0 : if (boundary->IndexInParent() > container->IndexInParent()) {
231 0 : container->ToTextPoint(mEndContainer.StartAssignment(), &mEndOffset, false);
232 0 : static_cast<Accessible*>(mEndContainer)->AddRef();
233 : }
234 :
235 0 : return true;
236 : }
237 :
238 : void
239 0 : TextRange::FindText(const nsAString& aText, EDirection aDirection,
240 : nsCaseTreatment aCaseSensitive, TextRange* aFoundRange) const
241 : {
242 :
243 0 : }
244 :
245 : void
246 0 : TextRange::FindAttr(EAttr aAttr, nsIVariant* aValue, EDirection aDirection,
247 : TextRange* aFoundRange) const
248 : {
249 :
250 0 : }
251 :
252 : void
253 0 : TextRange::AddToSelection() const
254 : {
255 :
256 0 : }
257 :
258 : void
259 0 : TextRange::RemoveFromSelection() const
260 : {
261 :
262 0 : }
263 :
264 : void
265 0 : TextRange::Select() const
266 : {
267 0 : }
268 :
269 : void
270 0 : TextRange::ScrollIntoView(EHowToAlign aHow) const
271 : {
272 :
273 0 : }
274 :
275 : ////////////////////////////////////////////////////////////////////////////////
276 : // pivate
277 :
278 : void
279 0 : TextRange::Set(HyperTextAccessible* aRoot,
280 : HyperTextAccessible* aStartContainer, int32_t aStartOffset,
281 : HyperTextAccessible* aEndContainer, int32_t aEndOffset)
282 : {
283 0 : mRoot = aRoot;
284 0 : mStartContainer = aStartContainer;
285 0 : mEndContainer = aEndContainer;
286 0 : mStartOffset = aStartOffset;
287 0 : mEndOffset = aEndOffset;
288 0 : }
289 :
290 : bool
291 0 : TextRange::TextInternal(nsAString& aText, Accessible* aCurrent,
292 : uint32_t aStartIntlOffset) const
293 : {
294 0 : bool moveNext = true;
295 0 : int32_t endIntlOffset = -1;
296 0 : if (aCurrent->Parent() == mEndContainer &&
297 0 : mEndContainer->GetChildAtOffset(mEndOffset) == aCurrent) {
298 :
299 0 : uint32_t currentStartOffset = mEndContainer->GetChildOffset(aCurrent);
300 0 : endIntlOffset = mEndOffset - currentStartOffset;
301 0 : if (endIntlOffset == 0)
302 0 : return false;
303 :
304 0 : moveNext = false;
305 : }
306 :
307 0 : if (aCurrent->IsTextLeaf()) {
308 0 : aCurrent->AppendTextTo(aText, aStartIntlOffset,
309 0 : endIntlOffset - aStartIntlOffset);
310 0 : if (!moveNext)
311 0 : return false;
312 : }
313 :
314 0 : Accessible* next = aCurrent->FirstChild();
315 0 : if (next) {
316 0 : if (!TextInternal(aText, next, 0))
317 0 : return false;
318 : }
319 :
320 0 : next = aCurrent->NextSibling();
321 0 : if (next) {
322 0 : if (!TextInternal(aText, next, 0))
323 0 : return false;
324 : }
325 :
326 0 : return moveNext;
327 : }
328 :
329 :
330 : void
331 0 : TextRange::MoveInternal(ETextUnit aUnit, int32_t aCount,
332 : HyperTextAccessible& aContainer, int32_t aOffset,
333 : HyperTextAccessible* aStopContainer, int32_t aStopOffset)
334 : {
335 :
336 0 : }
337 :
338 : Accessible*
339 0 : TextRange::CommonParent(Accessible* aAcc1, Accessible* aAcc2,
340 : nsTArray<Accessible*>* aParents1, uint32_t* aPos1,
341 : nsTArray<Accessible*>* aParents2, uint32_t* aPos2) const
342 : {
343 0 : if (aAcc1 == aAcc2) {
344 0 : return aAcc1;
345 : }
346 :
347 0 : MOZ_ASSERT(aParents1->Length() == 0 || aParents2->Length() == 0,
348 : "Wrong arguments");
349 :
350 : // Build the chain of parents.
351 0 : Accessible* p1 = aAcc1;
352 0 : Accessible* p2 = aAcc2;
353 0 : do {
354 0 : aParents1->AppendElement(p1);
355 0 : p1 = p1->Parent();
356 0 : } while (p1);
357 0 : do {
358 0 : aParents2->AppendElement(p2);
359 0 : p2 = p2->Parent();
360 0 : } while (p2);
361 :
362 : // Find where the parent chain differs
363 0 : *aPos1 = aParents1->Length();
364 0 : *aPos2 = aParents2->Length();
365 0 : Accessible* parent = nullptr;
366 0 : uint32_t len = 0;
367 0 : for (len = std::min(*aPos1, *aPos2); len > 0; --len) {
368 0 : Accessible* child1 = aParents1->ElementAt(--(*aPos1));
369 0 : Accessible* child2 = aParents2->ElementAt(--(*aPos2));
370 0 : if (child1 != child2)
371 0 : break;
372 :
373 0 : parent = child1;
374 : }
375 :
376 0 : return parent;
377 : }
378 :
379 : } // namespace a11y
380 : } // namespace mozilla
|