Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "nsString.h"
7 #include "nsTreeRows.h"
8 #include <algorithm>
10 nsTreeRows::Subtree*
11 nsTreeRows::EnsureSubtreeFor(Subtree* aParent,
12 int32_t aChildIndex)
13 {
14 Subtree* subtree = GetSubtreeFor(aParent, aChildIndex);
16 if (! subtree) {
17 subtree = aParent->mRows[aChildIndex].mSubtree = new Subtree(aParent);
18 InvalidateCachedRow();
19 }
21 return subtree;
22 }
24 nsTreeRows::Subtree*
25 nsTreeRows::GetSubtreeFor(const Subtree* aParent,
26 int32_t aChildIndex,
27 int32_t* aSubtreeSize)
28 {
29 NS_PRECONDITION(aParent, "no parent");
30 NS_PRECONDITION(aChildIndex >= 0, "bad child index");
32 Subtree* result = nullptr;
34 if (aChildIndex < aParent->mCount)
35 result = aParent->mRows[aChildIndex].mSubtree;
37 if (aSubtreeSize)
38 *aSubtreeSize = result ? result->mSubtreeSize : 0;
40 return result;
41 }
43 void
44 nsTreeRows::RemoveSubtreeFor(Subtree* aParent, int32_t aChildIndex)
45 {
46 NS_PRECONDITION(aParent, "no parent");
47 NS_PRECONDITION(aChildIndex >= 0 && aChildIndex < aParent->mCount, "bad child index");
49 Row& row = aParent->mRows[aChildIndex];
51 if (row.mSubtree) {
52 int32_t subtreeSize = row.mSubtree->GetSubtreeSize();
54 delete row.mSubtree;
55 row.mSubtree = nullptr;
57 for (Subtree* subtree = aParent; subtree != nullptr; subtree = subtree->mParent)
58 subtree->mSubtreeSize -= subtreeSize;
59 }
61 InvalidateCachedRow();
62 }
64 nsTreeRows::iterator
65 nsTreeRows::First()
66 {
67 iterator result;
68 result.Append(&mRoot, 0);
69 result.SetRowIndex(0);
70 return result;
71 }
73 nsTreeRows::iterator
74 nsTreeRows::Last()
75 {
76 iterator result;
78 // Build up a path along the rightmost edge of the tree
79 Subtree* current = &mRoot;
80 int32_t count = current->Count();
81 do {
82 int32_t last = count - 1;
83 result.Append(current, last);
84 current = count ? GetSubtreeFor(current, last) : nullptr;
85 } while (current && ((count = current->Count()) != 0));
87 // Now, at the bottom rightmost leaf, advance us one off the end.
88 result.GetTop().mChildIndex++;
90 // Our row index will be the size of the root subree, plus one.
91 result.SetRowIndex(mRoot.GetSubtreeSize() + 1);
93 return result;
94 }
96 nsTreeRows::iterator
97 nsTreeRows::operator[](int32_t aRow)
98 {
99 // See if we're just lucky, and end up with something
100 // nearby. (This tends to happen a lot due to the way that we get
101 // asked for rows n' stuff.)
102 int32_t last = mLastRow.GetRowIndex();
103 if (last != -1) {
104 if (aRow == last)
105 return mLastRow;
106 else if (last + 1 == aRow)
107 return ++mLastRow;
108 else if (last - 1 == aRow)
109 return --mLastRow;
110 }
112 // Nope. Construct a path to the specified index. This is a little
113 // bit better than O(n), because we can skip over subtrees. (So it
114 // ends up being approximately linear in the subtree size, instead
115 // of the entire view size. But, most of the time, big views are
116 // flat. Oh well.)
117 iterator result;
118 Subtree* current = &mRoot;
120 int32_t index = 0;
121 result.SetRowIndex(aRow);
123 do {
124 int32_t subtreeSize;
125 Subtree* subtree = GetSubtreeFor(current, index, &subtreeSize);
127 if (subtreeSize >= aRow) {
128 result.Append(current, index);
129 current = subtree;
130 index = 0;
131 --aRow;
132 }
133 else {
134 ++index;
135 aRow -= subtreeSize + 1;
136 }
137 } while (aRow >= 0);
139 mLastRow = result;
140 return result;
141 }
143 nsTreeRows::iterator
144 nsTreeRows::FindByResource(nsIRDFResource* aResource)
145 {
146 // XXX Mmm, scan through the rows one-by-one...
147 iterator last = Last();
148 iterator iter;
150 nsresult rv;
151 nsAutoString resourceid;
152 bool stringmode = false;
154 for (iter = First(); iter != last; ++iter) {
155 if (!stringmode) {
156 nsCOMPtr<nsIRDFResource> findres;
157 rv = iter->mMatch->mResult->GetResource(getter_AddRefs(findres));
158 if (NS_FAILED(rv)) return last;
160 if (findres == aResource)
161 break;
163 if (! findres) {
164 const char *uri;
165 aResource->GetValueConst(&uri);
166 CopyUTF8toUTF16(uri, resourceid);
168 // set stringmode and fall through
169 stringmode = true;
170 }
171 }
173 // additional check because previous block could change stringmode
174 if (stringmode) {
175 nsAutoString findid;
176 rv = iter->mMatch->mResult->GetId(findid);
177 if (NS_FAILED(rv)) return last;
179 if (resourceid.Equals(findid))
180 break;
181 }
182 }
184 return iter;
185 }
187 nsTreeRows::iterator
188 nsTreeRows::Find(nsIXULTemplateResult *aResult)
189 {
190 // XXX Mmm, scan through the rows one-by-one...
191 iterator last = Last();
192 iterator iter;
194 for (iter = First(); iter != last; ++iter) {
195 if (aResult == iter->mMatch->mResult)
196 break;
197 }
199 return iter;
200 }
202 void
203 nsTreeRows::Clear()
204 {
205 mRoot.Clear();
206 InvalidateCachedRow();
207 }
209 //----------------------------------------------------------------------
210 //
211 // nsTreeRows::Subtree
212 //
214 nsTreeRows::Subtree::~Subtree()
215 {
216 Clear();
217 }
219 void
220 nsTreeRows::Subtree::Clear()
221 {
222 for (int32_t i = mCount - 1; i >= 0; --i)
223 delete mRows[i].mSubtree;
225 delete[] mRows;
227 mRows = nullptr;
228 mCount = mCapacity = mSubtreeSize = 0;
229 }
231 nsTreeRows::iterator
232 nsTreeRows::Subtree::InsertRowAt(nsTemplateMatch* aMatch, int32_t aIndex)
233 {
234 if (mCount >= mCapacity || aIndex >= mCapacity) {
235 int32_t newCapacity = std::max(mCapacity * 2, aIndex + 1);
236 Row* newRows = new Row[newCapacity];
237 if (! newRows)
238 return iterator();
240 for (int32_t i = mCount - 1; i >= 0; --i)
241 newRows[i] = mRows[i];
243 delete[] mRows;
245 mRows = newRows;
246 mCapacity = newCapacity;
247 }
249 for (int32_t i = mCount - 1; i >= aIndex; --i)
250 mRows[i + 1] = mRows[i];
252 mRows[aIndex].mMatch = aMatch;
253 mRows[aIndex].mContainerType = eContainerType_Unknown;
254 mRows[aIndex].mContainerState = eContainerState_Unknown;
255 mRows[aIndex].mContainerFill = eContainerFill_Unknown;
256 mRows[aIndex].mSubtree = nullptr;
257 ++mCount;
259 // Now build an iterator that points to the newly inserted element.
260 int32_t rowIndex = 0;
261 iterator result;
262 result.Push(this, aIndex);
264 for ( ; --aIndex >= 0; ++rowIndex) {
265 // Account for open subtrees in the absolute row index.
266 const Subtree *subtree = mRows[aIndex].mSubtree;
267 if (subtree)
268 rowIndex += subtree->mSubtreeSize;
269 }
271 Subtree *subtree = this;
272 do {
273 // Note that the subtree's size has expanded.
274 ++subtree->mSubtreeSize;
276 Subtree *parent = subtree->mParent;
277 if (! parent)
278 break;
280 // Account for open subtrees in the absolute row index.
281 int32_t count = parent->Count();
282 for (aIndex = 0; aIndex < count; ++aIndex, ++rowIndex) {
283 const Subtree *child = (*parent)[aIndex].mSubtree;
284 if (subtree == child)
285 break;
287 if (child)
288 rowIndex += child->mSubtreeSize;
289 }
291 NS_ASSERTION(aIndex < count, "couldn't find subtree in parent");
293 result.Push(parent, aIndex);
294 subtree = parent;
295 ++rowIndex; // One for the parent row.
296 } while (1);
298 result.SetRowIndex(rowIndex);
299 return result;
300 }
302 void
303 nsTreeRows::Subtree::RemoveRowAt(int32_t aIndex)
304 {
305 NS_PRECONDITION(aIndex >= 0 && aIndex < Count(), "bad index");
306 if (aIndex < 0 || aIndex >= Count())
307 return;
309 // How big is the subtree we're going to be removing?
310 int32_t subtreeSize = mRows[aIndex].mSubtree
311 ? mRows[aIndex].mSubtree->GetSubtreeSize()
312 : 0;
314 ++subtreeSize;
316 delete mRows[aIndex].mSubtree;
318 for (int32_t i = aIndex + 1; i < mCount; ++i)
319 mRows[i - 1] = mRows[i];
321 --mCount;
323 for (Subtree* subtree = this; subtree != nullptr; subtree = subtree->mParent)
324 subtree->mSubtreeSize -= subtreeSize;
325 }
327 //----------------------------------------------------------------------
328 //
329 // nsTreeRows::iterator
330 //
332 nsTreeRows::iterator::iterator(const iterator& aIterator)
333 : mRowIndex(aIterator.mRowIndex),
334 mLink(aIterator.mLink)
335 {
336 }
338 nsTreeRows::iterator&
339 nsTreeRows::iterator::operator=(const iterator& aIterator)
340 {
341 mRowIndex = aIterator.mRowIndex;
342 mLink = aIterator.mLink;
343 return *this;
344 }
346 void
347 nsTreeRows::iterator::Append(Subtree* aParent, int32_t aChildIndex)
348 {
349 Link *link = mLink.AppendElement();
350 if (link) {
351 link->mParent = aParent;
352 link->mChildIndex = aChildIndex;
353 }
354 else
355 NS_ERROR("out of memory");
356 }
358 void
359 nsTreeRows::iterator::Push(Subtree *aParent, int32_t aChildIndex)
360 {
361 Link *link = mLink.InsertElementAt(0);
362 if (link) {
363 link->mParent = aParent;
364 link->mChildIndex = aChildIndex;
365 }
366 else
367 NS_ERROR("out of memory");
368 }
370 bool
371 nsTreeRows::iterator::operator==(const iterator& aIterator) const
372 {
373 if (GetDepth() != aIterator.GetDepth())
374 return false;
376 if (GetDepth() == 0)
377 return true;
379 return GetTop() == aIterator.GetTop();
380 }
382 void
383 nsTreeRows::iterator::Next()
384 {
385 NS_PRECONDITION(GetDepth() > 0, "cannot increment an uninitialized iterator");
387 // Increment the absolute row index
388 ++mRowIndex;
390 Link& top = GetTop();
392 // Is there a child subtree? If so, descend into the child
393 // subtree.
394 Subtree* subtree = top.GetRow().mSubtree;
396 if (subtree && subtree->Count()) {
397 Append(subtree, 0);
398 return;
399 }
401 // Have we exhausted the current subtree?
402 if (top.mChildIndex >= top.mParent->Count() - 1) {
403 // Yep. See if we've just iterated path the last element in
404 // the tree, period. Walk back up the stack, looking for any
405 // unfinished subtrees.
406 int32_t unfinished;
407 for (unfinished = GetDepth() - 2; unfinished >= 0; --unfinished) {
408 const Link& link = mLink[unfinished];
409 if (link.mChildIndex < link.mParent->Count() - 1)
410 break;
411 }
413 // If there are no unfinished subtrees in the stack, then this
414 // iterator is exhausted. Leave it in the same state that
415 // Last() does.
416 if (unfinished < 0) {
417 top.mChildIndex++;
418 return;
419 }
421 // Otherwise, we ran off the end of one of the inner
422 // subtrees. Pop up to the next unfinished level in the stack.
423 mLink.SetLength(unfinished + 1);
424 }
426 // Advance to the next child in this subtree
427 ++(GetTop().mChildIndex);
428 }
430 void
431 nsTreeRows::iterator::Prev()
432 {
433 NS_PRECONDITION(GetDepth() > 0, "cannot increment an uninitialized iterator");
435 // Decrement the absolute row index
436 --mRowIndex;
438 // Move to the previous child in this subtree
439 --(GetTop().mChildIndex);
441 // Have we exhausted the current subtree?
442 if (GetTop().mChildIndex < 0) {
443 // Yep. See if we've just iterated back to the first element
444 // in the tree, period. Walk back up the stack, looking for
445 // any unfinished subtrees.
446 int32_t unfinished;
447 for (unfinished = GetDepth() - 2; unfinished >= 0; --unfinished) {
448 const Link& link = mLink[unfinished];
449 if (link.mChildIndex >= 0)
450 break;
451 }
453 // If there are no unfinished subtrees in the stack, then this
454 // iterator is exhausted. Leave it in the same state that
455 // First() does.
456 if (unfinished < 0)
457 return;
459 // Otherwise, we ran off the end of one of the inner
460 // subtrees. Pop up to the next unfinished level in the stack.
461 mLink.SetLength(unfinished + 1);
462 return;
463 }
465 // Is there a child subtree immediately prior to our current
466 // position? If so, descend into it, grovelling down to the
467 // deepest, rightmost left edge.
468 Subtree* parent = GetTop().GetParent();
469 int32_t index = GetTop().GetChildIndex();
471 Subtree* subtree = (*parent)[index].mSubtree;
473 if (subtree && subtree->Count()) {
474 do {
475 index = subtree->Count() - 1;
476 Append(subtree, index);
478 parent = subtree;
479 subtree = (*parent)[index].mSubtree;
480 } while (subtree && subtree->Count());
481 }
482 }