Line data Source code
1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
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/. */
5 :
6 : #include "inDOMView.h"
7 : #include "inIDOMUtils.h"
8 :
9 : #include "inLayoutUtils.h"
10 :
11 : #include "nsString.h"
12 : #include "nsReadableUtils.h"
13 : #include "nsIDOMNode.h"
14 : #include "nsIDOMNodeFilter.h"
15 : #include "nsIDOMNodeList.h"
16 : #include "nsIDOMCharacterData.h"
17 : #include "nsIDOMAttr.h"
18 : #include "nsIDOMMozNamedAttrMap.h"
19 : #include "nsIDOMMutationEvent.h"
20 : #include "nsBindingManager.h"
21 : #include "nsNameSpaceManager.h"
22 : #include "nsIDocument.h"
23 : #include "nsIServiceManager.h"
24 : #include "nsITreeColumns.h"
25 : #include "nsITreeBoxObject.h"
26 : #include "mozilla/dom/Element.h"
27 : #include "mozilla/Services.h"
28 :
29 : #ifdef ACCESSIBILITY
30 : #include "nsAccessibilityService.h"
31 : #endif
32 :
33 : using namespace mozilla;
34 :
35 : ////////////////////////////////////////////////////////////////////////
36 : // inDOMViewNode
37 :
38 : class inDOMViewNode
39 : {
40 : public:
41 : inDOMViewNode() {}
42 : explicit inDOMViewNode(nsIDOMNode* aNode);
43 : ~inDOMViewNode();
44 :
45 : nsCOMPtr<nsIDOMNode> node;
46 :
47 : inDOMViewNode* parent;
48 : inDOMViewNode* next;
49 : inDOMViewNode* previous;
50 :
51 : int32_t level;
52 : bool isOpen;
53 : bool isContainer;
54 : bool hasAnonymous;
55 : bool hasSubDocument;
56 : };
57 :
58 0 : inDOMViewNode::inDOMViewNode(nsIDOMNode* aNode) :
59 : node(aNode),
60 : parent(nullptr),
61 : next(nullptr),
62 : previous(nullptr),
63 : level(0),
64 : isOpen(false),
65 : isContainer(false),
66 : hasAnonymous(false),
67 0 : hasSubDocument(false)
68 : {
69 :
70 0 : }
71 :
72 0 : inDOMViewNode::~inDOMViewNode()
73 : {
74 0 : }
75 :
76 : ////////////////////////////////////////////////////////////////////////
77 :
78 0 : inDOMView::inDOMView() :
79 : mShowAnonymous(false),
80 : mShowSubDocuments(false),
81 : mShowWhitespaceNodes(true),
82 : mShowAccessibleNodes(false),
83 0 : mWhatToShow(nsIDOMNodeFilter::SHOW_ALL)
84 : {
85 0 : }
86 :
87 0 : inDOMView::~inDOMView()
88 : {
89 0 : SetRootNode(nullptr);
90 0 : }
91 :
92 :
93 : ////////////////////////////////////////////////////////////////////////
94 : // nsISupports
95 :
96 0 : NS_IMPL_ISUPPORTS(inDOMView,
97 : inIDOMView,
98 : nsITreeView,
99 : nsIMutationObserver)
100 :
101 : ////////////////////////////////////////////////////////////////////////
102 : // inIDOMView
103 :
104 : NS_IMETHODIMP
105 0 : inDOMView::GetRootNode(nsIDOMNode** aNode)
106 : {
107 0 : *aNode = mRootNode;
108 0 : NS_IF_ADDREF(*aNode);
109 0 : return NS_OK;
110 : }
111 :
112 : NS_IMETHODIMP
113 0 : inDOMView::SetRootNode(nsIDOMNode* aNode)
114 : {
115 0 : if (mTree)
116 0 : mTree->BeginUpdateBatch();
117 :
118 0 : if (mRootDocument) {
119 : // remove previous document observer
120 0 : nsCOMPtr<nsINode> doc(do_QueryInterface(mRootDocument));
121 0 : if (doc)
122 0 : doc->RemoveMutationObserver(this);
123 : }
124 :
125 0 : RemoveAllNodes();
126 :
127 0 : mRootNode = aNode;
128 :
129 0 : if (aNode) {
130 : // If we are able to show element nodes, then start with the root node
131 : // as the first node in the buffer
132 0 : if (mWhatToShow & nsIDOMNodeFilter::SHOW_ELEMENT) {
133 : // allocate new node array
134 0 : AppendNode(CreateNode(aNode, nullptr));
135 : } else {
136 : // place only the children of the root node in the buffer
137 0 : ExpandNode(-1);
138 : }
139 :
140 : // store an owning reference to document so that it isn't
141 : // destroyed before we are
142 0 : mRootDocument = do_QueryInterface(aNode);
143 0 : if (!mRootDocument) {
144 0 : aNode->GetOwnerDocument(getter_AddRefs(mRootDocument));
145 : }
146 :
147 : // add document observer
148 0 : nsCOMPtr<nsINode> doc(do_QueryInterface(mRootDocument));
149 0 : if (doc)
150 0 : doc->AddMutationObserver(this);
151 : } else {
152 0 : mRootDocument = nullptr;
153 : }
154 :
155 0 : if (mTree)
156 0 : mTree->EndUpdateBatch();
157 :
158 0 : return NS_OK;
159 : }
160 :
161 : NS_IMETHODIMP
162 0 : inDOMView::GetNodeFromRowIndex(int32_t rowIndex, nsIDOMNode **_retval)
163 : {
164 0 : inDOMViewNode* viewNode = nullptr;
165 0 : RowToNode(rowIndex, &viewNode);
166 0 : if (!viewNode) return NS_ERROR_FAILURE;
167 0 : *_retval = viewNode->node;
168 0 : NS_IF_ADDREF(*_retval);
169 :
170 0 : return NS_OK;
171 : }
172 :
173 : NS_IMETHODIMP
174 0 : inDOMView::GetRowIndexFromNode(nsIDOMNode *node, int32_t *_retval)
175 : {
176 0 : NodeToRow(node, _retval);
177 0 : return NS_OK;
178 : }
179 :
180 :
181 : NS_IMETHODIMP
182 0 : inDOMView::GetShowAnonymousContent(bool *aShowAnonymousContent)
183 : {
184 0 : *aShowAnonymousContent = mShowAnonymous;
185 0 : return NS_OK;
186 : }
187 :
188 : NS_IMETHODIMP
189 0 : inDOMView::SetShowAnonymousContent(bool aShowAnonymousContent)
190 : {
191 0 : mShowAnonymous = aShowAnonymousContent;
192 0 : return NS_OK;
193 : }
194 :
195 : NS_IMETHODIMP
196 0 : inDOMView::GetShowSubDocuments(bool *aShowSubDocuments)
197 : {
198 0 : *aShowSubDocuments = mShowSubDocuments;
199 0 : return NS_OK;
200 : }
201 :
202 : NS_IMETHODIMP
203 0 : inDOMView::SetShowSubDocuments(bool aShowSubDocuments)
204 : {
205 0 : mShowSubDocuments = aShowSubDocuments;
206 0 : return NS_OK;
207 : }
208 :
209 : NS_IMETHODIMP
210 0 : inDOMView::GetShowWhitespaceNodes(bool *aShowWhitespaceNodes)
211 : {
212 0 : *aShowWhitespaceNodes = mShowWhitespaceNodes;
213 0 : return NS_OK;
214 : }
215 :
216 : NS_IMETHODIMP
217 0 : inDOMView::SetShowWhitespaceNodes(bool aShowWhitespaceNodes)
218 : {
219 0 : mShowWhitespaceNodes = aShowWhitespaceNodes;
220 0 : return NS_OK;
221 : }
222 :
223 : NS_IMETHODIMP
224 0 : inDOMView::GetShowAccessibleNodes(bool *aShowAccessibleNodes)
225 : {
226 0 : *aShowAccessibleNodes = mShowAccessibleNodes;
227 0 : return NS_OK;
228 : }
229 :
230 : NS_IMETHODIMP
231 0 : inDOMView::SetShowAccessibleNodes(bool aShowAccessibleNodes)
232 : {
233 0 : mShowAccessibleNodes = aShowAccessibleNodes;
234 0 : return NS_OK;
235 : }
236 :
237 : NS_IMETHODIMP
238 0 : inDOMView::GetWhatToShow(uint32_t *aWhatToShow)
239 : {
240 0 : *aWhatToShow = mWhatToShow;
241 0 : return NS_OK;
242 : }
243 :
244 : NS_IMETHODIMP
245 0 : inDOMView::SetWhatToShow(uint32_t aWhatToShow)
246 : {
247 0 : mWhatToShow = aWhatToShow;
248 0 : return NS_OK;
249 : }
250 :
251 : NS_IMETHODIMP
252 0 : inDOMView::Rebuild()
253 : {
254 0 : nsCOMPtr<nsIDOMNode> root;
255 0 : GetRootNode(getter_AddRefs(root));
256 0 : SetRootNode(root);
257 0 : return NS_OK;
258 : }
259 :
260 : ////////////////////////////////////////////////////////////////////////
261 : // nsITreeView
262 :
263 : NS_IMETHODIMP
264 0 : inDOMView::GetRowCount(int32_t *aRowCount)
265 : {
266 0 : *aRowCount = GetRowCount();
267 0 : return NS_OK;
268 : }
269 :
270 : NS_IMETHODIMP
271 0 : inDOMView::GetRowProperties(int32_t index, nsAString& aProps)
272 : {
273 0 : return NS_OK;
274 : }
275 :
276 : NS_IMETHODIMP
277 0 : inDOMView::GetCellProperties(int32_t row, nsITreeColumn* col,
278 : nsAString& aProps)
279 : {
280 0 : inDOMViewNode* node = nullptr;
281 0 : RowToNode(row, &node);
282 0 : if (!node) return NS_ERROR_FAILURE;
283 :
284 0 : nsCOMPtr<nsIContent> content = do_QueryInterface(node->node);
285 0 : if (content && content->IsInAnonymousSubtree()) {
286 0 : aProps.AppendLiteral("anonymous ");
287 : }
288 :
289 : uint16_t nodeType;
290 0 : node->node->GetNodeType(&nodeType);
291 0 : switch (nodeType) {
292 : case nsIDOMNode::ELEMENT_NODE:
293 0 : aProps.AppendLiteral("ELEMENT_NODE");
294 0 : break;
295 : case nsIDOMNode::ATTRIBUTE_NODE:
296 0 : aProps.AppendLiteral("ATTRIBUTE_NODE");
297 0 : break;
298 : case nsIDOMNode::TEXT_NODE:
299 0 : aProps.AppendLiteral("TEXT_NODE");
300 0 : break;
301 : case nsIDOMNode::CDATA_SECTION_NODE:
302 0 : aProps.AppendLiteral("CDATA_SECTION_NODE");
303 0 : break;
304 : case nsIDOMNode::ENTITY_REFERENCE_NODE:
305 0 : aProps.AppendLiteral("ENTITY_REFERENCE_NODE");
306 0 : break;
307 : case nsIDOMNode::ENTITY_NODE:
308 0 : aProps.AppendLiteral("ENTITY_NODE");
309 0 : break;
310 : case nsIDOMNode::PROCESSING_INSTRUCTION_NODE:
311 0 : aProps.AppendLiteral("PROCESSING_INSTRUCTION_NODE");
312 0 : break;
313 : case nsIDOMNode::COMMENT_NODE:
314 0 : aProps.AppendLiteral("COMMENT_NODE");
315 0 : break;
316 : case nsIDOMNode::DOCUMENT_NODE:
317 0 : aProps.AppendLiteral("DOCUMENT_NODE");
318 0 : break;
319 : case nsIDOMNode::DOCUMENT_TYPE_NODE:
320 0 : aProps.AppendLiteral("DOCUMENT_TYPE_NODE");
321 0 : break;
322 : case nsIDOMNode::DOCUMENT_FRAGMENT_NODE:
323 0 : aProps.AppendLiteral("DOCUMENT_FRAGMENT_NODE");
324 0 : break;
325 : case nsIDOMNode::NOTATION_NODE:
326 0 : aProps.AppendLiteral("NOTATION_NODE");
327 0 : break;
328 : }
329 :
330 : #ifdef ACCESSIBILITY
331 0 : if (mShowAccessibleNodes) {
332 0 : nsAccessibilityService* accService = GetOrCreateAccService();
333 0 : NS_ENSURE_TRUE(accService, NS_ERROR_FAILURE);
334 :
335 0 : if (accService->HasAccessible(node->node))
336 0 : aProps.AppendLiteral(" ACCESSIBLE_NODE");
337 : }
338 : #endif
339 :
340 0 : return NS_OK;
341 : }
342 :
343 : NS_IMETHODIMP
344 0 : inDOMView::GetColumnProperties(nsITreeColumn* col, nsAString& aProps)
345 : {
346 0 : return NS_OK;
347 : }
348 :
349 : NS_IMETHODIMP
350 0 : inDOMView::GetImageSrc(int32_t row, nsITreeColumn* col, nsAString& _retval)
351 : {
352 0 : return NS_OK;
353 : }
354 :
355 : NS_IMETHODIMP
356 0 : inDOMView::GetProgressMode(int32_t row, nsITreeColumn* col, int32_t* _retval)
357 : {
358 0 : return NS_OK;
359 : }
360 :
361 : NS_IMETHODIMP
362 0 : inDOMView::GetCellValue(int32_t row, nsITreeColumn* col, nsAString& _retval)
363 : {
364 0 : return NS_OK;
365 : }
366 :
367 : NS_IMETHODIMP
368 0 : inDOMView::GetCellText(int32_t row, nsITreeColumn* col, nsAString& _retval)
369 : {
370 0 : inDOMViewNode* node = nullptr;
371 0 : RowToNode(row, &node);
372 0 : if (!node) return NS_ERROR_FAILURE;
373 :
374 0 : nsIDOMNode* domNode = node->node;
375 :
376 0 : nsAutoString colID;
377 0 : col->GetId(colID);
378 0 : if (colID.EqualsLiteral("colNodeName"))
379 0 : domNode->GetNodeName(_retval);
380 0 : else if (colID.EqualsLiteral("colLocalName"))
381 0 : domNode->GetLocalName(_retval);
382 0 : else if (colID.EqualsLiteral("colPrefix"))
383 0 : domNode->GetPrefix(_retval);
384 0 : else if (colID.EqualsLiteral("colNamespaceURI"))
385 0 : domNode->GetNamespaceURI(_retval);
386 0 : else if (colID.EqualsLiteral("colNodeType")) {
387 : uint16_t nodeType;
388 0 : domNode->GetNodeType(&nodeType);
389 0 : nsAutoString temp;
390 0 : temp.AppendInt(int32_t(nodeType));
391 0 : _retval = temp;
392 0 : } else if (colID.EqualsLiteral("colNodeValue"))
393 0 : domNode->GetNodeValue(_retval);
394 : else {
395 0 : if (StringBeginsWith(colID, NS_LITERAL_STRING("col@"))) {
396 0 : nsCOMPtr<nsIDOMElement> el = do_QueryInterface(node->node);
397 0 : if (el) {
398 0 : nsAutoString attr;
399 0 : colID.Right(attr, colID.Length()-4); // have to use this because Substring is crashing on me!
400 0 : el->GetAttribute(attr, _retval);
401 : }
402 : }
403 : }
404 :
405 0 : return NS_OK;
406 : }
407 :
408 : NS_IMETHODIMP
409 0 : inDOMView::IsContainer(int32_t index, bool *_retval)
410 : {
411 0 : inDOMViewNode* node = nullptr;
412 0 : RowToNode(index, &node);
413 0 : if (!node) return NS_ERROR_FAILURE;
414 :
415 0 : *_retval = node->isContainer;
416 0 : return NS_OK;
417 : }
418 :
419 : NS_IMETHODIMP
420 0 : inDOMView::IsContainerOpen(int32_t index, bool *_retval)
421 : {
422 0 : inDOMViewNode* node = nullptr;
423 0 : RowToNode(index, &node);
424 0 : if (!node) return NS_ERROR_FAILURE;
425 :
426 0 : *_retval = node->isOpen;
427 0 : return NS_OK;
428 : }
429 :
430 : NS_IMETHODIMP
431 0 : inDOMView::IsContainerEmpty(int32_t index, bool *_retval)
432 : {
433 0 : inDOMViewNode* node = nullptr;
434 0 : RowToNode(index, &node);
435 0 : if (!node) return NS_ERROR_FAILURE;
436 :
437 0 : *_retval = node->isContainer ? false : true;
438 0 : return NS_OK;
439 : }
440 :
441 : NS_IMETHODIMP
442 0 : inDOMView::GetLevel(int32_t index, int32_t *_retval)
443 : {
444 0 : inDOMViewNode* node = nullptr;
445 0 : RowToNode(index, &node);
446 0 : if (!node) return NS_ERROR_FAILURE;
447 :
448 0 : *_retval = node->level;
449 0 : return NS_OK;
450 : }
451 :
452 : NS_IMETHODIMP
453 0 : inDOMView::GetParentIndex(int32_t rowIndex, int32_t *_retval)
454 : {
455 0 : inDOMViewNode* node = nullptr;
456 0 : RowToNode(rowIndex, &node);
457 0 : if (!node) return NS_ERROR_FAILURE;
458 :
459 : // GetParentIndex returns -1 if there is no parent
460 0 : *_retval = -1;
461 :
462 0 : inDOMViewNode* checkNode = nullptr;
463 0 : int32_t i = rowIndex - 1;
464 0 : do {
465 0 : nsresult rv = RowToNode(i, &checkNode);
466 0 : if (NS_FAILED(rv)) {
467 : // No parent. Just break out.
468 0 : break;
469 : }
470 :
471 0 : if (checkNode == node->parent) {
472 0 : *_retval = i;
473 0 : return NS_OK;
474 : }
475 0 : --i;
476 0 : } while (checkNode);
477 :
478 0 : return NS_OK;
479 : }
480 :
481 : NS_IMETHODIMP
482 0 : inDOMView::HasNextSibling(int32_t rowIndex, int32_t afterIndex, bool *_retval)
483 : {
484 0 : inDOMViewNode* node = nullptr;
485 0 : RowToNode(rowIndex, &node);
486 0 : if (!node) return NS_ERROR_FAILURE;
487 :
488 0 : *_retval = node->next != nullptr;
489 :
490 0 : return NS_OK;
491 : }
492 :
493 : NS_IMETHODIMP
494 0 : inDOMView::ToggleOpenState(int32_t index)
495 : {
496 0 : inDOMViewNode* node = nullptr;
497 0 : RowToNode(index, &node);
498 0 : if (!node) return NS_ERROR_FAILURE;
499 :
500 0 : int32_t oldCount = GetRowCount();
501 0 : if (node->isOpen)
502 0 : CollapseNode(index);
503 : else
504 0 : ExpandNode(index);
505 :
506 : // Update the twisty.
507 0 : mTree->InvalidateRow(index);
508 :
509 0 : mTree->RowCountChanged(index+1, GetRowCount() - oldCount);
510 :
511 0 : return NS_OK;
512 : }
513 :
514 : NS_IMETHODIMP
515 0 : inDOMView::SetTree(nsITreeBoxObject *tree)
516 : {
517 0 : mTree = tree;
518 0 : return NS_OK;
519 : }
520 :
521 : NS_IMETHODIMP
522 0 : inDOMView::GetSelection(nsITreeSelection * *aSelection)
523 : {
524 0 : *aSelection = mSelection;
525 0 : NS_IF_ADDREF(*aSelection);
526 0 : return NS_OK;
527 : }
528 :
529 0 : NS_IMETHODIMP inDOMView::SetSelection(nsITreeSelection * aSelection)
530 : {
531 0 : mSelection = aSelection;
532 0 : return NS_OK;
533 : }
534 :
535 : NS_IMETHODIMP
536 0 : inDOMView::SelectionChanged()
537 : {
538 0 : return NS_OK;
539 : }
540 :
541 : NS_IMETHODIMP
542 0 : inDOMView::SetCellValue(int32_t row, nsITreeColumn* col, const nsAString& value)
543 : {
544 0 : return NS_OK;
545 : }
546 :
547 : NS_IMETHODIMP
548 0 : inDOMView::SetCellText(int32_t row, nsITreeColumn* col, const nsAString& value)
549 : {
550 0 : return NS_OK;
551 : }
552 :
553 : NS_IMETHODIMP
554 0 : inDOMView::CycleHeader(nsITreeColumn* col)
555 : {
556 0 : return NS_OK;
557 : }
558 :
559 : NS_IMETHODIMP
560 0 : inDOMView::CycleCell(int32_t row, nsITreeColumn* col)
561 : {
562 0 : return NS_OK;
563 : }
564 :
565 : NS_IMETHODIMP
566 0 : inDOMView::IsEditable(int32_t row, nsITreeColumn* col, bool *_retval)
567 : {
568 0 : return NS_OK;
569 : }
570 :
571 :
572 : NS_IMETHODIMP
573 0 : inDOMView::IsSelectable(int32_t row, nsITreeColumn* col, bool *_retval)
574 : {
575 0 : return NS_OK;
576 : }
577 :
578 : NS_IMETHODIMP
579 0 : inDOMView::IsSeparator(int32_t index, bool *_retval)
580 : {
581 0 : return NS_OK;
582 : }
583 :
584 : NS_IMETHODIMP
585 0 : inDOMView::IsSorted(bool *_retval)
586 : {
587 0 : return NS_OK;
588 : }
589 :
590 : NS_IMETHODIMP
591 0 : inDOMView::CanDrop(int32_t index, int32_t orientation,
592 : nsIDOMDataTransfer* aDataTransfer, bool *_retval)
593 : {
594 0 : *_retval = false;
595 0 : return NS_OK;
596 : }
597 :
598 : NS_IMETHODIMP
599 0 : inDOMView::Drop(int32_t row, int32_t orientation, nsIDOMDataTransfer* aDataTransfer)
600 : {
601 0 : return NS_OK;
602 : }
603 :
604 : NS_IMETHODIMP
605 0 : inDOMView::PerformAction(const char16_t *action)
606 : {
607 0 : return NS_OK;
608 : }
609 :
610 : NS_IMETHODIMP
611 0 : inDOMView::PerformActionOnRow(const char16_t *action, int32_t row)
612 : {
613 0 : return NS_OK;
614 : }
615 :
616 : NS_IMETHODIMP
617 0 : inDOMView::PerformActionOnCell(const char16_t* action, int32_t row, nsITreeColumn* col)
618 : {
619 0 : return NS_OK;
620 : }
621 :
622 : ///////////////////////////////////////////////////////////////////////
623 : // nsIMutationObserver
624 :
625 : void
626 0 : inDOMView::NodeWillBeDestroyed(const nsINode* aNode)
627 : {
628 0 : NS_NOTREACHED("Document destroyed while we're holding a strong ref to it");
629 0 : }
630 :
631 : void
632 0 : inDOMView::AttributeChanged(nsIDocument* aDocument, dom::Element* aElement,
633 : int32_t aNameSpaceID, nsIAtom* aAttribute,
634 : int32_t aModType,
635 : const nsAttrValue* aOldValue)
636 : {
637 0 : if (!mTree) {
638 0 : return;
639 : }
640 :
641 0 : if (!(mWhatToShow & nsIDOMNodeFilter::SHOW_ATTRIBUTE)) {
642 0 : return;
643 : }
644 :
645 0 : nsCOMPtr<nsIMutationObserver> kungFuDeathGrip(this);
646 :
647 : // get the dom attribute node, if there is any
648 0 : nsCOMPtr<nsIDOMElement> el(do_QueryInterface(aElement));
649 0 : nsCOMPtr<nsIDOMAttr> domAttr;
650 0 : nsDependentAtomString attrStr(aAttribute);
651 0 : if (aNameSpaceID) {
652 0 : nsNameSpaceManager* nsm = nsNameSpaceManager::GetInstance();
653 0 : if (!nsm) {
654 : // we can't find out which attribute we want :(
655 0 : return;
656 : }
657 0 : nsString attrNS;
658 0 : nsresult rv = nsm->GetNameSpaceURI(aNameSpaceID, attrNS);
659 0 : if (NS_FAILED(rv)) {
660 0 : return;
661 : }
662 0 : (void)el->GetAttributeNodeNS(attrNS, attrStr, getter_AddRefs(domAttr));
663 : } else {
664 0 : (void)el->GetAttributeNode(attrStr, getter_AddRefs(domAttr));
665 : }
666 :
667 0 : if (aModType == nsIDOMMutationEvent::MODIFICATION) {
668 : // No fancy stuff here, just invalidate the changed row
669 0 : if (!domAttr) {
670 0 : return;
671 : }
672 0 : int32_t row = 0;
673 0 : NodeToRow(domAttr, &row);
674 0 : mTree->InvalidateRange(row, row);
675 0 : } else if (aModType == nsIDOMMutationEvent::ADDITION) {
676 0 : if (!domAttr) {
677 0 : return;
678 : }
679 : // get the number of attributes on this content node
680 0 : nsCOMPtr<nsIDOMMozNamedAttrMap> attrs;
681 0 : el->GetAttributes(getter_AddRefs(attrs));
682 : uint32_t attrCount;
683 0 : attrs->GetLength(&attrCount);
684 :
685 0 : inDOMViewNode* contentNode = nullptr;
686 : int32_t contentRow;
687 : int32_t attrRow;
688 0 : if (mRootNode == el &&
689 0 : !(mWhatToShow & nsIDOMNodeFilter::SHOW_ELEMENT)) {
690 : // if this view has a root node but is not displaying it,
691 : // it is ok to act as if the changed attribute is on the root.
692 0 : attrRow = attrCount - 1;
693 : } else {
694 0 : if (NS_FAILED(NodeToRow(el, &contentRow))) {
695 0 : return;
696 : }
697 0 : RowToNode(contentRow, &contentNode);
698 0 : if (!contentNode->isOpen) {
699 0 : return;
700 : }
701 0 : attrRow = contentRow + attrCount;
702 : }
703 :
704 0 : inDOMViewNode* newNode = CreateNode(domAttr, contentNode);
705 0 : inDOMViewNode* insertNode = nullptr;
706 0 : RowToNode(attrRow, &insertNode);
707 0 : if (insertNode) {
708 0 : if (contentNode &&
709 0 : insertNode->level <= contentNode->level) {
710 0 : RowToNode(attrRow-1, &insertNode);
711 0 : InsertLinkAfter(newNode, insertNode);
712 : } else
713 0 : InsertLinkBefore(newNode, insertNode);
714 : }
715 0 : InsertNode(newNode, attrRow);
716 0 : mTree->RowCountChanged(attrRow, 1);
717 0 : } else if (aModType == nsIDOMMutationEvent::REMOVAL) {
718 : // At this point, the attribute is already gone from the DOM, but is still represented
719 : // in our mRows array. Search through the content node's children for the corresponding
720 : // node and remove it.
721 :
722 : // get the row of the content node
723 0 : inDOMViewNode* contentNode = nullptr;
724 : int32_t contentRow;
725 : int32_t baseLevel;
726 0 : if (NS_SUCCEEDED(NodeToRow(el, &contentRow))) {
727 0 : RowToNode(contentRow, &contentNode);
728 0 : baseLevel = contentNode->level;
729 : } else {
730 0 : if (mRootNode == el) {
731 0 : contentRow = -1;
732 0 : baseLevel = -1;
733 : } else
734 0 : return;
735 : }
736 :
737 : // search for the attribute node that was removed
738 0 : inDOMViewNode* checkNode = nullptr;
739 0 : int32_t row = 0;
740 0 : for (row = contentRow+1; row < GetRowCount(); ++row) {
741 0 : checkNode = GetNodeAt(row);
742 0 : if (checkNode->level == baseLevel+1) {
743 0 : domAttr = do_QueryInterface(checkNode->node);
744 0 : if (domAttr) {
745 0 : nsAutoString attrName;
746 0 : domAttr->GetNodeName(attrName);
747 0 : if (attrName.Equals(attrStr)) {
748 : // we have found the row for the attribute that was removed
749 0 : RemoveLink(checkNode);
750 0 : RemoveNode(row);
751 0 : mTree->RowCountChanged(row, -1);
752 0 : break;
753 : }
754 : }
755 : }
756 0 : if (checkNode->level <= baseLevel)
757 0 : break;
758 : }
759 :
760 : }
761 : }
762 :
763 : void
764 0 : inDOMView::ContentAppended(nsIDocument *aDocument,
765 : nsIContent* aContainer,
766 : nsIContent* aFirstNewContent,
767 : int32_t /* unused */)
768 : {
769 0 : if (!mTree) {
770 0 : return;
771 : }
772 :
773 0 : for (nsIContent* cur = aFirstNewContent; cur; cur = cur->GetNextSibling()) {
774 : // Our ContentInserted impl doesn't use the index
775 0 : ContentInserted(aDocument, aContainer, cur, 0);
776 : }
777 : }
778 :
779 : void
780 0 : inDOMView::ContentInserted(nsIDocument *aDocument, nsIContent* aContainer,
781 : nsIContent* aChild, int32_t /* unused */)
782 : {
783 0 : if (!mTree)
784 0 : return;
785 :
786 : nsresult rv;
787 0 : nsCOMPtr<nsIDOMNode> childDOMNode(do_QueryInterface(aChild));
788 0 : nsCOMPtr<nsIDOMNode> parent;
789 0 : if (!mDOMUtils) {
790 0 : mDOMUtils = services::GetInDOMUtils();
791 0 : if (!mDOMUtils) {
792 0 : return;
793 : }
794 : }
795 0 : mDOMUtils->GetParentForNode(childDOMNode, mShowAnonymous,
796 0 : getter_AddRefs(parent));
797 :
798 : // find the inDOMViewNode for the parent of the inserted content
799 0 : int32_t parentRow = 0;
800 0 : if (NS_FAILED(rv = NodeToRow(parent, &parentRow)))
801 0 : return;
802 0 : inDOMViewNode* parentNode = nullptr;
803 0 : if (NS_FAILED(rv = RowToNode(parentRow, &parentNode)))
804 0 : return;
805 :
806 0 : nsCOMPtr<nsIMutationObserver> kungFuDeathGrip(this);
807 :
808 0 : if (!parentNode->isOpen) {
809 : // Parent is not open, so don't bother creating tree rows for the
810 : // kids. But do indicate that it's now a container, if needed.
811 0 : if (!parentNode->isContainer) {
812 0 : parentNode->isContainer = true;
813 0 : mTree->InvalidateRow(parentRow);
814 : }
815 0 : return;
816 : }
817 :
818 : // get the previous sibling of the inserted content
819 0 : nsCOMPtr<nsIDOMNode> previous;
820 0 : GetRealPreviousSibling(childDOMNode, parent, getter_AddRefs(previous));
821 0 : inDOMViewNode* previousNode = nullptr;
822 :
823 0 : int32_t row = 0;
824 0 : if (previous) {
825 : // find the inDOMViewNode for the previous sibling of the inserted content
826 0 : int32_t previousRow = 0;
827 0 : if (NS_FAILED(rv = NodeToRow(previous, &previousRow)))
828 0 : return;
829 0 : if (NS_FAILED(rv = RowToNode(previousRow, &previousNode)))
830 0 : return;
831 :
832 : // get the last descendant of the previous row, which is the row
833 : // after which to insert this new row
834 0 : GetLastDescendantOf(previousNode, previousRow, &row);
835 0 : ++row;
836 : } else {
837 : // there is no previous sibling, so the new row will be inserted after the parent
838 0 : row = parentRow+1;
839 : }
840 :
841 0 : inDOMViewNode* newNode = CreateNode(childDOMNode, parentNode);
842 :
843 0 : if (previous) {
844 0 : InsertLinkAfter(newNode, previousNode);
845 : } else {
846 : int32_t firstChildRow;
847 0 : if (NS_SUCCEEDED(GetFirstDescendantOf(parentNode, parentRow, &firstChildRow))) {
848 : inDOMViewNode* firstChild;
849 0 : RowToNode(firstChildRow, &firstChild);
850 0 : InsertLinkBefore(newNode, firstChild);
851 : }
852 : }
853 :
854 : // insert new node
855 0 : InsertNode(newNode, row);
856 :
857 0 : mTree->RowCountChanged(row, 1);
858 : }
859 :
860 : void
861 0 : inDOMView::ContentRemoved(nsIDocument *aDocument, nsIContent* aContainer,
862 : nsIContent* aChild, int32_t aIndexInContainer,
863 : nsIContent* aPreviousSibling)
864 : {
865 0 : if (!mTree)
866 0 : return;
867 :
868 : nsresult rv;
869 :
870 : // find the inDOMViewNode for the old child
871 0 : nsCOMPtr<nsIDOMNode> oldDOMNode(do_QueryInterface(aChild));
872 0 : int32_t row = 0;
873 0 : if (NS_FAILED(rv = NodeToRow(oldDOMNode, &row)))
874 0 : return;
875 : inDOMViewNode* oldNode;
876 0 : if (NS_FAILED(rv = RowToNode(row, &oldNode)))
877 0 : return;
878 :
879 0 : nsCOMPtr<nsIMutationObserver> kungFuDeathGrip(this);
880 :
881 : // The parent may no longer be a container. Note that we don't want
882 : // to access oldNode after calling RemoveNode, so do this now.
883 0 : inDOMViewNode* parentNode = oldNode->parent;
884 0 : bool isOnlyChild = oldNode->previous == nullptr && oldNode->next == nullptr;
885 :
886 : // Keep track of how many rows we are removing. It's at least one,
887 : // but if we're open it's more.
888 0 : int32_t oldCount = GetRowCount();
889 :
890 0 : if (oldNode->isOpen)
891 0 : CollapseNode(row);
892 :
893 0 : RemoveLink(oldNode);
894 0 : RemoveNode(row);
895 :
896 0 : if (isOnlyChild) {
897 : // Fix up the parent
898 0 : parentNode->isContainer = false;
899 0 : parentNode->isOpen = false;
900 0 : mTree->InvalidateRow(NodeToRow(parentNode));
901 : }
902 :
903 0 : mTree->RowCountChanged(row, GetRowCount() - oldCount);
904 : }
905 :
906 : ///////////////////////////////////////////////////////////////////////
907 : // inDOMView
908 :
909 : //////// NODE MANAGEMENT
910 :
911 : inDOMViewNode*
912 0 : inDOMView::GetNodeAt(int32_t aRow)
913 : {
914 0 : return mNodes.ElementAt(aRow);
915 : }
916 :
917 : int32_t
918 0 : inDOMView::GetRowCount()
919 : {
920 0 : return mNodes.Length();
921 : }
922 :
923 : int32_t
924 0 : inDOMView::NodeToRow(inDOMViewNode* aNode)
925 : {
926 0 : return mNodes.IndexOf(aNode);
927 : }
928 :
929 : inDOMViewNode*
930 0 : inDOMView::CreateNode(nsIDOMNode* aNode, inDOMViewNode* aParent)
931 : {
932 0 : inDOMViewNode* viewNode = new inDOMViewNode(aNode);
933 0 : viewNode->level = aParent ? aParent->level+1 : 0;
934 0 : viewNode->parent = aParent;
935 :
936 0 : nsCOMArray<nsIDOMNode> grandKids;
937 0 : GetChildNodesFor(aNode, grandKids);
938 0 : viewNode->isContainer = (grandKids.Count() > 0);
939 0 : return viewNode;
940 : }
941 :
942 : bool
943 0 : inDOMView::RowOutOfBounds(int32_t aRow, int32_t aCount)
944 : {
945 0 : return aRow < 0 || aRow >= GetRowCount() || aCount+aRow > GetRowCount();
946 : }
947 :
948 : void
949 0 : inDOMView::AppendNode(inDOMViewNode* aNode)
950 : {
951 0 : mNodes.AppendElement(aNode);
952 0 : }
953 :
954 : void
955 0 : inDOMView::InsertNode(inDOMViewNode* aNode, int32_t aRow)
956 : {
957 0 : if (RowOutOfBounds(aRow, 1))
958 0 : AppendNode(aNode);
959 : else
960 0 : mNodes.InsertElementAt(aRow, aNode);
961 0 : }
962 :
963 : void
964 0 : inDOMView::RemoveNode(int32_t aRow)
965 : {
966 0 : if (RowOutOfBounds(aRow, 1))
967 0 : return;
968 :
969 0 : delete GetNodeAt(aRow);
970 0 : mNodes.RemoveElementAt(aRow);
971 : }
972 :
973 : void
974 0 : inDOMView::ReplaceNode(inDOMViewNode* aNode, int32_t aRow)
975 : {
976 0 : if (RowOutOfBounds(aRow, 1))
977 0 : return;
978 :
979 0 : delete GetNodeAt(aRow);
980 0 : mNodes.ElementAt(aRow) = aNode;
981 : }
982 :
983 : void
984 0 : inDOMView::InsertNodes(nsTArray<inDOMViewNode*>& aNodes, int32_t aRow)
985 : {
986 0 : if (aRow < 0 || aRow > GetRowCount())
987 0 : return;
988 :
989 0 : mNodes.InsertElementsAt(aRow, aNodes);
990 : }
991 :
992 : void
993 0 : inDOMView::RemoveNodes(int32_t aRow, int32_t aCount)
994 : {
995 0 : if (aRow < 0)
996 0 : return;
997 :
998 0 : int32_t rowCount = GetRowCount();
999 0 : for (int32_t i = aRow; i < aRow+aCount && i < rowCount; ++i) {
1000 0 : delete GetNodeAt(i);
1001 : }
1002 :
1003 0 : mNodes.RemoveElementsAt(aRow, aCount);
1004 : }
1005 :
1006 : void
1007 0 : inDOMView::RemoveAllNodes()
1008 : {
1009 0 : int32_t rowCount = GetRowCount();
1010 0 : for (int32_t i = 0; i < rowCount; ++i) {
1011 0 : delete GetNodeAt(i);
1012 : }
1013 :
1014 0 : mNodes.Clear();
1015 0 : }
1016 :
1017 : void
1018 0 : inDOMView::ExpandNode(int32_t aRow)
1019 : {
1020 0 : inDOMViewNode* node = nullptr;
1021 0 : RowToNode(aRow, &node);
1022 :
1023 0 : nsCOMArray<nsIDOMNode> kids;
1024 0 : GetChildNodesFor(node ? node->node : mRootNode,
1025 0 : kids);
1026 0 : int32_t kidCount = kids.Count();
1027 :
1028 0 : nsTArray<inDOMViewNode*> list(kidCount);
1029 :
1030 0 : inDOMViewNode* newNode = nullptr;
1031 0 : inDOMViewNode* prevNode = nullptr;
1032 :
1033 0 : for (int32_t i = 0; i < kidCount; ++i) {
1034 0 : newNode = CreateNode(kids[i], node);
1035 0 : list.AppendElement(newNode);
1036 :
1037 0 : if (prevNode)
1038 0 : prevNode->next = newNode;
1039 0 : newNode->previous = prevNode;
1040 0 : prevNode = newNode;
1041 : }
1042 :
1043 0 : InsertNodes(list, aRow+1);
1044 :
1045 0 : if (node)
1046 0 : node->isOpen = true;
1047 0 : }
1048 :
1049 : void
1050 0 : inDOMView::CollapseNode(int32_t aRow)
1051 : {
1052 0 : inDOMViewNode* node = nullptr;
1053 0 : nsresult rv = RowToNode(aRow, &node);
1054 0 : if (NS_FAILED(rv)) {
1055 0 : return;
1056 : }
1057 :
1058 0 : int32_t row = 0;
1059 0 : GetLastDescendantOf(node, aRow, &row);
1060 :
1061 0 : RemoveNodes(aRow+1, row-aRow);
1062 :
1063 0 : node->isOpen = false;
1064 : }
1065 :
1066 : //////// NODE AND ROW CONVERSION
1067 :
1068 : nsresult
1069 0 : inDOMView::RowToNode(int32_t aRow, inDOMViewNode** aNode)
1070 : {
1071 0 : if (aRow < 0 || aRow >= GetRowCount())
1072 0 : return NS_ERROR_FAILURE;
1073 :
1074 0 : *aNode = GetNodeAt(aRow);
1075 0 : return NS_OK;
1076 : }
1077 :
1078 : nsresult
1079 0 : inDOMView::NodeToRow(nsIDOMNode* aNode, int32_t* aRow)
1080 : {
1081 0 : int32_t rowCount = GetRowCount();
1082 0 : for (int32_t i = 0; i < rowCount; ++i) {
1083 0 : if (GetNodeAt(i)->node == aNode) {
1084 0 : *aRow = i;
1085 0 : return NS_OK;
1086 : }
1087 : }
1088 :
1089 0 : *aRow = -1;
1090 0 : return NS_ERROR_FAILURE;
1091 : }
1092 :
1093 : //////// NODE HIERARCHY MUTATION
1094 :
1095 : void
1096 0 : inDOMView::InsertLinkAfter(inDOMViewNode* aNode, inDOMViewNode* aInsertAfter)
1097 : {
1098 0 : if (aInsertAfter->next)
1099 0 : aInsertAfter->next->previous = aNode;
1100 0 : aNode->next = aInsertAfter->next;
1101 0 : aInsertAfter->next = aNode;
1102 0 : aNode->previous = aInsertAfter;
1103 0 : }
1104 :
1105 : void
1106 0 : inDOMView::InsertLinkBefore(inDOMViewNode* aNode, inDOMViewNode* aInsertBefore)
1107 : {
1108 0 : if (aInsertBefore->previous)
1109 0 : aInsertBefore->previous->next = aNode;
1110 0 : aNode->previous = aInsertBefore->previous;
1111 0 : aInsertBefore->previous = aNode;
1112 0 : aNode->next = aInsertBefore;
1113 0 : }
1114 :
1115 : void
1116 0 : inDOMView::RemoveLink(inDOMViewNode* aNode)
1117 : {
1118 0 : if (aNode->previous)
1119 0 : aNode->previous->next = aNode->next;
1120 0 : if (aNode->next)
1121 0 : aNode->next->previous = aNode->previous;
1122 0 : }
1123 :
1124 : void
1125 0 : inDOMView::ReplaceLink(inDOMViewNode* aNewNode, inDOMViewNode* aOldNode)
1126 : {
1127 0 : if (aOldNode->previous)
1128 0 : aOldNode->previous->next = aNewNode;
1129 0 : if (aOldNode->next)
1130 0 : aOldNode->next->previous = aNewNode;
1131 0 : aNewNode->next = aOldNode->next;
1132 0 : aNewNode->previous = aOldNode->previous;
1133 0 : }
1134 :
1135 : //////// NODE HIERARCHY UTILITIES
1136 :
1137 : nsresult
1138 0 : inDOMView::GetFirstDescendantOf(inDOMViewNode* aNode, int32_t aRow, int32_t* aResult)
1139 : {
1140 : // get the first node that is a descendant of the previous sibling
1141 0 : int32_t row = 0;
1142 : inDOMViewNode* node;
1143 0 : for (row = aRow+1; row < GetRowCount(); ++row) {
1144 0 : node = GetNodeAt(row);
1145 0 : if (node->parent == aNode) {
1146 0 : *aResult = row;
1147 0 : return NS_OK;
1148 : }
1149 0 : if (node->level <= aNode->level)
1150 0 : break;
1151 : }
1152 0 : return NS_ERROR_FAILURE;
1153 : }
1154 :
1155 : nsresult
1156 0 : inDOMView::GetLastDescendantOf(inDOMViewNode* aNode, int32_t aRow, int32_t* aResult)
1157 : {
1158 : // get the last node that is a descendant of the previous sibling
1159 0 : int32_t row = 0;
1160 0 : for (row = aRow+1; row < GetRowCount(); ++row) {
1161 0 : if (GetNodeAt(row)->level <= aNode->level)
1162 0 : break;
1163 : }
1164 0 : *aResult = row-1;
1165 0 : return NS_OK;
1166 : }
1167 :
1168 : //////// DOM UTILITIES
1169 :
1170 : nsresult
1171 0 : inDOMView::GetChildNodesFor(nsIDOMNode* aNode, nsCOMArray<nsIDOMNode>& aResult)
1172 : {
1173 0 : NS_ENSURE_ARG(aNode);
1174 : // attribute nodes
1175 0 : if (mWhatToShow & nsIDOMNodeFilter::SHOW_ATTRIBUTE) {
1176 0 : nsCOMPtr<nsIDOMElement> element = do_QueryInterface(aNode);
1177 0 : if (element) {
1178 0 : nsCOMPtr<nsIDOMMozNamedAttrMap> attrs;
1179 0 : element->GetAttributes(getter_AddRefs(attrs));
1180 0 : if (attrs) {
1181 0 : AppendAttrsToArray(attrs, aResult);
1182 : }
1183 : }
1184 : }
1185 :
1186 0 : if (mWhatToShow & nsIDOMNodeFilter::SHOW_ELEMENT) {
1187 0 : nsCOMPtr<nsIDOMNodeList> kids;
1188 0 : if (!mDOMUtils) {
1189 0 : mDOMUtils = services::GetInDOMUtils();
1190 0 : if (!mDOMUtils) {
1191 0 : return NS_ERROR_FAILURE;
1192 : }
1193 : }
1194 :
1195 0 : mDOMUtils->GetChildrenForNode(aNode, mShowAnonymous,
1196 0 : getter_AddRefs(kids));
1197 :
1198 0 : if (kids) {
1199 0 : AppendKidsToArray(kids, aResult);
1200 : }
1201 : }
1202 :
1203 0 : if (mShowSubDocuments) {
1204 : nsCOMPtr<nsIDOMNode> domdoc =
1205 0 : do_QueryInterface(inLayoutUtils::GetSubDocumentFor(aNode));
1206 0 : if (domdoc) {
1207 0 : aResult.AppendObject(domdoc);
1208 : }
1209 : }
1210 :
1211 0 : return NS_OK;
1212 : }
1213 :
1214 : nsresult
1215 0 : inDOMView::GetRealPreviousSibling(nsIDOMNode* aNode, nsIDOMNode* aRealParent, nsIDOMNode** aSibling)
1216 : {
1217 : // XXXjrh: This won't work for some cases during some situations where XBL insertion points
1218 : // are involved. Fix me!
1219 0 : aNode->GetPreviousSibling(aSibling);
1220 0 : return NS_OK;
1221 : }
1222 :
1223 : nsresult
1224 0 : inDOMView::AppendKidsToArray(nsIDOMNodeList* aKids,
1225 : nsCOMArray<nsIDOMNode>& aArray)
1226 : {
1227 0 : uint32_t l = 0;
1228 0 : aKids->GetLength(&l);
1229 0 : nsCOMPtr<nsIDOMNode> kid;
1230 0 : uint16_t nodeType = 0;
1231 :
1232 : // Try and get DOM Utils in case we don't have one yet.
1233 0 : if (!mShowWhitespaceNodes && !mDOMUtils) {
1234 0 : mDOMUtils = services::GetInDOMUtils();
1235 : }
1236 :
1237 0 : for (uint32_t i = 0; i < l; ++i) {
1238 0 : aKids->Item(i, getter_AddRefs(kid));
1239 0 : kid->GetNodeType(&nodeType);
1240 :
1241 0 : NS_ASSERTION(nodeType && nodeType <= nsIDOMNode::NOTATION_NODE,
1242 : "Unknown node type. "
1243 : "Were new types added to the spec?");
1244 : // As of DOM Level 2 Core and Traversal, each NodeFilter constant
1245 : // is defined as the lower nth bit in the NodeFilter bitmask,
1246 : // where n is the numeric constant of the nodeType it represents.
1247 : // If this invariant ever changes, we will need to update the
1248 : // following line.
1249 0 : uint32_t filterForNodeType = 1 << (nodeType - 1);
1250 :
1251 0 : if (mWhatToShow & filterForNodeType) {
1252 0 : if ((nodeType == nsIDOMNode::TEXT_NODE ||
1253 0 : nodeType == nsIDOMNode::COMMENT_NODE) &&
1254 0 : !mShowWhitespaceNodes && mDOMUtils) {
1255 0 : nsCOMPtr<nsIDOMCharacterData> data = do_QueryInterface(kid);
1256 0 : NS_ASSERTION(data, "Does not implement nsIDOMCharacterData!");
1257 : bool ignore;
1258 0 : mDOMUtils->IsIgnorableWhitespace(data, &ignore);
1259 0 : if (ignore) {
1260 0 : continue;
1261 : }
1262 : }
1263 :
1264 0 : aArray.AppendElement(kid.forget());
1265 : }
1266 : }
1267 :
1268 0 : return NS_OK;
1269 : }
1270 :
1271 : nsresult
1272 0 : inDOMView::AppendAttrsToArray(nsIDOMMozNamedAttrMap* aAttributes,
1273 : nsCOMArray<nsIDOMNode>& aArray)
1274 : {
1275 0 : uint32_t l = 0;
1276 0 : aAttributes->GetLength(&l);
1277 0 : nsCOMPtr<nsIDOMAttr> attribute;
1278 0 : for (uint32_t i = 0; i < l; ++i) {
1279 0 : aAttributes->Item(i, getter_AddRefs(attribute));
1280 0 : aArray.AppendElement(attribute.forget());
1281 : }
1282 0 : return NS_OK;
1283 : }
|