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/. */
7 #include "TextRange-inl.h"
9 #include "Accessible-inl.h"
10 #include "nsAccUtils.h"
15 ////////////////////////////////////////////////////////////////////////////////
18 bool TextPoint::operator<(const TextPoint
& aPoint
) const {
19 if (mContainer
== aPoint
.mContainer
) return mOffset
< aPoint
.mOffset
;
21 // Build the chain of parents
22 Accessible
* p1
= mContainer
;
23 Accessible
* p2
= aPoint
.mContainer
;
24 AutoTArray
<Accessible
*, 30> parents1
, parents2
;
26 parents1
.AppendElement(p1
);
30 parents2
.AppendElement(p2
);
34 // Find where the parent chain differs
35 uint32_t pos1
= parents1
.Length(), pos2
= parents2
.Length();
36 for (uint32_t len
= std::min(pos1
, pos2
); len
> 0; --len
) {
37 Accessible
* child1
= parents1
.ElementAt(--pos1
);
38 Accessible
* child2
= parents2
.ElementAt(--pos2
);
40 return child1
->IndexInParent() < child2
->IndexInParent();
43 NS_ERROR("Broken tree?!");
47 ////////////////////////////////////////////////////////////////////////////////
50 TextRange::TextRange(HyperTextAccessible
* aRoot
,
51 HyperTextAccessible
* aStartContainer
, int32_t aStartOffset
,
52 HyperTextAccessible
* aEndContainer
, int32_t aEndOffset
)
54 mStartContainer(aStartContainer
),
55 mEndContainer(aEndContainer
),
56 mStartOffset(aStartOffset
),
57 mEndOffset(aEndOffset
) {}
59 void TextRange::EmbeddedChildren(nsTArray
<Accessible
*>* aChildren
) const {
60 if (mStartContainer
== mEndContainer
) {
61 int32_t startIdx
= mStartContainer
->GetChildIndexAtOffset(mStartOffset
);
62 int32_t endIdx
= mStartContainer
->GetChildIndexAtOffset(mEndOffset
);
63 for (int32_t idx
= startIdx
; idx
<= endIdx
; idx
++) {
64 Accessible
* child
= mStartContainer
->GetChildAt(idx
);
65 if (!child
->IsText()) {
66 aChildren
->AppendElement(child
);
72 Accessible
* p1
= mStartContainer
->GetChildAtOffset(mStartOffset
);
73 Accessible
* p2
= mEndContainer
->GetChildAtOffset(mEndOffset
);
75 uint32_t pos1
= 0, pos2
= 0;
76 AutoTArray
<Accessible
*, 30> parents1
, parents2
;
77 Accessible
* container
=
78 CommonParent(p1
, p2
, &parents1
, &pos1
, &parents2
, &pos2
);
80 // Traverse the tree up to the container and collect embedded objects.
81 for (uint32_t idx
= 0; idx
< pos1
- 1; idx
++) {
82 Accessible
* parent
= parents1
[idx
+ 1];
83 Accessible
* child
= parents1
[idx
];
84 uint32_t childCount
= parent
->ChildCount();
85 for (uint32_t childIdx
= child
->IndexInParent(); childIdx
< childCount
;
87 Accessible
* next
= parent
->GetChildAt(childIdx
);
88 if (!next
->IsText()) {
89 aChildren
->AppendElement(next
);
94 // Traverse through direct children in the container.
95 int32_t endIdx
= parents2
[pos2
- 1]->IndexInParent();
96 int32_t childIdx
= parents1
[pos1
- 1]->IndexInParent() + 1;
97 for (; childIdx
< endIdx
; childIdx
++) {
98 Accessible
* next
= container
->GetChildAt(childIdx
);
99 if (!next
->IsText()) {
100 aChildren
->AppendElement(next
);
104 // Traverse down from the container to end point.
105 for (int32_t idx
= pos2
- 2; idx
> 0; idx
--) {
106 Accessible
* parent
= parents2
[idx
];
107 Accessible
* child
= parents2
[idx
- 1];
108 int32_t endIdx
= child
->IndexInParent();
109 for (int32_t childIdx
= 0; childIdx
< endIdx
; childIdx
++) {
110 Accessible
* next
= parent
->GetChildAt(childIdx
);
111 if (!next
->IsText()) {
112 aChildren
->AppendElement(next
);
118 void TextRange::Text(nsAString
& aText
) const {
119 Accessible
* current
= mStartContainer
->GetChildAtOffset(mStartOffset
);
120 uint32_t startIntlOffset
=
121 mStartOffset
- mStartContainer
->GetChildOffset(current
);
123 while (current
&& TextInternal(aText
, current
, startIntlOffset
)) {
124 current
= current
->Parent();
127 current
= current
->NextSibling();
131 void TextRange::Bounds(nsTArray
<nsIntRect
> aRects
) const {}
133 void TextRange::Normalize(ETextUnit aUnit
) {}
135 bool TextRange::Crop(Accessible
* aContainer
) {
136 uint32_t boundaryPos
= 0, containerPos
= 0;
137 AutoTArray
<Accessible
*, 30> boundaryParents
, containerParents
;
139 // Crop the start boundary.
140 Accessible
* container
= nullptr;
141 Accessible
* boundary
= mStartContainer
->GetChildAtOffset(mStartOffset
);
142 if (boundary
!= aContainer
) {
143 CommonParent(boundary
, aContainer
, &boundaryParents
, &boundaryPos
,
144 &containerParents
, &containerPos
);
146 if (boundaryPos
== 0) {
147 if (containerPos
!= 0) {
148 // The container is contained by the start boundary, reduce the range to
149 // the point starting at the container.
150 aContainer
->ToTextPoint(mStartContainer
.StartAssignment(),
152 static_cast<Accessible
*>(mStartContainer
)->AddRef();
154 // The start boundary and the container are siblings.
155 container
= aContainer
;
157 } else if (containerPos
!= 0) {
158 // The container does not contain the start boundary.
159 boundary
= boundaryParents
[boundaryPos
];
160 container
= containerParents
[containerPos
];
164 // If the range start is after the container, then make the range invalid.
165 if (boundary
->IndexInParent() > container
->IndexInParent()) {
166 return !!(mRoot
= nullptr);
169 // If the range starts before the container, then reduce the range to
170 // the point starting at the container.
171 if (boundary
->IndexInParent() < container
->IndexInParent()) {
172 container
->ToTextPoint(mStartContainer
.StartAssignment(),
174 mStartContainer
.get()->AddRef();
178 boundaryParents
.SetLengthAndRetainStorage(0);
179 containerParents
.SetLengthAndRetainStorage(0);
182 boundary
= mEndContainer
->GetChildAtOffset(mEndOffset
);
183 if (boundary
== aContainer
) {
187 // Crop the end boundary.
189 CommonParent(boundary
, aContainer
, &boundaryParents
, &boundaryPos
,
190 &containerParents
, &containerPos
);
192 if (boundaryPos
== 0) {
193 if (containerPos
!= 0) {
194 aContainer
->ToTextPoint(mEndContainer
.StartAssignment(), &mEndOffset
,
196 static_cast<Accessible
*>(mEndContainer
)->AddRef();
198 container
= aContainer
;
200 } else if (containerPos
!= 0) {
201 boundary
= boundaryParents
[boundaryPos
];
202 container
= containerParents
[containerPos
];
209 if (boundary
->IndexInParent() < container
->IndexInParent()) {
210 return !!(mRoot
= nullptr);
213 if (boundary
->IndexInParent() > container
->IndexInParent()) {
214 container
->ToTextPoint(mEndContainer
.StartAssignment(), &mEndOffset
, false);
215 static_cast<Accessible
*>(mEndContainer
)->AddRef();
221 void TextRange::FindText(const nsAString
& aText
, EDirection aDirection
,
222 nsCaseTreatment aCaseSensitive
,
223 TextRange
* aFoundRange
) const {}
225 void TextRange::FindAttr(EAttr aAttr
, nsIVariant
* aValue
, EDirection aDirection
,
226 TextRange
* aFoundRange
) const {}
228 void TextRange::AddToSelection() const {}
230 void TextRange::RemoveFromSelection() const {}
232 void TextRange::Select() const {}
234 void TextRange::ScrollIntoView(EHowToAlign aHow
) const {}
236 ////////////////////////////////////////////////////////////////////////////////
239 void TextRange::Set(HyperTextAccessible
* aRoot
,
240 HyperTextAccessible
* aStartContainer
, int32_t aStartOffset
,
241 HyperTextAccessible
* aEndContainer
, int32_t aEndOffset
) {
243 mStartContainer
= aStartContainer
;
244 mEndContainer
= aEndContainer
;
245 mStartOffset
= aStartOffset
;
246 mEndOffset
= aEndOffset
;
249 bool TextRange::TextInternal(nsAString
& aText
, Accessible
* aCurrent
,
250 uint32_t aStartIntlOffset
) const {
251 bool moveNext
= true;
252 int32_t endIntlOffset
= -1;
253 if (aCurrent
->Parent() == mEndContainer
&&
254 mEndContainer
->GetChildAtOffset(mEndOffset
) == aCurrent
) {
255 uint32_t currentStartOffset
= mEndContainer
->GetChildOffset(aCurrent
);
256 endIntlOffset
= mEndOffset
- currentStartOffset
;
257 if (endIntlOffset
== 0) return false;
262 if (aCurrent
->IsTextLeaf()) {
263 aCurrent
->AppendTextTo(aText
, aStartIntlOffset
,
264 endIntlOffset
- aStartIntlOffset
);
265 if (!moveNext
) return false;
268 Accessible
* next
= aCurrent
->FirstChild();
270 if (!TextInternal(aText
, next
, 0)) return false;
273 next
= aCurrent
->NextSibling();
275 if (!TextInternal(aText
, next
, 0)) return false;
281 void TextRange::MoveInternal(ETextUnit aUnit
, int32_t aCount
,
282 HyperTextAccessible
& aContainer
, int32_t aOffset
,
283 HyperTextAccessible
* aStopContainer
,
284 int32_t aStopOffset
) {}
286 Accessible
* TextRange::CommonParent(Accessible
* aAcc1
, Accessible
* aAcc2
,
287 nsTArray
<Accessible
*>* aParents1
,
289 nsTArray
<Accessible
*>* aParents2
,
290 uint32_t* aPos2
) const {
291 if (aAcc1
== aAcc2
) {
295 MOZ_ASSERT(aParents1
->Length() == 0 || aParents2
->Length() == 0,
298 // Build the chain of parents.
299 Accessible
* p1
= aAcc1
;
300 Accessible
* p2
= aAcc2
;
302 aParents1
->AppendElement(p1
);
306 aParents2
->AppendElement(p2
);
310 // Find where the parent chain differs
311 *aPos1
= aParents1
->Length();
312 *aPos2
= aParents2
->Length();
313 Accessible
* parent
= nullptr;
315 for (len
= std::min(*aPos1
, *aPos2
); len
> 0; --len
) {
316 Accessible
* child1
= aParents1
->ElementAt(--(*aPos1
));
317 Accessible
* child2
= aParents2
->ElementAt(--(*aPos2
));
318 if (child1
!= child2
) break;
327 } // namespace mozilla