Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/accessible/base/TextRange.cpp
Line
Count
Source (jump to first uncovered line)
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
TextPoint::operator <(const TextPoint& aPoint) const
20
0
{
21
0
  if (mContainer == aPoint.mContainer)
22
0
    return mOffset < aPoint.mOffset;
23
0
24
0
  // 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
0
37
0
  // 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
0
  }
45
0
46
0
  NS_ERROR("Broken tree?!");
47
0
  return false;
48
0
}
49
50
////////////////////////////////////////////////////////////////////////////////
51
// TextRange
52
53
TextRange::TextRange(HyperTextAccessible* aRoot,
54
                     HyperTextAccessible* aStartContainer, int32_t aStartOffset,
55
                     HyperTextAccessible* aEndContainer, int32_t aEndOffset) :
56
  mRoot(aRoot), mStartContainer(aStartContainer), mEndContainer(aEndContainer),
57
  mStartOffset(aStartOffset), mEndOffset(aEndOffset)
58
0
{
59
0
}
60
61
void
62
TextRange::EmbeddedChildren(nsTArray<Accessible*>* aChildren) const
63
0
{
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
0
      }
72
0
    }
73
0
    return;
74
0
  }
75
0
76
0
  Accessible* p1 = mStartContainer->GetChildAtOffset(mStartOffset);
77
0
  Accessible* p2 = mEndContainer->GetChildAtOffset(mEndOffset);
78
0
79
0
  uint32_t pos1 = 0, pos2 = 0;
80
0
  AutoTArray<Accessible*, 30> parents1, parents2;
81
0
  Accessible* container =
82
0
    CommonParent(p1, p2, &parents1, &pos1, &parents2, &pos2);
83
0
84
0
  // 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
0
      }
94
0
    }
95
0
  }
96
0
97
0
  // 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
0
    }
105
0
  }
106
0
107
0
  // 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
0
      }
117
0
    }
118
0
  }
119
0
}
120
121
void
122
TextRange::Text(nsAString& aText) const
123
0
{
124
0
  Accessible* current = mStartContainer->GetChildAtOffset(mStartOffset);
125
0
  uint32_t startIntlOffset =
126
0
    mStartOffset - mStartContainer->GetChildOffset(current);
127
0
128
0
  while (current && TextInternal(aText, current, startIntlOffset)) {
129
0
    current = current->Parent();
130
0
    if (!current)
131
0
      break;
132
0
133
0
    current = current->NextSibling();
134
0
  }
135
0
}
136
137
void
138
TextRange::Bounds(nsTArray<nsIntRect> aRects) const
139
0
{
140
0
141
0
}
142
143
void
144
TextRange::Normalize(ETextUnit aUnit)
145
0
{
146
0
147
0
}
148
149
bool
150
TextRange::Crop(Accessible* aContainer)
151
0
{
152
0
  uint32_t boundaryPos = 0, containerPos = 0;
153
0
  AutoTArray<Accessible*, 30> boundaryParents, containerParents;
154
0
155
0
  // Crop the start boundary.
156
0
  Accessible* container = nullptr;
157
0
  Accessible* boundary = mStartContainer->GetChildAtOffset(mStartOffset);
158
0
  if (boundary != aContainer) {
159
0
    CommonParent(boundary, aContainer, &boundaryParents, &boundaryPos,
160
0
                 &containerParents, &containerPos);
161
0
162
0
    if (boundaryPos == 0) {
163
0
      if (containerPos != 0) {
164
0
        // The container is contained by the start boundary, reduce the range to
165
0
        // the point starting at the container.
166
0
        aContainer->ToTextPoint(mStartContainer.StartAssignment(), &mStartOffset);
167
0
        static_cast<Accessible*>(mStartContainer)->AddRef();
168
0
      }
169
0
      else {
170
0
        // The start boundary and the container are siblings.
171
0
        container = aContainer;
172
0
      }
173
0
    }
174
0
    else if (containerPos != 0) {
175
0
      // The container does not contain the start boundary.
176
0
      boundary = boundaryParents[boundaryPos];
177
0
      container = containerParents[containerPos];
178
0
    }
179
0
180
0
    if (container) {
181
0
      // 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
0
      }
185
0
186
0
      // If the range starts before the container, then reduce the range to
187
0
      // 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
0
      }
192
0
    }
193
0
194
0
    boundaryParents.SetLengthAndRetainStorage(0);
195
0
    containerParents.SetLengthAndRetainStorage(0);
196
0
  }
197
0
198
0
  boundary = mEndContainer->GetChildAtOffset(mEndOffset);
199
0
  if (boundary == aContainer) {
200
0
    return true;
201
0
  }
202
0
203
0
  // Crop the end boundary.
204
0
  container = nullptr;
205
0
  CommonParent(boundary, aContainer, &boundaryParents, &boundaryPos,
206
0
               &containerParents, &containerPos);
207
0
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
0
    }
213
0
    else {
214
0
      container = aContainer;
215
0
    }
216
0
  }
217
0
  else if (containerPos != 0) {
218
0
    boundary = boundaryParents[boundaryPos];
219
0
    container = containerParents[containerPos];
220
0
  }
221
0
222
0
  if (!container) {
223
0
    return true;
224
0
  }
225
0
226
0
  if (boundary->IndexInParent() < container->IndexInParent()) {
227
0
    return !!(mRoot = nullptr);
228
0
  }
229
0
230
0
  if (boundary->IndexInParent() > container->IndexInParent()) {
231
0
    container->ToTextPoint(mEndContainer.StartAssignment(), &mEndOffset, false);
232
0
    static_cast<Accessible*>(mEndContainer)->AddRef();
233
0
  }
234
0
235
0
  return true;
236
0
}
237
238
void
239
TextRange::FindText(const nsAString& aText, EDirection aDirection,
240
                    nsCaseTreatment aCaseSensitive, TextRange* aFoundRange) const
241
0
{
242
0
243
0
}
244
245
void
246
TextRange::FindAttr(EAttr aAttr, nsIVariant* aValue, EDirection aDirection,
247
                    TextRange* aFoundRange) const
248
0
{
249
0
250
0
}
251
252
void
253
TextRange::AddToSelection() const
254
0
{
255
0
256
0
}
257
258
void
259
TextRange::RemoveFromSelection() const
260
0
{
261
0
262
0
}
263
264
void
265
TextRange::Select() const
266
0
{
267
0
}
268
269
void
270
TextRange::ScrollIntoView(EHowToAlign aHow) const
271
0
{
272
0
273
0
}
274
275
////////////////////////////////////////////////////////////////////////////////
276
// pivate
277
278
void
279
TextRange::Set(HyperTextAccessible* aRoot,
280
               HyperTextAccessible* aStartContainer, int32_t aStartOffset,
281
               HyperTextAccessible* aEndContainer, int32_t aEndOffset)
282
0
{
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
TextRange::TextInternal(nsAString& aText, Accessible* aCurrent,
292
                        uint32_t aStartIntlOffset) const
293
0
{
294
0
  bool moveNext = true;
295
0
  int32_t endIntlOffset = -1;
296
0
  if (aCurrent->Parent() == mEndContainer &&
297
0
      mEndContainer->GetChildAtOffset(mEndOffset) == aCurrent) {
298
0
299
0
    uint32_t currentStartOffset = mEndContainer->GetChildOffset(aCurrent);
300
0
    endIntlOffset = mEndOffset - currentStartOffset;
301
0
    if (endIntlOffset == 0)
302
0
      return false;
303
0
304
0
    moveNext = false;
305
0
  }
306
0
307
0
  if (aCurrent->IsTextLeaf()) {
308
0
    aCurrent->AppendTextTo(aText, aStartIntlOffset,
309
0
                           endIntlOffset - aStartIntlOffset);
310
0
    if (!moveNext)
311
0
      return false;
312
0
  }
313
0
314
0
  Accessible* next = aCurrent->FirstChild();
315
0
  if (next) {
316
0
    if (!TextInternal(aText, next, 0))
317
0
      return false;
318
0
  }
319
0
320
0
  next = aCurrent->NextSibling();
321
0
  if (next) {
322
0
    if (!TextInternal(aText, next, 0))
323
0
      return false;
324
0
  }
325
0
326
0
  return moveNext;
327
0
}
328
329
330
void
331
TextRange::MoveInternal(ETextUnit aUnit, int32_t aCount,
332
                        HyperTextAccessible& aContainer, int32_t aOffset,
333
                        HyperTextAccessible* aStopContainer, int32_t aStopOffset)
334
0
{
335
0
336
0
}
337
338
Accessible*
339
TextRange::CommonParent(Accessible* aAcc1, Accessible* aAcc2,
340
                        nsTArray<Accessible*>* aParents1, uint32_t* aPos1,
341
                        nsTArray<Accessible*>* aParents2, uint32_t* aPos2) const
342
0
{
343
0
  if (aAcc1 == aAcc2) {
344
0
    return aAcc1;
345
0
  }
346
0
347
0
  MOZ_ASSERT(aParents1->Length() == 0 || aParents2->Length() == 0,
348
0
             "Wrong arguments");
349
0
350
0
  // 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
0
362
0
  // 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
0
373
0
    parent = child1;
374
0
  }
375
0
376
0
  return parent;
377
0
}
378
379
} // namespace a11y
380
} // namespace mozilla