LCOV - code coverage report
Current view: top level - dom/html - HTMLTableElement.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 550 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 75 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "mozilla/dom/HTMLTableElement.h"
       8             : #include "mozilla/GenericSpecifiedValuesInlines.h"
       9             : #include "nsAttrValueInlines.h"
      10             : #include "nsHTMLStyleSheet.h"
      11             : #include "nsMappedAttributes.h"
      12             : #include "mozilla/dom/HTMLCollectionBinding.h"
      13             : #include "mozilla/dom/HTMLTableElementBinding.h"
      14             : #include "nsContentUtils.h"
      15             : #include "jsfriendapi.h"
      16             : 
      17           0 : NS_IMPL_NS_NEW_HTML_ELEMENT(Table)
      18             : 
      19             : namespace mozilla {
      20             : namespace dom {
      21             : 
      22             : /* ------------------------------ TableRowsCollection -------------------------------- */
      23             : /**
      24             :  * This class provides a late-bound collection of rows in a table.
      25             :  * mParent is NOT ref-counted to avoid circular references
      26             :  */
      27             : class TableRowsCollection final : public nsIHTMLCollection
      28             :                                 , public nsStubMutationObserver
      29             :                                 , public nsWrapperCache
      30             : {
      31             : public:
      32             :   explicit TableRowsCollection(HTMLTableElement* aParent);
      33             : 
      34             :   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
      35             :   NS_DECL_NSIDOMHTMLCOLLECTION
      36             : 
      37             :   NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
      38             :   NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
      39             :   NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
      40             :   NS_DECL_NSIMUTATIONOBSERVER_NODEWILLBEDESTROYED
      41             : 
      42             :   virtual Element* GetElementAt(uint32_t aIndex) override;
      43           0 :   virtual nsINode* GetParentObject() override
      44             :   {
      45           0 :     return mParent;
      46             :   }
      47             : 
      48             :   virtual Element*
      49             :   GetFirstNamedElement(const nsAString& aName, bool& aFound) override;
      50             :   virtual void GetSupportedNames(nsTArray<nsString>& aNames) override;
      51             : 
      52             :   NS_IMETHOD    ParentDestroyed();
      53             : 
      54           0 :   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(TableRowsCollection, nsIHTMLCollection)
      55             : 
      56             :   // nsWrapperCache
      57             :   using nsWrapperCache::GetWrapperPreserveColor;
      58             :   using nsWrapperCache::PreserveWrapper;
      59             :   virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
      60             : protected:
      61             :   // Unregister ourselves as a mutation observer, and clear our internal state.
      62             :   void CleanUp();
      63           0 :   void LastRelease()
      64             :   {
      65           0 :     CleanUp();
      66           0 :   }
      67           0 :   virtual ~TableRowsCollection()
      68           0 :   {
      69             :     // we do NOT have a ref-counted reference to mParent, so do NOT
      70             :     // release it!  this is to avoid circular references.  The
      71             :     // instantiator who provided mParent is responsible for managing our
      72             :     // reference for us.
      73           0 :     CleanUp();
      74           0 :   }
      75             : 
      76           0 :   virtual JSObject* GetWrapperPreserveColorInternal() override
      77             :   {
      78           0 :     return nsWrapperCache::GetWrapperPreserveColor();
      79             :   }
      80           0 :   virtual void PreserveWrapperInternal(nsISupports* aScriptObjectHolder) override
      81             :   {
      82           0 :     nsWrapperCache::PreserveWrapper(aScriptObjectHolder);
      83           0 :   }
      84             : 
      85             :   // Ensure that HTMLTableElement is in a valid state. This must be called
      86             :   // before inspecting the mRows object.
      87             :   void EnsureInitialized();
      88             : 
      89             :   // Checks if the passed-in container is interesting for the purposes of
      90             :   // invalidation due to a mutation observer.
      91             :   bool InterestingContainer(nsIContent* aContainer);
      92             : 
      93             :   // Check if the passed-in nsIContent is a <tr> within the section defined by
      94             :   // `aSection`. The root of the table is considered to be part of the `<tbody>`
      95             :   // section.
      96             :   bool IsAppropriateRow(nsIAtom* aSection, nsIContent* aContent);
      97             : 
      98             :   // Scan backwards starting from `aCurrent` in the table, looking for the
      99             :   // previous row in the table which is within the section `aSection`.
     100             :   nsIContent* PreviousRow(nsIAtom* aSection, nsIContent* aCurrent);
     101             : 
     102             :   // Handle the insertion of the child `aChild` into the container `aContainer`
     103             :   // within the tree. The container must be an `InterestingContainer`. This
     104             :   // method updates the mRows, mBodyStart, and mFootStart member variables.
     105             :   //
     106             :   // HandleInsert returns an integer which can be passed to the next call of the
     107             :   // method in a loop inserting children into the same container. This will
     108             :   // optimize subsequent insertions to require less work. This can either be -1,
     109             :   // in which case we don't know where to insert the next row, and When passed
     110             :   // to HandleInsert, it will use `PreviousRow` to locate the index to insert.
     111             :   // Or, it can be an index to insert the next <tr> in the same container at.
     112             :   int32_t HandleInsert(nsIContent* aContainer,
     113             :                        nsIContent* aChild,
     114             :                        int32_t aIndexGuess = -1);
     115             : 
     116             :   // The HTMLTableElement which this TableRowsCollection tracks the rows for.
     117             :   HTMLTableElement* mParent;
     118             : 
     119             :   // The current state of the TableRowsCollection. mBodyStart and mFootStart are
     120             :   // indices into mRows which represent the location of the first row in the
     121             :   // body or foot section. If there are no rows in a section, the index points
     122             :   // at the location where the first element in that section would be inserted.
     123             :   nsTArray<nsCOMPtr<nsIContent>> mRows;
     124             :   uint32_t mBodyStart;
     125             :   uint32_t mFootStart;
     126             :   bool mInitialized;
     127             : };
     128             : 
     129             : 
     130           0 : TableRowsCollection::TableRowsCollection(HTMLTableElement *aParent)
     131             :   : mParent(aParent)
     132             :   , mBodyStart(0)
     133             :   , mFootStart(0)
     134           0 :   , mInitialized(false)
     135             : {
     136           0 :   MOZ_ASSERT(mParent);
     137           0 : }
     138             : 
     139             : void
     140           0 : TableRowsCollection::EnsureInitialized()
     141             : {
     142           0 :   if (mInitialized) {
     143           0 :     return;
     144             :   }
     145           0 :   mInitialized = true;
     146             : 
     147             :   // Initialize mRows as the TableRowsCollection is created. The mutation
     148             :   // observer should keep it up to date.
     149             :   //
     150             :   // It should be extremely unlikely that anyone creates a TableRowsCollection
     151             :   // without calling a method on it, so lazily performing this initialization
     152             :   // seems unnecessary.
     153           0 :   AutoTArray<nsCOMPtr<nsIContent>, 32> body;
     154           0 :   AutoTArray<nsCOMPtr<nsIContent>, 32> foot;
     155           0 :   mRows.Clear();
     156             : 
     157           0 :   auto addRowChildren = [&] (nsTArray<nsCOMPtr<nsIContent>>& aArray, nsIContent* aNode) {
     158           0 :     for (nsIContent* inner = aNode->nsINode::GetFirstChild();
     159           0 :          inner; inner = inner->GetNextSibling()) {
     160           0 :       if (inner->IsHTMLElement(nsGkAtoms::tr)) {
     161           0 :         aArray.AppendElement(inner);
     162             :       }
     163             :     }
     164           0 :   };
     165             : 
     166           0 :   for (nsIContent* node = mParent->nsINode::GetFirstChild();
     167           0 :        node; node = node->GetNextSibling()) {
     168           0 :     if (node->IsHTMLElement(nsGkAtoms::thead)) {
     169           0 :       addRowChildren(mRows, node);
     170           0 :     } else if (node->IsHTMLElement(nsGkAtoms::tbody)) {
     171           0 :       addRowChildren(body, node);
     172           0 :     } else if (node->IsHTMLElement(nsGkAtoms::tfoot)) {
     173           0 :       addRowChildren(foot, node);
     174           0 :     } else if (node->IsHTMLElement(nsGkAtoms::tr)) {
     175           0 :       body.AppendElement(node);
     176             :     }
     177             :   }
     178             : 
     179           0 :   mBodyStart = mRows.Length();
     180           0 :   mRows.AppendElements(Move(body));
     181           0 :   mFootStart = mRows.Length();
     182           0 :   mRows.AppendElements(Move(foot));
     183             : 
     184           0 :   mParent->AddMutationObserver(this);
     185             : }
     186             : 
     187             : void
     188           0 : TableRowsCollection::CleanUp()
     189             : {
     190             :   // Unregister ourselves as a mutation observer.
     191           0 :   if (mInitialized && mParent)  {
     192           0 :     mParent->RemoveMutationObserver(this);
     193             :   }
     194             : 
     195             :   // Clean up all of our internal state and make it empty in case someone looks
     196             :   // at us.
     197           0 :   mRows.Clear();
     198           0 :   mBodyStart = 0;
     199           0 :   mFootStart = 0;
     200             : 
     201             :   // We set mInitialized to true in case someone still has a reference to us, as
     202             :   // we don't need to try to initialize first.
     203           0 :   mInitialized = true;
     204           0 :   mParent = nullptr;
     205           0 : }
     206             : 
     207             : JSObject*
     208           0 : TableRowsCollection::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
     209             : {
     210           0 :   return HTMLCollectionBinding::Wrap(aCx, this, aGivenProto);
     211             : }
     212             : 
     213           0 : NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(TableRowsCollection, mRows)
     214           0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(TableRowsCollection)
     215           0 : NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_LAST_RELEASE(TableRowsCollection,
     216             :                                                    LastRelease())
     217             : 
     218           0 : NS_INTERFACE_TABLE_HEAD(TableRowsCollection)
     219           0 :   NS_WRAPPERCACHE_INTERFACE_TABLE_ENTRY
     220           0 :   NS_INTERFACE_TABLE(TableRowsCollection, nsIHTMLCollection,
     221             :                      nsIDOMHTMLCollection, nsIMutationObserver)
     222           0 :   NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(TableRowsCollection)
     223           0 : NS_INTERFACE_MAP_END
     224             : 
     225             : NS_IMETHODIMP
     226           0 : TableRowsCollection::GetLength(uint32_t* aLength)
     227             : {
     228           0 :   EnsureInitialized();
     229           0 :   *aLength = mRows.Length();
     230           0 :   return NS_OK;
     231             : }
     232             : 
     233             : Element*
     234           0 : TableRowsCollection::GetElementAt(uint32_t aIndex)
     235             : {
     236           0 :   EnsureInitialized();
     237           0 :   if (aIndex < mRows.Length()) {
     238           0 :     return mRows[aIndex]->AsElement();
     239             :   }
     240           0 :   return nullptr;
     241             : }
     242             : 
     243             : NS_IMETHODIMP
     244           0 : TableRowsCollection::Item(uint32_t aIndex, nsIDOMNode** aReturn)
     245             : {
     246           0 :   nsISupports* node = GetElementAt(aIndex);
     247           0 :   if (!node) {
     248           0 :     *aReturn = nullptr;
     249             : 
     250           0 :     return NS_OK;
     251             :   }
     252             : 
     253           0 :   return CallQueryInterface(node, aReturn);
     254             : }
     255             : 
     256             : Element*
     257           0 : TableRowsCollection::GetFirstNamedElement(const nsAString& aName, bool& aFound)
     258             : {
     259           0 :   EnsureInitialized();
     260           0 :   aFound = false;
     261           0 :   nsCOMPtr<nsIAtom> nameAtom = NS_Atomize(aName);
     262           0 :   NS_ENSURE_TRUE(nameAtom, nullptr);
     263             : 
     264           0 :   for (auto& node : mRows) {
     265           0 :     if (node->AttrValueIs(kNameSpaceID_None, nsGkAtoms::name,
     266           0 :                           nameAtom, eCaseMatters) ||
     267           0 :         node->AttrValueIs(kNameSpaceID_None, nsGkAtoms::id,
     268             :                           nameAtom, eCaseMatters)) {
     269           0 :       aFound = true;
     270           0 :       return node->AsElement();
     271             :     }
     272             :   }
     273             : 
     274           0 :   return nullptr;
     275             : }
     276             : 
     277             : void
     278           0 : TableRowsCollection::GetSupportedNames(nsTArray<nsString>& aNames)
     279             : {
     280           0 :   EnsureInitialized();
     281           0 :   for (auto& node : mRows) {
     282           0 :     if (node->HasID()) {
     283           0 :       nsIAtom* idAtom = node->GetID();
     284           0 :       MOZ_ASSERT(idAtom != nsGkAtoms::_empty,
     285             :                  "Empty ids don't get atomized");
     286           0 :       nsDependentAtomString idStr(idAtom);
     287           0 :       if (!aNames.Contains(idStr)) {
     288           0 :         aNames.AppendElement(idStr);
     289             :       }
     290             :     }
     291             : 
     292           0 :     nsGenericHTMLElement* el = nsGenericHTMLElement::FromContent(node);
     293           0 :     if (el) {
     294           0 :       const nsAttrValue* val = el->GetParsedAttr(nsGkAtoms::name);
     295           0 :       if (val && val->Type() == nsAttrValue::eAtom) {
     296           0 :         nsIAtom* nameAtom = val->GetAtomValue();
     297           0 :         MOZ_ASSERT(nameAtom != nsGkAtoms::_empty,
     298             :                    "Empty names don't get atomized");
     299           0 :         nsDependentAtomString nameStr(nameAtom);
     300           0 :         if (!aNames.Contains(nameStr)) {
     301           0 :           aNames.AppendElement(nameStr);
     302             :         }
     303             :       }
     304             :     }
     305             :   }
     306           0 : }
     307             : 
     308             : 
     309             : NS_IMETHODIMP
     310           0 : TableRowsCollection::NamedItem(const nsAString& aName,
     311             :                                nsIDOMNode** aReturn)
     312             : {
     313             :   bool found;
     314           0 :   nsISupports* node = GetFirstNamedElement(aName, found);
     315           0 :   if (!node) {
     316           0 :     *aReturn = nullptr;
     317             : 
     318           0 :     return NS_OK;
     319             :   }
     320             : 
     321           0 :   return CallQueryInterface(node, aReturn);
     322             : }
     323             : 
     324             : NS_IMETHODIMP
     325           0 : TableRowsCollection::ParentDestroyed()
     326             : {
     327           0 :   CleanUp();
     328           0 :   return NS_OK;
     329             : }
     330             : 
     331             : bool
     332           0 : TableRowsCollection::InterestingContainer(nsIContent* aContainer)
     333             : {
     334           0 :   return mParent && aContainer &&
     335           0 :     (aContainer == mParent ||
     336           0 :      (aContainer->GetParent() == mParent &&
     337           0 :       aContainer->IsAnyOfHTMLElements(nsGkAtoms::thead,
     338             :                                       nsGkAtoms::tbody,
     339           0 :                                       nsGkAtoms::tfoot)));
     340             : }
     341             : 
     342             : bool
     343           0 : TableRowsCollection::IsAppropriateRow(nsIAtom* aSection, nsIContent* aContent)
     344             : {
     345           0 :   if (!aContent->IsHTMLElement(nsGkAtoms::tr)) {
     346           0 :     return false;
     347             :   }
     348             :   // If it's in the root, then we consider it to be in a tbody.
     349           0 :   nsIContent* parent = aContent->GetParent();
     350           0 :   if (aSection == nsGkAtoms::tbody && parent == mParent) {
     351           0 :     return true;
     352             :   }
     353           0 :   return parent->IsHTMLElement(aSection);
     354             : }
     355             : 
     356             : nsIContent*
     357           0 : TableRowsCollection::PreviousRow(nsIAtom* aSection, nsIContent* aCurrent)
     358             : {
     359             :   // Keep going backwards until we've found a `tr` element. We want to always
     360             :   // run at least once, as we don't want to find ourselves.
     361             :   //
     362             :   // Each spin of the loop we step backwards one element. If we're at the top of
     363             :   // a section, we step out of it into the root, and if we step onto a section
     364             :   // matching `aSection`, we step into it. We keep spinning the loop until
     365             :   // either we reach the first element in mParent, or find a <tr> in an
     366             :   // appropriate section.
     367           0 :   nsIContent* prev = aCurrent;
     368           0 :   do {
     369           0 :     nsIContent* parent = prev->GetParent();
     370           0 :     prev = prev->GetPreviousSibling();
     371             : 
     372             :     // Ascend out of any sections we're currently in, if we've run out of
     373             :     // elements.
     374           0 :     if (!prev && parent != mParent) {
     375           0 :       prev = parent->GetPreviousSibling();
     376             :     }
     377             : 
     378             :     // Descend into a section if we stepped onto one.
     379           0 :     if (prev && prev->GetParent() == mParent && prev->IsHTMLElement(aSection)) {
     380           0 :       prev = prev->GetLastChild();
     381             :     }
     382           0 :   } while (prev && !IsAppropriateRow(aSection, prev));
     383           0 :   return prev;
     384             : }
     385             : 
     386             : int32_t
     387           0 : TableRowsCollection::HandleInsert(nsIContent* aContainer,
     388             :                                   nsIContent* aChild,
     389             :                                   int32_t aIndexGuess)
     390             : {
     391           0 :   if (!nsContentUtils::IsInSameAnonymousTree(mParent, aChild)) {
     392           0 :     return aIndexGuess; // Nothing inserted, guess hasn't changed.
     393             :   }
     394             : 
     395             :   // If we're adding a section to the root, add each of the rows in that section
     396             :   // individually.
     397           0 :   if (aContainer == mParent &&
     398           0 :       aChild->IsAnyOfHTMLElements(nsGkAtoms::thead,
     399             :                                   nsGkAtoms::tbody,
     400             :                                   nsGkAtoms::tfoot)) {
     401             :     // If we're entering a tbody, we can persist the index guess we were passed,
     402             :     // as the newly added items are in the same section as us, however, if we're
     403             :     // entering thead or tfoot we will have to re-scan.
     404           0 :     bool isTBody = aChild->IsHTMLElement(nsGkAtoms::tbody);
     405           0 :     int32_t indexGuess = isTBody ? aIndexGuess : -1;
     406             : 
     407           0 :     for (nsIContent* inner = aChild->GetFirstChild();
     408           0 :          inner; inner = inner->GetNextSibling()) {
     409           0 :       indexGuess = HandleInsert(aChild, inner, indexGuess);
     410             :     }
     411             : 
     412           0 :     return isTBody ? indexGuess : -1;
     413             :   }
     414           0 :   if (!aChild->IsHTMLElement(nsGkAtoms::tr)) {
     415           0 :     return aIndexGuess; // Nothing inserted, guess hasn't changed.
     416             :   }
     417             : 
     418             :   // We should have only been passed an insertion from an interesting container,
     419             :   // so we can get the container we're inserting to fairly easily.
     420           0 :   nsIAtom* section = aContainer == mParent
     421           0 :     ? nsGkAtoms::tbody
     422           0 :     : aContainer->NodeInfo()->NameAtom();
     423             : 
     424             :   // Determine the default index we would to insert after if we don't find any
     425             :   // previous row, and offset our section boundaries based on the section we're
     426             :   // planning to insert into.
     427           0 :   size_t index = 0;
     428           0 :   if (section == nsGkAtoms::thead) {
     429           0 :     mBodyStart++;
     430           0 :     mFootStart++;
     431           0 :   } else if (section == nsGkAtoms::tbody) {
     432           0 :     index = mBodyStart;
     433           0 :     mFootStart++;
     434           0 :   } else if (section == nsGkAtoms::tfoot) {
     435           0 :     index = mFootStart;
     436             :   } else {
     437           0 :     MOZ_ASSERT(false, "section should be one of thead, tbody, or tfoot");
     438             :   }
     439             : 
     440             :   // If we already have an index guess, we can skip scanning for the previous row.
     441           0 :   if (aIndexGuess >= 0) {
     442           0 :     index = aIndexGuess;
     443             :   } else {
     444             :     // Find the previous row in the section we're inserting into. If we find it,
     445             :     // we can use it to override our insertion index. We don't need to modify
     446             :     // mBodyStart or mFootStart anymore, as they have already been correctly
     447             :     // updated based only on section.
     448           0 :     nsIContent* insertAfter = PreviousRow(section, aChild);
     449           0 :     if (insertAfter) {
     450             :       // NOTE: We want to ensure that appending elements is quick, so we search
     451             :       // from the end rather than from the beginning.
     452           0 :       index = mRows.LastIndexOf(insertAfter) + 1;
     453           0 :       MOZ_ASSERT(index != nsTArray<nsCOMPtr<nsIContent>>::NoIndex);
     454             :     }
     455             :   }
     456             : 
     457             : #ifdef DEBUG
     458             :   // Assert that we're inserting into the correct section.
     459           0 :   if (section == nsGkAtoms::thead) {
     460           0 :     MOZ_ASSERT(index < mBodyStart);
     461           0 :   } else if (section == nsGkAtoms::tbody) {
     462           0 :     MOZ_ASSERT(index >= mBodyStart);
     463           0 :     MOZ_ASSERT(index < mFootStart);
     464           0 :   } else if (section == nsGkAtoms::tfoot) {
     465           0 :     MOZ_ASSERT(index >= mFootStart);
     466           0 :     MOZ_ASSERT(index <= mRows.Length());
     467             :   }
     468             : 
     469           0 :   MOZ_ASSERT(mBodyStart <= mFootStart);
     470           0 :   MOZ_ASSERT(mFootStart <= mRows.Length() + 1);
     471             : #endif
     472             : 
     473           0 :   mRows.InsertElementAt(index, aChild);
     474           0 :   return index + 1;
     475             : }
     476             : 
     477             : // nsIMutationObserver
     478             : 
     479             : void
     480           0 : TableRowsCollection::ContentAppended(nsIDocument* aDocument,
     481             :                                      nsIContent* aContainer,
     482             :                                      nsIContent* aFirstNewContent,
     483             :                                      int32_t aNewIndexInContainer)
     484             : {
     485           0 :   if (!nsContentUtils::IsInSameAnonymousTree(mParent, aFirstNewContent) ||
     486           0 :       !InterestingContainer(aContainer)) {
     487           0 :     return;
     488             :   }
     489             : 
     490             :   // We usually can't guess where we need to start inserting, unless we're
     491             :   // appending into mParent, in which case we can provide the guess that we
     492             :   // should insert at the end of the body, which can help us avoid potentially
     493             :   // expensive work in the common case.
     494           0 :   int32_t indexGuess = mParent == aContainer ? mFootStart : -1;
     495             : 
     496             :   // Insert each of the newly added content one at a time. The indexGuess should
     497             :   // make insertions of a large number of elements cheaper.
     498           0 :   for (nsIContent* content = aFirstNewContent;
     499           0 :        content; content = content->GetNextSibling()) {
     500           0 :     indexGuess = HandleInsert(aContainer, content, indexGuess);
     501             :   }
     502             : }
     503             : 
     504             : void
     505           0 : TableRowsCollection::ContentInserted(nsIDocument* aDocument,
     506             :                                      nsIContent* aContainer,
     507             :                                      nsIContent* aChild,
     508             :                                      int32_t aIndexInContainer)
     509             : {
     510           0 :   if (!nsContentUtils::IsInSameAnonymousTree(mParent, aChild) ||
     511           0 :       !InterestingContainer(aContainer)) {
     512           0 :     return;
     513             :   }
     514             : 
     515           0 :   HandleInsert(aContainer, aChild);
     516             : }
     517             : 
     518             : void
     519           0 : TableRowsCollection::ContentRemoved(nsIDocument* aDocument,
     520             :                                     nsIContent* aContainer,
     521             :                                     nsIContent* aChild,
     522             :                                     int32_t aIndexInContainer,
     523             :                                     nsIContent* aPreviousSibling)
     524             : {
     525           0 :   if (!nsContentUtils::IsInSameAnonymousTree(mParent, aChild) ||
     526           0 :       !InterestingContainer(aContainer)) {
     527           0 :     return;
     528             :   }
     529             : 
     530             :   // If the element being removed is a `tr`, we can just remove it from our
     531             :   // list. It shouldn't change the order of anything.
     532           0 :   if (aChild->IsHTMLElement(nsGkAtoms::tr)) {
     533           0 :     size_t index = mRows.IndexOf(aChild);
     534           0 :     if (index != nsTArray<nsCOMPtr<nsIContent>>::NoIndex) {
     535           0 :       mRows.RemoveElementAt(index);
     536           0 :       if (mBodyStart > index) {
     537           0 :         mBodyStart--;
     538             :       }
     539           0 :       if (mFootStart > index) {
     540           0 :         mFootStart--;
     541             :       }
     542             :     }
     543           0 :     return;
     544             :   }
     545             : 
     546             :   // If the element being removed is a `thead`, `tbody`, or `tfoot`, we can
     547             :   // remove any `tr`s in our list which have that element as its parent node. In
     548             :   // any other situation, the removal won't affect us, so we can ignore it.
     549           0 :   if (!aChild->IsAnyOfHTMLElements(nsGkAtoms::thead, nsGkAtoms::tbody, nsGkAtoms::tfoot)) {
     550           0 :     return;
     551             :   }
     552             : 
     553           0 :   size_t beforeLength = mRows.Length();
     554           0 :   mRows.RemoveElementsBy([&] (nsIContent* element) {
     555           0 :     return element->GetParent() == aChild;
     556           0 :   });
     557           0 :   size_t removed = beforeLength - mRows.Length();
     558           0 :   if (aChild->IsHTMLElement(nsGkAtoms::thead)) {
     559             :     // NOTE: Need to move both tbody and tfoot, as we removed from head.
     560           0 :     mBodyStart -= removed;
     561           0 :     mFootStart -= removed;
     562           0 :   } else if (aChild->IsHTMLElement(nsGkAtoms::tbody)) {
     563             :     // NOTE: Need to move tfoot, as we removed from body.
     564           0 :     mFootStart -= removed;
     565             :   }
     566             : }
     567             : 
     568             : void
     569           0 : TableRowsCollection::NodeWillBeDestroyed(const nsINode* aNode)
     570             : {
     571             :   // Set mInitialized to false so CleanUp doesn't try to remove our mutation
     572             :   // observer, as we're going away. CleanUp() will reset mInitialized to true as
     573             :   // it returns.
     574           0 :   mInitialized = false;
     575           0 :   CleanUp();
     576           0 : }
     577             : 
     578             : /* --------------------------- HTMLTableElement ---------------------------- */
     579             : 
     580           0 : HTMLTableElement::HTMLTableElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
     581             :   : nsGenericHTMLElement(aNodeInfo),
     582           0 :     mTableInheritedAttributes(nullptr)
     583             : {
     584           0 :   SetHasWeirdParserInsertionMode();
     585           0 : }
     586             : 
     587           0 : HTMLTableElement::~HTMLTableElement()
     588             : {
     589           0 :   if (mRows) {
     590           0 :     mRows->ParentDestroyed();
     591             :   }
     592           0 :   ReleaseInheritedAttributes();
     593           0 : }
     594             : 
     595             : JSObject*
     596           0 : HTMLTableElement::WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto)
     597             : {
     598           0 :   return HTMLTableElementBinding::Wrap(aCx, this, aGivenProto);
     599             : }
     600             : 
     601             : NS_IMPL_CYCLE_COLLECTION_CLASS(HTMLTableElement)
     602             : 
     603           0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(HTMLTableElement, nsGenericHTMLElement)
     604           0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK(mTBodies)
     605           0 :   if (tmp->mRows) {
     606           0 :     tmp->mRows->ParentDestroyed();
     607             :   }
     608           0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK(mRows)
     609           0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
     610           0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(HTMLTableElement,
     611             :                                                   nsGenericHTMLElement)
     612           0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTBodies)
     613           0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRows)
     614           0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
     615             : 
     616           0 : NS_IMPL_ADDREF_INHERITED(HTMLTableElement, Element)
     617           0 : NS_IMPL_RELEASE_INHERITED(HTMLTableElement, Element)
     618             : 
     619             : // QueryInterface implementation for HTMLTableElement
     620           0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(HTMLTableElement)
     621           0 : NS_INTERFACE_MAP_END_INHERITING(nsGenericHTMLElement)
     622             : 
     623             : 
     624           0 : NS_IMPL_ELEMENT_CLONE(HTMLTableElement)
     625             : 
     626             : 
     627             : // the DOM spec says border, cellpadding, cellSpacing are all "wstring"
     628             : // in fact, they are integers or they are meaningless.  so we store them
     629             : // here as ints.
     630             : 
     631             : nsIHTMLCollection*
     632           0 : HTMLTableElement::Rows()
     633             : {
     634           0 :   if (!mRows) {
     635           0 :     mRows = new TableRowsCollection(this);
     636             :   }
     637             : 
     638           0 :   return mRows;
     639             : }
     640             : 
     641             : nsIHTMLCollection*
     642           0 : HTMLTableElement::TBodies()
     643             : {
     644           0 :   if (!mTBodies) {
     645             :     // Not using NS_GetContentList because this should not be cached
     646             :     mTBodies = new nsContentList(this,
     647             :                                  kNameSpaceID_XHTML,
     648             :                                  nsGkAtoms::tbody,
     649             :                                  nsGkAtoms::tbody,
     650           0 :                                  false);
     651             :   }
     652             : 
     653           0 :   return mTBodies;
     654             : }
     655             : 
     656             : already_AddRefed<nsGenericHTMLElement>
     657           0 : HTMLTableElement::CreateTHead()
     658             : {
     659           0 :   RefPtr<nsGenericHTMLElement> head = GetTHead();
     660           0 :   if (!head) {
     661             :     // Create a new head rowgroup.
     662           0 :     RefPtr<mozilla::dom::NodeInfo> nodeInfo;
     663           0 :     nsContentUtils::QNameChanged(mNodeInfo, nsGkAtoms::thead,
     664           0 :                                  getter_AddRefs(nodeInfo));
     665             : 
     666           0 :     head = NS_NewHTMLTableSectionElement(nodeInfo.forget());
     667           0 :     if (!head) {
     668           0 :       return nullptr;
     669             :     }
     670             : 
     671           0 :     nsCOMPtr<nsIContent> refNode = nullptr;
     672           0 :     for (refNode = nsINode::GetFirstChild();
     673             :          refNode;
     674           0 :          refNode = refNode->GetNextSibling()) {
     675             : 
     676           0 :       if (refNode->IsHTMLElement() &&
     677           0 :           !refNode->IsHTMLElement(nsGkAtoms::caption) &&
     678           0 :           !refNode->IsHTMLElement(nsGkAtoms::colgroup)) {
     679           0 :         break;
     680             :       }
     681             :     }
     682             : 
     683           0 :     IgnoredErrorResult rv;
     684           0 :     nsINode::InsertBefore(*head, refNode, rv);
     685             :   }
     686           0 :   return head.forget();
     687             : }
     688             : 
     689             : void
     690           0 : HTMLTableElement::DeleteTHead()
     691             : {
     692           0 :   HTMLTableSectionElement* tHead = GetTHead();
     693           0 :   if (tHead) {
     694           0 :     mozilla::ErrorResult rv;
     695           0 :     nsINode::RemoveChild(*tHead, rv);
     696           0 :     MOZ_ASSERT(!rv.Failed());
     697             :   }
     698           0 : }
     699             : 
     700             : already_AddRefed<nsGenericHTMLElement>
     701           0 : HTMLTableElement::CreateTFoot()
     702             : {
     703           0 :   RefPtr<nsGenericHTMLElement> foot = GetTFoot();
     704           0 :   if (!foot) {
     705             :     // create a new foot rowgroup
     706           0 :     RefPtr<mozilla::dom::NodeInfo> nodeInfo;
     707           0 :     nsContentUtils::QNameChanged(mNodeInfo, nsGkAtoms::tfoot,
     708           0 :                                  getter_AddRefs(nodeInfo));
     709             : 
     710           0 :     foot = NS_NewHTMLTableSectionElement(nodeInfo.forget());
     711           0 :     if (!foot) {
     712           0 :       return nullptr;
     713             :     }
     714           0 :     AppendChildTo(foot, true);
     715             :   }
     716             : 
     717           0 :   return foot.forget();
     718             : }
     719             : 
     720             : void
     721           0 : HTMLTableElement::DeleteTFoot()
     722             : {
     723           0 :   HTMLTableSectionElement* tFoot = GetTFoot();
     724           0 :   if (tFoot) {
     725           0 :     mozilla::ErrorResult rv;
     726           0 :     nsINode::RemoveChild(*tFoot, rv);
     727           0 :     MOZ_ASSERT(!rv.Failed());
     728             :   }
     729           0 : }
     730             : 
     731             : already_AddRefed<nsGenericHTMLElement>
     732           0 : HTMLTableElement::CreateCaption()
     733             : {
     734           0 :   RefPtr<nsGenericHTMLElement> caption = GetCaption();
     735           0 :   if (!caption) {
     736             :     // Create a new caption.
     737           0 :     RefPtr<mozilla::dom::NodeInfo> nodeInfo;
     738           0 :     nsContentUtils::QNameChanged(mNodeInfo, nsGkAtoms::caption,
     739           0 :                                  getter_AddRefs(nodeInfo));
     740             : 
     741           0 :     caption = NS_NewHTMLTableCaptionElement(nodeInfo.forget());
     742           0 :     if (!caption) {
     743           0 :       return nullptr;
     744             :     }
     745             : 
     746           0 :     IgnoredErrorResult rv;
     747           0 :     nsCOMPtr<nsINode> firsChild = nsINode::GetFirstChild();
     748           0 :     nsINode::InsertBefore(*caption, firsChild, rv);
     749             :   }
     750           0 :   return caption.forget();
     751             : }
     752             : 
     753             : void
     754           0 : HTMLTableElement::DeleteCaption()
     755             : {
     756           0 :   HTMLTableCaptionElement* caption = GetCaption();
     757           0 :   if (caption) {
     758           0 :     mozilla::ErrorResult rv;
     759           0 :     nsINode::RemoveChild(*caption, rv);
     760           0 :     MOZ_ASSERT(!rv.Failed());
     761             :   }
     762           0 : }
     763             : 
     764             : already_AddRefed<nsGenericHTMLElement>
     765           0 : HTMLTableElement::CreateTBody()
     766             : {
     767             :   RefPtr<mozilla::dom::NodeInfo> nodeInfo =
     768           0 :     OwnerDoc()->NodeInfoManager()->GetNodeInfo(nsGkAtoms::tbody, nullptr,
     769             :                                                kNameSpaceID_XHTML,
     770           0 :                                                nsIDOMNode::ELEMENT_NODE);
     771           0 :   MOZ_ASSERT(nodeInfo);
     772             : 
     773             :   RefPtr<nsGenericHTMLElement> newBody =
     774           0 :     NS_NewHTMLTableSectionElement(nodeInfo.forget());
     775           0 :   MOZ_ASSERT(newBody);
     776             : 
     777           0 :   nsCOMPtr<nsIContent> referenceNode = nullptr;
     778           0 :   for (nsIContent* child = nsINode::GetLastChild();
     779           0 :        child;
     780           0 :        child = child->GetPreviousSibling()) {
     781           0 :     if (child->IsHTMLElement(nsGkAtoms::tbody)) {
     782           0 :       referenceNode = child->GetNextSibling();
     783           0 :       break;
     784             :     }
     785             :   }
     786             : 
     787           0 :   IgnoredErrorResult rv;
     788           0 :   nsINode::InsertBefore(*newBody, referenceNode, rv);
     789             : 
     790           0 :   return newBody.forget();
     791             : }
     792             : 
     793             : already_AddRefed<nsGenericHTMLElement>
     794           0 : HTMLTableElement::InsertRow(int32_t aIndex, ErrorResult& aError)
     795             : {
     796             :   /* get the ref row at aIndex
     797             :      if there is one,
     798             :        get its parent
     799             :        insert the new row just before the ref row
     800             :      else
     801             :        get the first row group
     802             :        insert the new row as its first child
     803             :   */
     804           0 :   if (aIndex < -1) {
     805           0 :     aError.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
     806           0 :     return nullptr;
     807             :   }
     808             : 
     809           0 :   nsIHTMLCollection* rows = Rows();
     810           0 :   uint32_t rowCount = rows->Length();
     811           0 :   if ((uint32_t)aIndex > rowCount && aIndex != -1) {
     812           0 :     aError.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
     813           0 :     return nullptr;
     814             :   }
     815             : 
     816             :   // use local variable refIndex so we can remember original aIndex
     817           0 :   uint32_t refIndex = (uint32_t)aIndex;
     818             : 
     819           0 :   RefPtr<nsGenericHTMLElement> newRow;
     820           0 :   if (rowCount > 0) {
     821           0 :     if (refIndex == rowCount || aIndex == -1) {
     822             :       // we set refIndex to the last row so we can get the last row's
     823             :       // parent we then do an AppendChild below if (rowCount<aIndex)
     824             : 
     825           0 :       refIndex = rowCount - 1;
     826             :     }
     827             : 
     828           0 :     RefPtr<Element> refRow = rows->Item(refIndex);
     829           0 :     nsCOMPtr<nsINode> parent = refRow->GetParentNode();
     830             : 
     831             :     // create the row
     832           0 :     RefPtr<mozilla::dom::NodeInfo> nodeInfo;
     833           0 :     nsContentUtils::QNameChanged(mNodeInfo, nsGkAtoms::tr,
     834           0 :                                  getter_AddRefs(nodeInfo));
     835             : 
     836           0 :     newRow = NS_NewHTMLTableRowElement(nodeInfo.forget());
     837             : 
     838           0 :     if (newRow) {
     839             :       // If aIndex is -1 or equal to the number of rows, the new row
     840             :       // is appended.
     841           0 :       if (aIndex == -1 || uint32_t(aIndex) == rowCount) {
     842           0 :         parent->AppendChild(*newRow, aError);
     843             :       } else {
     844             :         // insert the new row before the reference row we found above
     845           0 :         parent->InsertBefore(*newRow, refRow, aError);
     846             :       }
     847             : 
     848           0 :       if (aError.Failed()) {
     849           0 :         return nullptr;
     850             :       }
     851             :     }
     852             :   } else {
     853             :     // the row count was 0, so
     854             :     // find the last row group and insert there as first child
     855           0 :     nsCOMPtr<nsIContent> rowGroup;
     856           0 :     for (nsIContent* child = nsINode::GetLastChild();
     857           0 :          child;
     858           0 :          child = child->GetPreviousSibling()) {
     859           0 :       if (child->IsHTMLElement(nsGkAtoms::tbody)) {
     860           0 :         rowGroup = child;
     861           0 :         break;
     862             :       }
     863             :     }
     864             : 
     865           0 :     if (!rowGroup) { // need to create a TBODY
     866           0 :       RefPtr<mozilla::dom::NodeInfo> nodeInfo;
     867           0 :       nsContentUtils::QNameChanged(mNodeInfo, nsGkAtoms::tbody,
     868           0 :                                    getter_AddRefs(nodeInfo));
     869             : 
     870           0 :       rowGroup = NS_NewHTMLTableSectionElement(nodeInfo.forget());
     871           0 :       if (rowGroup) {
     872           0 :         aError = AppendChildTo(rowGroup, true);
     873           0 :         if (aError.Failed()) {
     874           0 :           return nullptr;
     875             :         }
     876             :       }
     877             :     }
     878             : 
     879           0 :     if (rowGroup) {
     880           0 :       RefPtr<mozilla::dom::NodeInfo> nodeInfo;
     881           0 :       nsContentUtils::QNameChanged(mNodeInfo, nsGkAtoms::tr,
     882           0 :                                    getter_AddRefs(nodeInfo));
     883             : 
     884           0 :       newRow = NS_NewHTMLTableRowElement(nodeInfo.forget());
     885           0 :       if (newRow) {
     886             :         HTMLTableSectionElement* section =
     887           0 :           static_cast<HTMLTableSectionElement*>(rowGroup.get());
     888           0 :         nsIHTMLCollection* rows = section->Rows();
     889           0 :         nsCOMPtr<nsINode> refNode = rows->Item(0);
     890           0 :         rowGroup->InsertBefore(*newRow, refNode, aError);
     891             :       }
     892             :     }
     893             :   }
     894             : 
     895           0 :   return newRow.forget();
     896             : }
     897             : 
     898             : void
     899           0 : HTMLTableElement::DeleteRow(int32_t aIndex, ErrorResult& aError)
     900             : {
     901           0 :   if (aIndex < -1) {
     902           0 :     aError.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
     903           0 :     return;
     904             :   }
     905             : 
     906           0 :   nsIHTMLCollection* rows = Rows();
     907             :   uint32_t refIndex;
     908           0 :   if (aIndex == -1) {
     909           0 :     refIndex = rows->Length();
     910           0 :     if (refIndex == 0) {
     911           0 :       return;
     912             :     }
     913             : 
     914           0 :     --refIndex;
     915             :   } else {
     916           0 :     refIndex = (uint32_t)aIndex;
     917             :   }
     918             : 
     919           0 :   nsCOMPtr<nsIContent> row = rows->Item(refIndex);
     920           0 :   if (!row) {
     921           0 :     aError.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
     922           0 :     return;
     923             :   }
     924             : 
     925           0 :   row->RemoveFromParent();
     926             : }
     927             : 
     928             : bool
     929           0 : HTMLTableElement::ParseAttribute(int32_t aNamespaceID,
     930             :                                  nsIAtom* aAttribute,
     931             :                                  const nsAString& aValue,
     932             :                                  nsAttrValue& aResult)
     933             : {
     934             :   /* ignore summary, just a string */
     935           0 :   if (aNamespaceID == kNameSpaceID_None) {
     936           0 :     if (aAttribute == nsGkAtoms::cellspacing ||
     937           0 :         aAttribute == nsGkAtoms::cellpadding ||
     938           0 :         aAttribute == nsGkAtoms::border) {
     939           0 :       return aResult.ParseNonNegativeIntValue(aValue);
     940             :     }
     941           0 :     if (aAttribute == nsGkAtoms::height) {
     942           0 :       return aResult.ParseSpecialIntValue(aValue);
     943             :     }
     944           0 :     if (aAttribute == nsGkAtoms::width) {
     945           0 :       if (aResult.ParseSpecialIntValue(aValue)) {
     946             :         // treat 0 width as auto
     947           0 :         nsAttrValue::ValueType type = aResult.Type();
     948           0 :         return !((type == nsAttrValue::eInteger &&
     949           0 :                   aResult.GetIntegerValue() == 0) ||
     950           0 :                  (type == nsAttrValue::ePercent &&
     951           0 :                   aResult.GetPercentValue() == 0.0f));
     952             :       }
     953           0 :       return false;
     954             :     }
     955             : 
     956           0 :     if (aAttribute == nsGkAtoms::align) {
     957           0 :       return ParseTableHAlignValue(aValue, aResult);
     958             :     }
     959           0 :     if (aAttribute == nsGkAtoms::bgcolor ||
     960           0 :         aAttribute == nsGkAtoms::bordercolor) {
     961           0 :       return aResult.ParseColor(aValue);
     962             :     }
     963           0 :     if (aAttribute == nsGkAtoms::hspace ||
     964           0 :         aAttribute == nsGkAtoms::vspace) {
     965           0 :       return aResult.ParseIntWithBounds(aValue, 0);
     966             :     }
     967             :   }
     968             : 
     969           0 :   return nsGenericHTMLElement::ParseBackgroundAttribute(aNamespaceID,
     970             :                                                         aAttribute, aValue,
     971           0 :                                                         aResult) ||
     972           0 :          nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
     973           0 :                                               aResult);
     974             : }
     975             : 
     976             : 
     977             : 
     978             : void
     979           0 : HTMLTableElement::MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
     980             :                                         GenericSpecifiedValues* aData)
     981             : {
     982             :   // XXX Bug 211636:  This function is used by a single style rule
     983             :   // that's used to match two different type of elements -- tables, and
     984             :   // table cells.  (nsHTMLTableCellElement overrides
     985             :   // WalkContentStyleRules so that this happens.)  This violates the
     986             :   // nsIStyleRule contract, since it's the same style rule object doing
     987             :   // the mapping in two different ways.  It's also incorrect since it's
     988             :   // testing the display type of the style context rather than checking
     989             :   // which *element* it's matching (style rules should not stop matching
     990             :   // when the display type is changed).
     991             : 
     992           0 :   nsPresContext* presContext = aData->PresContext();
     993           0 :   nsCompatibility mode = presContext->CompatibilityMode();
     994             : 
     995           0 :   if (aData->ShouldComputeStyleStruct(NS_STYLE_INHERIT_BIT(TableBorder))) {
     996             :     // cellspacing
     997           0 :     const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::cellspacing);
     998           0 :     if (value && value->Type() == nsAttrValue::eInteger &&
     999           0 :         !aData->PropertyIsSet(eCSSProperty_border_spacing)) {
    1000           0 :       aData->SetPixelValue(eCSSProperty_border_spacing, float(value->GetIntegerValue()));
    1001             :     }
    1002             :   }
    1003           0 :   if (aData->ShouldComputeStyleStruct(NS_STYLE_INHERIT_BIT(Margin))) {
    1004             :     // align; Check for enumerated type (it may be another type if
    1005             :     // illegal)
    1006           0 :     const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::align);
    1007             : 
    1008           0 :     if (value && value->Type() == nsAttrValue::eEnum) {
    1009           0 :       if (value->GetEnumValue() == NS_STYLE_TEXT_ALIGN_CENTER ||
    1010           0 :           value->GetEnumValue() == NS_STYLE_TEXT_ALIGN_MOZ_CENTER) {
    1011           0 :         aData->SetAutoValueIfUnset(eCSSProperty_margin_left);
    1012           0 :         aData->SetAutoValueIfUnset(eCSSProperty_margin_right);
    1013             :       }
    1014             :     }
    1015             : 
    1016             :     // hspace is mapped into left and right margin,
    1017             :     // vspace is mapped into top and bottom margins
    1018             :     // - *** Quirks Mode only ***
    1019           0 :     if (eCompatibility_NavQuirks == mode) {
    1020           0 :       value = aAttributes->GetAttr(nsGkAtoms::hspace);
    1021             : 
    1022           0 :       if (value && value->Type() == nsAttrValue::eInteger) {
    1023           0 :         aData->SetPixelValueIfUnset(eCSSProperty_margin_left, (float)value->GetIntegerValue());
    1024           0 :         aData->SetPixelValueIfUnset(eCSSProperty_margin_right, (float)value->GetIntegerValue());
    1025             :       }
    1026             : 
    1027           0 :       value = aAttributes->GetAttr(nsGkAtoms::vspace);
    1028             : 
    1029           0 :       if (value && value->Type() == nsAttrValue::eInteger) {
    1030           0 :         aData->SetPixelValueIfUnset(eCSSProperty_margin_top, (float)value->GetIntegerValue());
    1031           0 :         aData->SetPixelValueIfUnset(eCSSProperty_margin_bottom, (float)value->GetIntegerValue());
    1032             :       }
    1033             :     }
    1034             :   }
    1035           0 :   if (aData->ShouldComputeStyleStruct(NS_STYLE_INHERIT_BIT(Border))) {
    1036             :     // bordercolor
    1037           0 :     const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::bordercolor);
    1038             :     nscolor color;
    1039           0 :     if (value && presContext->UseDocumentColors() &&
    1040           0 :         value->GetColorValue(color)) {
    1041           0 :       aData->SetColorValueIfUnset(eCSSProperty_border_top_color, color);
    1042           0 :       aData->SetColorValueIfUnset(eCSSProperty_border_left_color, color);
    1043           0 :       aData->SetColorValueIfUnset(eCSSProperty_border_bottom_color, color);
    1044           0 :       aData->SetColorValueIfUnset(eCSSProperty_border_right_color, color);
    1045             :     }
    1046             : 
    1047             :     // border
    1048           0 :     const nsAttrValue* borderValue = aAttributes->GetAttr(nsGkAtoms::border);
    1049           0 :     if (borderValue) {
    1050             :       // border = 1 pixel default
    1051           0 :       int32_t borderThickness = 1;
    1052             : 
    1053           0 :       if (borderValue->Type() == nsAttrValue::eInteger)
    1054           0 :         borderThickness = borderValue->GetIntegerValue();
    1055             : 
    1056             :       // by default, set all border sides to the specified width
    1057           0 :       aData->SetPixelValueIfUnset(eCSSProperty_border_top_width, (float)borderThickness);
    1058           0 :       aData->SetPixelValueIfUnset(eCSSProperty_border_left_width, (float)borderThickness);
    1059           0 :       aData->SetPixelValueIfUnset(eCSSProperty_border_bottom_width, (float)borderThickness);
    1060           0 :       aData->SetPixelValueIfUnset(eCSSProperty_border_right_width, (float)borderThickness);
    1061             :     }
    1062             :   }
    1063           0 :   nsGenericHTMLElement::MapImageSizeAttributesInto(aAttributes, aData);
    1064           0 :   nsGenericHTMLElement::MapBackgroundAttributesInto(aAttributes, aData);
    1065           0 :   nsGenericHTMLElement::MapCommonAttributesInto(aAttributes, aData);
    1066           0 : }
    1067             : 
    1068             : NS_IMETHODIMP_(bool)
    1069           0 : HTMLTableElement::IsAttributeMapped(const nsIAtom* aAttribute) const
    1070             : {
    1071             :   static const MappedAttributeEntry attributes[] = {
    1072             :     { &nsGkAtoms::cellpadding },
    1073             :     { &nsGkAtoms::cellspacing },
    1074             :     { &nsGkAtoms::border },
    1075             :     { &nsGkAtoms::width },
    1076             :     { &nsGkAtoms::height },
    1077             :     { &nsGkAtoms::hspace },
    1078             :     { &nsGkAtoms::vspace },
    1079             : 
    1080             :     { &nsGkAtoms::bordercolor },
    1081             : 
    1082             :     { &nsGkAtoms::align },
    1083             :     { nullptr }
    1084             :   };
    1085             : 
    1086             :   static const MappedAttributeEntry* const map[] = {
    1087             :     attributes,
    1088             :     sCommonAttributeMap,
    1089             :     sBackgroundAttributeMap,
    1090             :   };
    1091             : 
    1092           0 :   return FindAttributeDependence(aAttribute, map);
    1093             : }
    1094             : 
    1095             : nsMapRuleToAttributesFunc
    1096           0 : HTMLTableElement::GetAttributeMappingFunction() const
    1097             : {
    1098           0 :   return &MapAttributesIntoRule;
    1099             : }
    1100             : 
    1101             : static void
    1102           0 : MapInheritedTableAttributesIntoRule(const nsMappedAttributes* aAttributes,
    1103             :                                     GenericSpecifiedValues* aData)
    1104             : {
    1105           0 :   if (aData->ShouldComputeStyleStruct(NS_STYLE_INHERIT_BIT(Padding))) {
    1106           0 :     const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::cellpadding);
    1107           0 :     if (value && value->Type() == nsAttrValue::eInteger) {
    1108             :       // We have cellpadding.  This will override our padding values if we
    1109             :       // don't have any set.
    1110           0 :       float pad = float(value->GetIntegerValue());
    1111             : 
    1112           0 :       aData->SetPixelValueIfUnset(eCSSProperty_padding_top, pad);
    1113           0 :       aData->SetPixelValueIfUnset(eCSSProperty_padding_right, pad);
    1114           0 :       aData->SetPixelValueIfUnset(eCSSProperty_padding_bottom, pad);
    1115           0 :       aData->SetPixelValueIfUnset(eCSSProperty_padding_left, pad);
    1116             :     }
    1117             :   }
    1118           0 : }
    1119             : 
    1120             : nsMappedAttributes*
    1121           0 : HTMLTableElement::GetAttributesMappedForCell()
    1122             : {
    1123           0 :   return mTableInheritedAttributes;
    1124             : }
    1125             : 
    1126             : void
    1127           0 : HTMLTableElement::BuildInheritedAttributes()
    1128             : {
    1129           0 :   NS_ASSERTION(!mTableInheritedAttributes,
    1130             :                "potential leak, plus waste of work");
    1131           0 :   MOZ_ASSERT(NS_IsMainThread());
    1132           0 :   nsIDocument *document = GetComposedDoc();
    1133           0 :   nsHTMLStyleSheet* sheet = document ?
    1134           0 :                               document->GetAttributeStyleSheet() : nullptr;
    1135           0 :   RefPtr<nsMappedAttributes> newAttrs;
    1136           0 :   if (sheet) {
    1137           0 :     const nsAttrValue* value = mAttrsAndChildren.GetAttr(nsGkAtoms::cellpadding);
    1138           0 :     if (value) {
    1139             :       RefPtr<nsMappedAttributes> modifiableMapped = new
    1140           0 :       nsMappedAttributes(sheet, MapInheritedTableAttributesIntoRule);
    1141             : 
    1142           0 :       if (modifiableMapped) {
    1143           0 :         nsAttrValue val(*value);
    1144             :         bool oldValueSet;
    1145           0 :         modifiableMapped->SetAndSwapAttr(nsGkAtoms::cellpadding, val,
    1146           0 :                                          &oldValueSet);
    1147             :       }
    1148           0 :       newAttrs = sheet->UniqueMappedAttributes(modifiableMapped);
    1149           0 :       NS_ASSERTION(newAttrs, "out of memory, but handling gracefully");
    1150             : 
    1151           0 :       if (newAttrs != modifiableMapped) {
    1152             :         // Reset the stylesheet of modifiableMapped so that it doesn't
    1153             :         // spend time trying to remove itself from the hash.  There is no
    1154             :         // risk that modifiableMapped is in the hash since we created
    1155             :         // it ourselves and it didn't come from the stylesheet (in which
    1156             :         // case it would not have been modifiable).
    1157           0 :         modifiableMapped->DropStyleSheetReference();
    1158             :       }
    1159             :     }
    1160           0 :     mTableInheritedAttributes = newAttrs;
    1161           0 :     NS_IF_ADDREF(mTableInheritedAttributes);
    1162             :   }
    1163           0 : }
    1164             : 
    1165             : void
    1166           0 : HTMLTableElement::ReleaseInheritedAttributes()
    1167             : {
    1168           0 :   NS_IF_RELEASE(mTableInheritedAttributes);
    1169           0 : }
    1170             : 
    1171             : nsresult
    1172           0 : HTMLTableElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
    1173             :                              nsIContent* aBindingParent,
    1174             :                              bool aCompileEventHandlers)
    1175             : {
    1176           0 :   ReleaseInheritedAttributes();
    1177           0 :   nsresult rv = nsGenericHTMLElement::BindToTree(aDocument, aParent,
    1178             :                                                 aBindingParent,
    1179           0 :                                                 aCompileEventHandlers);
    1180           0 :   NS_ENSURE_SUCCESS(rv, rv);
    1181           0 :   BuildInheritedAttributes();
    1182           0 :   return NS_OK;
    1183             : }
    1184             : 
    1185             : void
    1186           0 : HTMLTableElement::UnbindFromTree(bool aDeep, bool aNullParent)
    1187             : {
    1188           0 :   ReleaseInheritedAttributes();
    1189           0 :   nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent);
    1190           0 : }
    1191             : 
    1192             : nsresult
    1193           0 : HTMLTableElement::BeforeSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
    1194             :                                 const nsAttrValueOrString* aValue,
    1195             :                                 bool aNotify)
    1196             : {
    1197           0 :   if (aName == nsGkAtoms::cellpadding && aNameSpaceID == kNameSpaceID_None) {
    1198           0 :     ReleaseInheritedAttributes();
    1199             :   }
    1200           0 :   return nsGenericHTMLElement::BeforeSetAttr(aNameSpaceID, aName, aValue,
    1201           0 :                                              aNotify);
    1202             : }
    1203             : 
    1204             : nsresult
    1205           0 : HTMLTableElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
    1206             :                                const nsAttrValue* aValue,
    1207             :                                const nsAttrValue* aOldValue, bool aNotify)
    1208             : {
    1209           0 :   if (aName == nsGkAtoms::cellpadding && aNameSpaceID == kNameSpaceID_None) {
    1210           0 :     BuildInheritedAttributes();
    1211             :   }
    1212           0 :   return nsGenericHTMLElement::AfterSetAttr(aNameSpaceID, aName, aValue,
    1213           0 :                                             aOldValue, aNotify);
    1214             : }
    1215             : 
    1216             : } // namespace dom
    1217             : } // namespace mozilla

Generated by: LCOV version 1.13