layout/inspector/inDOMView.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

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

mercurial