LCOV - code coverage report
Current view: directory - content/base/src - nsAttrAndChildArray.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 366 226 61.7 %
Date: 2012-06-02 Functions: 33 25 75.8 %

       1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2                 : /* ***** BEGIN LICENSE BLOCK *****
       3                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       4                 :  *
       5                 :  * The contents of this file are subject to the Mozilla Public License Version
       6                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       7                 :  * the License. You may obtain a copy of the License at
       8                 :  * http://www.mozilla.org/MPL/
       9                 :  *
      10                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      11                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      12                 :  * for the specific language governing rights and limitations under the
      13                 :  * License.
      14                 :  *
      15                 :  * The Original Code is mozilla.org code.
      16                 :  *
      17                 :  * The Initial Developer of the Original Code is
      18                 :  * IBM Corporation.
      19                 :  * Portions created by the Initial Developer are Copyright (C) 2003
      20                 :  * IBM Corporation. All Rights Reserved.
      21                 :  *
      22                 :  * Contributor(s):
      23                 :  *   IBM Corporation
      24                 :  *
      25                 :  * Alternatively, the contents of this file may be used under the terms of
      26                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      27                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      28                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      29                 :  * of those above. If you wish to allow use of your version of this file only
      30                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      31                 :  * use your version of this file under the terms of the MPL, indicate your
      32                 :  * decision by deleting the provisions above and replace them with the notice
      33                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      34                 :  * the provisions above, a recipient may use your version of this file under
      35                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      36                 :  *
      37                 :  * ***** END LICENSE BLOCK ***** */
      38                 : 
      39                 : /*
      40                 :  * Storage of the children and attributes of a DOM node; storage for
      41                 :  * the two is unified to minimize footprint.
      42                 :  */
      43                 : 
      44                 : #include "nsAttrAndChildArray.h"
      45                 : #include "nsMappedAttributeElement.h"
      46                 : #include "prmem.h"
      47                 : #include "prbit.h"
      48                 : #include "nsString.h"
      49                 : #include "nsHTMLStyleSheet.h"
      50                 : #include "nsRuleWalker.h"
      51                 : #include "nsMappedAttributes.h"
      52                 : #include "nsUnicharUtils.h"
      53                 : #include "nsAutoPtr.h"
      54                 : #include "nsContentUtils.h" // nsAutoScriptBlocker
      55                 : 
      56                 : /*
      57                 : CACHE_POINTER_SHIFT indicates how many steps to downshift the |this| pointer.
      58                 : It should be small enough to not cause collisions between adjecent arrays, and
      59                 : large enough to make sure that all indexes are used. The size below is based
      60                 : on the size of the smallest possible element (currently 24[*] bytes) which is
      61                 : the smallest distance between two nsAttrAndChildArray. 24/(2^_5_) is 0.75.
      62                 : This means that two adjacent nsAttrAndChildArrays will overlap one in 4 times.
      63                 : However not all elements will have enough children to get cached. And any
      64                 : allocator that doesn't return addresses aligned to 64 bytes will ensure that
      65                 : any index will get used.
      66                 : 
      67                 : [*] sizeof(nsGenericElement) + 4 bytes for nsIDOMElement vtable pointer.
      68                 : */
      69                 : 
      70                 : #define CACHE_POINTER_SHIFT 5
      71                 : #define CACHE_NUM_SLOTS 128
      72                 : #define CACHE_CHILD_LIMIT 10
      73                 : 
      74                 : #define CACHE_GET_INDEX(_array) \
      75                 :   ((NS_PTR_TO_INT32(_array) >> CACHE_POINTER_SHIFT) & \
      76                 :    (CACHE_NUM_SLOTS - 1))
      77                 : 
      78                 : struct IndexCacheSlot
      79                 : {
      80                 :   const nsAttrAndChildArray* array;
      81                 :   PRInt32 index;
      82                 : };
      83                 : 
      84                 : // This is inited to all zeroes since it's static. Though even if it wasn't
      85                 : // the worst thing that'd happen is a small inefficency if you'd get a false
      86                 : // positive cachehit.
      87                 : static IndexCacheSlot indexCache[CACHE_NUM_SLOTS];
      88                 : 
      89                 : static
      90                 : inline
      91                 : void
      92             102 : AddIndexToCache(const nsAttrAndChildArray* aArray, PRInt32 aIndex)
      93                 : {
      94             102 :   PRUint32 ix = CACHE_GET_INDEX(aArray);
      95             102 :   indexCache[ix].array = aArray;
      96             102 :   indexCache[ix].index = aIndex;
      97             102 : }
      98                 : 
      99                 : static
     100                 : inline
     101                 : PRInt32
     102             102 : GetIndexFromCache(const nsAttrAndChildArray* aArray)
     103                 : {
     104             102 :   PRUint32 ix = CACHE_GET_INDEX(aArray);
     105             102 :   return indexCache[ix].array == aArray ? indexCache[ix].index : -1;
     106                 : }
     107                 : 
     108                 : 
     109                 : /**
     110                 :  * Due to a compiler bug in VisualAge C++ for AIX, we need to return the 
     111                 :  * address of the first index into mBuffer here, instead of simply returning 
     112                 :  * mBuffer itself.
     113                 :  *
     114                 :  * See Bug 231104 for more information.
     115                 :  */
     116                 : #define ATTRS(_impl) \
     117                 :   reinterpret_cast<InternalAttr*>(&((_impl)->mBuffer[0]))
     118                 :   
     119                 : 
     120                 : #define NS_IMPL_EXTRA_SIZE \
     121                 :   ((sizeof(Impl) - sizeof(mImpl->mBuffer)) / sizeof(void*))
     122                 : 
     123           39306 : nsAttrAndChildArray::nsAttrAndChildArray()
     124           39306 :   : mImpl(nsnull)
     125                 : {
     126           39306 : }
     127                 : 
     128           39302 : nsAttrAndChildArray::~nsAttrAndChildArray()
     129                 : {
     130           39302 :   if (!mImpl) {
     131             598 :     return;
     132                 :   }
     133                 : 
     134           38704 :   Clear();
     135                 : 
     136           38704 :   PR_Free(mImpl);
     137           39302 : }
     138                 : 
     139                 : nsIContent*
     140          140721 : nsAttrAndChildArray::GetSafeChildAt(PRUint32 aPos) const
     141                 : {
     142          140721 :   if (aPos < ChildCount()) {
     143          140721 :     return ChildAt(aPos);
     144                 :   }
     145                 :   
     146               0 :   return nsnull;
     147                 : }
     148                 : 
     149                 : nsIContent * const *
     150             359 : nsAttrAndChildArray::GetChildArray(PRUint32* aChildCount) const
     151                 : {
     152             359 :   *aChildCount = ChildCount();
     153                 :   
     154             359 :   if (!*aChildCount) {
     155             309 :     return nsnull;
     156                 :   }
     157                 :   
     158              50 :   return reinterpret_cast<nsIContent**>(mImpl->mBuffer + AttrSlotsSize());
     159                 : }
     160                 : 
     161                 : nsresult
     162          111957 : nsAttrAndChildArray::InsertChildAt(nsIContent* aChild, PRUint32 aPos)
     163                 : {
     164          111957 :   NS_ASSERTION(aChild, "nullchild");
     165          111957 :   NS_ASSERTION(aPos <= ChildCount(), "out-of-bounds");
     166                 : 
     167          111957 :   PRUint32 offset = AttrSlotsSize();
     168          111957 :   PRUint32 childCount = ChildCount();
     169                 : 
     170          111957 :   NS_ENSURE_TRUE(childCount < ATTRCHILD_ARRAY_MAX_CHILD_COUNT,
     171                 :                  NS_ERROR_FAILURE);
     172                 : 
     173                 :   // First try to fit new child in existing childlist
     174          111957 :   if (mImpl && offset + childCount < mImpl->mBufferSize) {
     175           74131 :     void** pos = mImpl->mBuffer + offset + aPos;
     176           74131 :     if (childCount != aPos) {
     177               8 :       memmove(pos + 1, pos, (childCount - aPos) * sizeof(nsIContent*));
     178                 :     }
     179           74131 :     SetChildAtPos(pos, aChild, aPos, childCount);
     180                 : 
     181           74131 :     SetChildCount(childCount + 1);
     182                 : 
     183           74131 :     return NS_OK;
     184                 :   }
     185                 : 
     186                 :   // Try to fit new child in existing buffer by compressing attrslots
     187           37826 :   if (offset && !mImpl->mBuffer[offset - ATTRSIZE]) {
     188                 :     // Compress away all empty slots while we're at it. This might not be the
     189                 :     // optimal thing to do.
     190               0 :     PRUint32 attrCount = NonMappedAttrCount();
     191               0 :     void** newStart = mImpl->mBuffer + attrCount * ATTRSIZE;
     192               0 :     void** oldStart = mImpl->mBuffer + offset;
     193               0 :     memmove(newStart, oldStart, aPos * sizeof(nsIContent*));
     194               0 :     memmove(&newStart[aPos + 1], &oldStart[aPos],
     195               0 :             (childCount - aPos) * sizeof(nsIContent*));
     196               0 :     SetChildAtPos(newStart + aPos, aChild, aPos, childCount);
     197                 : 
     198               0 :     SetAttrSlotAndChildCount(attrCount, childCount + 1);
     199                 : 
     200               0 :     return NS_OK;
     201                 :   }
     202                 : 
     203                 :   // We can't fit in current buffer, Realloc time!
     204           37826 :   if (!GrowBy(1)) {
     205               0 :     return NS_ERROR_OUT_OF_MEMORY;
     206                 :   }
     207                 : 
     208           37826 :   void** pos = mImpl->mBuffer + offset + aPos;
     209           37826 :   if (childCount != aPos) {
     210               4 :     memmove(pos + 1, pos, (childCount - aPos) * sizeof(nsIContent*));
     211                 :   }
     212           37826 :   SetChildAtPos(pos, aChild, aPos, childCount);
     213                 : 
     214           37826 :   SetChildCount(childCount + 1);
     215                 :   
     216           37826 :   return NS_OK;
     217                 : }
     218                 : 
     219                 : void
     220            1612 : nsAttrAndChildArray::RemoveChildAt(PRUint32 aPos)
     221                 : {
     222                 :   // Just store the return value of TakeChildAt in an nsCOMPtr to
     223                 :   // trigger a release.
     224            1612 :   nsCOMPtr<nsIContent> child = TakeChildAt(aPos);
     225            1612 : }
     226                 : 
     227                 : already_AddRefed<nsIContent>
     228          111953 : nsAttrAndChildArray::TakeChildAt(PRUint32 aPos)
     229                 : {
     230          111953 :   NS_ASSERTION(aPos < ChildCount(), "out-of-bounds");
     231                 : 
     232          111953 :   PRUint32 childCount = ChildCount();
     233          111953 :   void** pos = mImpl->mBuffer + AttrSlotsSize() + aPos;
     234          111953 :   nsIContent* child = static_cast<nsIContent*>(*pos);
     235          111953 :   if (child->mPreviousSibling) {
     236           74800 :     child->mPreviousSibling->mNextSibling = child->mNextSibling;
     237                 :   }
     238          111953 :   if (child->mNextSibling) {
     239             122 :     child->mNextSibling->mPreviousSibling = child->mPreviousSibling;
     240                 :   }
     241          111953 :   child->mPreviousSibling = child->mNextSibling = nsnull;
     242                 : 
     243          111953 :   memmove(pos, pos + 1, (childCount - aPos - 1) * sizeof(nsIContent*));
     244          111953 :   SetChildCount(childCount - 1);
     245                 : 
     246          111953 :   return child;
     247                 : }
     248                 : 
     249                 : PRInt32
     250             628 : nsAttrAndChildArray::IndexOfChild(nsINode* aPossibleChild) const
     251                 : {
     252             628 :   if (!mImpl) {
     253               0 :     return -1;
     254                 :   }
     255             628 :   void** children = mImpl->mBuffer + AttrSlotsSize();
     256                 :   // Use signed here since we compare count to cursor which has to be signed
     257             628 :   PRInt32 i, count = ChildCount();
     258                 : 
     259             628 :   if (count >= CACHE_CHILD_LIMIT) {
     260             102 :     PRInt32 cursor = GetIndexFromCache(this);
     261                 :     // Need to compare to count here since we may have removed children since
     262                 :     // the index was added to the cache.
     263                 :     // We're also relying on that GetIndexFromCache returns -1 if no cached
     264                 :     // index was found.
     265             102 :     if (cursor >= count) {
     266               0 :       cursor = -1;
     267                 :     }
     268                 : 
     269                 :     // Seek outward from the last found index. |inc| will change sign every
     270                 :     // run through the loop. |sign| just exists to make sure the absolute
     271                 :     // value of |inc| increases each time through.
     272             102 :     PRInt32 inc = 1, sign = 1;
     273             308 :     while (cursor >= 0 && cursor < count) {
     274             190 :       if (children[cursor] == aPossibleChild) {
     275              86 :         AddIndexToCache(this, cursor);
     276                 : 
     277              86 :         return cursor;
     278                 :       }
     279                 : 
     280             104 :       cursor += inc;
     281             104 :       inc = -inc - sign;
     282             104 :       sign = -sign;
     283                 :     }
     284                 : 
     285                 :     // We ran into one 'edge'. Add inc to cursor once more to get back to
     286                 :     // the 'side' where we still need to search, then step in the |sign|
     287                 :     // direction.
     288              16 :     cursor += inc;
     289                 : 
     290              16 :     if (sign > 0) {
     291              21 :       for (; cursor < count; ++cursor) {
     292              21 :         if (children[cursor] == aPossibleChild) {
     293               5 :           AddIndexToCache(this, cursor);
     294                 : 
     295               5 :           return static_cast<PRInt32>(cursor);
     296                 :         }
     297                 :       }
     298                 :     }
     299                 :     else {
     300              40 :       for (; cursor >= 0; --cursor) {
     301              40 :         if (children[cursor] == aPossibleChild) {
     302              11 :           AddIndexToCache(this, cursor);
     303                 : 
     304              11 :           return static_cast<PRInt32>(cursor);
     305                 :         }
     306                 :       }
     307                 :     }
     308                 : 
     309                 :     // The child wasn't even in the remaining children
     310               0 :     return -1;
     311                 :   }
     312                 : 
     313            1135 :   for (i = 0; i < count; ++i) {
     314            1135 :     if (children[i] == aPossibleChild) {
     315             526 :       return static_cast<PRInt32>(i);
     316                 :     }
     317                 :   }
     318                 : 
     319               0 :   return -1;
     320                 : }
     321                 : 
     322                 : PRUint32
     323           71547 : nsAttrAndChildArray::AttrCount() const
     324                 : {
     325           71547 :   return NonMappedAttrCount() + MappedAttrCount();
     326                 : }
     327                 : 
     328                 : const nsAttrValue*
     329           10400 : nsAttrAndChildArray::GetAttr(nsIAtom* aLocalName, PRInt32 aNamespaceID) const
     330                 : {
     331           10400 :   PRUint32 i, slotCount = AttrSlotCount();
     332           10400 :   if (aNamespaceID == kNameSpaceID_None) {
     333                 :     // This should be the common case so lets make an optimized loop
     334           36529 :     for (i = 0; i < slotCount && AttrSlotIsTaken(i); ++i) {
     335           36240 :       if (ATTRS(mImpl)[i].mName.Equals(aLocalName)) {
     336            8866 :         return &ATTRS(mImpl)[i].mValue;
     337                 :       }
     338                 :     }
     339                 : 
     340             289 :     if (mImpl && mImpl->mMappedAttrs) {
     341               0 :       return mImpl->mMappedAttrs->GetAttr(aLocalName);
     342                 :     }
     343                 :   }
     344                 :   else {
     345            2410 :     for (i = 0; i < slotCount && AttrSlotIsTaken(i); ++i) {
     346            2407 :       if (ATTRS(mImpl)[i].mName.Equals(aLocalName, aNamespaceID)) {
     347            1242 :         return &ATTRS(mImpl)[i].mValue;
     348                 :       }
     349                 :     }
     350                 :   }
     351                 : 
     352             292 :   return nsnull;
     353                 : }
     354                 : 
     355                 : const nsAttrValue*
     356            1022 : nsAttrAndChildArray::AttrAt(PRUint32 aPos) const
     357                 : {
     358            1022 :   NS_ASSERTION(aPos < AttrCount(),
     359                 :                "out-of-bounds access in nsAttrAndChildArray");
     360                 : 
     361            1022 :   PRUint32 mapped = MappedAttrCount();
     362            1022 :   if (aPos < mapped) {
     363               0 :     return mImpl->mMappedAttrs->AttrAt(aPos);
     364                 :   }
     365                 : 
     366            1022 :   return &ATTRS(mImpl)[aPos - mapped].mValue;
     367                 : }
     368                 : 
     369                 : nsresult
     370            9771 : nsAttrAndChildArray::SetAndTakeAttr(nsIAtom* aLocalName, nsAttrValue& aValue)
     371                 : {
     372            9771 :   PRUint32 i, slotCount = AttrSlotCount();
     373           27420 :   for (i = 0; i < slotCount && AttrSlotIsTaken(i); ++i) {
     374           17649 :     if (ATTRS(mImpl)[i].mName.Equals(aLocalName)) {
     375               0 :       ATTRS(mImpl)[i].mValue.Reset();
     376               0 :       ATTRS(mImpl)[i].mValue.SwapValueWith(aValue);
     377                 : 
     378               0 :       return NS_OK;
     379                 :     }
     380                 :   }
     381                 : 
     382            9771 :   NS_ENSURE_TRUE(i < ATTRCHILD_ARRAY_MAX_ATTR_COUNT,
     383                 :                  NS_ERROR_FAILURE);
     384                 : 
     385            9771 :   if (i == slotCount && !AddAttrSlot()) {
     386               0 :     return NS_ERROR_OUT_OF_MEMORY;
     387                 :   }
     388                 : 
     389            9771 :   new (&ATTRS(mImpl)[i].mName) nsAttrName(aLocalName);
     390            9771 :   new (&ATTRS(mImpl)[i].mValue) nsAttrValue();
     391            9771 :   ATTRS(mImpl)[i].mValue.SwapValueWith(aValue);
     392                 : 
     393            9771 :   return NS_OK;
     394                 : }
     395                 : 
     396                 : nsresult
     397            1683 : nsAttrAndChildArray::SetAndTakeAttr(nsINodeInfo* aName, nsAttrValue& aValue)
     398                 : {
     399            1683 :   PRInt32 namespaceID = aName->NamespaceID();
     400            1683 :   nsIAtom* localName = aName->NameAtom();
     401            1683 :   if (namespaceID == kNameSpaceID_None) {
     402               0 :     return SetAndTakeAttr(localName, aValue);
     403                 :   }
     404                 : 
     405            1683 :   PRUint32 i, slotCount = AttrSlotCount();
     406            2307 :   for (i = 0; i < slotCount && AttrSlotIsTaken(i); ++i) {
     407             630 :     if (ATTRS(mImpl)[i].mName.Equals(localName, namespaceID)) {
     408               6 :       ATTRS(mImpl)[i].mName.SetTo(aName);
     409               6 :       ATTRS(mImpl)[i].mValue.Reset();
     410               6 :       ATTRS(mImpl)[i].mValue.SwapValueWith(aValue);
     411                 : 
     412               6 :       return NS_OK;
     413                 :     }
     414                 :   }
     415                 : 
     416            1677 :   NS_ENSURE_TRUE(i < ATTRCHILD_ARRAY_MAX_ATTR_COUNT,
     417                 :                  NS_ERROR_FAILURE);
     418                 : 
     419            1677 :   if (i == slotCount && !AddAttrSlot()) {
     420               0 :     return NS_ERROR_OUT_OF_MEMORY;
     421                 :   }
     422                 : 
     423            1677 :   new (&ATTRS(mImpl)[i].mName) nsAttrName(aName);
     424            1677 :   new (&ATTRS(mImpl)[i].mValue) nsAttrValue();
     425            1677 :   ATTRS(mImpl)[i].mValue.SwapValueWith(aValue);
     426                 : 
     427            1677 :   return NS_OK;
     428                 : }
     429                 : 
     430                 : 
     431                 : nsresult
     432               0 : nsAttrAndChildArray::RemoveAttrAt(PRUint32 aPos, nsAttrValue& aValue)
     433                 : {
     434               0 :   NS_ASSERTION(aPos < AttrCount(), "out-of-bounds");
     435                 : 
     436               0 :   PRUint32 mapped = MappedAttrCount();
     437               0 :   if (aPos < mapped) {
     438               0 :     if (mapped == 1) {
     439                 :       // We're removing the last mapped attribute.  Can't swap in this
     440                 :       // case; have to copy.
     441               0 :       aValue.SetTo(*mImpl->mMappedAttrs->AttrAt(0));
     442               0 :       NS_RELEASE(mImpl->mMappedAttrs);
     443                 : 
     444               0 :       return NS_OK;
     445                 :     }
     446                 : 
     447               0 :     nsRefPtr<nsMappedAttributes> mapped;
     448                 :     nsresult rv = GetModifiableMapped(nsnull, nsnull, false,
     449               0 :                                       getter_AddRefs(mapped));
     450               0 :     NS_ENSURE_SUCCESS(rv, rv);
     451                 : 
     452               0 :     mapped->RemoveAttrAt(aPos, aValue);
     453                 : 
     454               0 :     return MakeMappedUnique(mapped);
     455                 :   }
     456                 : 
     457               0 :   aPos -= mapped;
     458               0 :   ATTRS(mImpl)[aPos].mValue.SwapValueWith(aValue);
     459               0 :   ATTRS(mImpl)[aPos].~InternalAttr();
     460                 : 
     461               0 :   PRUint32 slotCount = AttrSlotCount();
     462               0 :   memmove(&ATTRS(mImpl)[aPos],
     463               0 :           &ATTRS(mImpl)[aPos + 1],
     464               0 :           (slotCount - aPos - 1) * sizeof(InternalAttr));
     465               0 :   memset(&ATTRS(mImpl)[slotCount - 1], nsnull, sizeof(InternalAttr));
     466                 : 
     467               0 :   return NS_OK;
     468                 : }
     469                 : 
     470                 : const nsAttrName*
     471           15870 : nsAttrAndChildArray::AttrNameAt(PRUint32 aPos) const
     472                 : {
     473           15870 :   NS_ASSERTION(aPos < AttrCount(),
     474                 :                "out-of-bounds access in nsAttrAndChildArray");
     475                 : 
     476           15870 :   PRUint32 mapped = MappedAttrCount();
     477           15870 :   if (aPos < mapped) {
     478               0 :     return mImpl->mMappedAttrs->NameAt(aPos);
     479                 :   }
     480                 : 
     481           15870 :   return &ATTRS(mImpl)[aPos - mapped].mName;
     482                 : }
     483                 : 
     484                 : const nsAttrName*
     485            6147 : nsAttrAndChildArray::GetSafeAttrNameAt(PRUint32 aPos) const
     486                 : {
     487            6147 :   PRUint32 mapped = MappedAttrCount();
     488            6147 :   if (aPos < mapped) {
     489               0 :     return mImpl->mMappedAttrs->NameAt(aPos);
     490                 :   }
     491                 : 
     492            6147 :   aPos -= mapped;
     493            6147 :   if (aPos >= AttrSlotCount()) {
     494               0 :     return nsnull;
     495                 :   }
     496                 : 
     497            6147 :   void** pos = mImpl->mBuffer + aPos * ATTRSIZE;
     498            6147 :   if (!*pos) {
     499               0 :     return nsnull;
     500                 :   }
     501                 : 
     502            6147 :   return &reinterpret_cast<InternalAttr*>(pos)->mName;
     503                 : }
     504                 : 
     505                 : const nsAttrName*
     506            7795 : nsAttrAndChildArray::GetExistingAttrNameFromQName(const nsAString& aName) const
     507                 : {
     508            7795 :   PRUint32 i, slotCount = AttrSlotCount();
     509           23255 :   for (i = 0; i < slotCount && AttrSlotIsTaken(i); ++i) {
     510           18898 :     if (ATTRS(mImpl)[i].mName.QualifiedNameEquals(aName)) {
     511            3438 :       return &ATTRS(mImpl)[i].mName;
     512                 :     }
     513                 :   }
     514                 : 
     515            4357 :   if (mImpl && mImpl->mMappedAttrs) {
     516               0 :     return mImpl->mMappedAttrs->GetExistingAttrNameFromQName(aName);
     517                 :   }
     518                 : 
     519            4357 :   return nsnull;
     520                 : }
     521                 : 
     522                 : PRInt32
     523            5222 : nsAttrAndChildArray::IndexOfAttr(nsIAtom* aLocalName, PRInt32 aNamespaceID) const
     524                 : {
     525                 :   PRInt32 idx;
     526            5222 :   if (mImpl && mImpl->mMappedAttrs) {
     527               0 :     idx = mImpl->mMappedAttrs->IndexOfAttr(aLocalName, aNamespaceID);
     528               0 :     if (idx >= 0) {
     529               0 :       return idx;
     530                 :     }
     531                 :   }
     532                 : 
     533                 :   PRUint32 i;
     534            5222 :   PRUint32 mapped = MappedAttrCount();
     535            5222 :   PRUint32 slotCount = AttrSlotCount();
     536            5222 :   if (aNamespaceID == kNameSpaceID_None) {
     537                 :     // This should be the common case so lets make an optimized loop
     538           21933 :     for (i = 0; i < slotCount && AttrSlotIsTaken(i); ++i) {
     539           18095 :       if (ATTRS(mImpl)[i].mName.Equals(aLocalName)) {
     540             262 :         return i + mapped;
     541                 :       }
     542                 :     }
     543                 :   }
     544                 :   else {
     545            1781 :     for (i = 0; i < slotCount && AttrSlotIsTaken(i); ++i) {
     546            1252 :       if (ATTRS(mImpl)[i].mName.Equals(aLocalName, aNamespaceID)) {
     547             593 :         return i + mapped;
     548                 :       }
     549                 :     }
     550                 :   }
     551                 : 
     552            4367 :   return -1;
     553                 : }
     554                 : 
     555                 : nsresult
     556               0 : nsAttrAndChildArray::SetAndTakeMappedAttr(nsIAtom* aLocalName,
     557                 :                                           nsAttrValue& aValue,
     558                 :                                           nsMappedAttributeElement* aContent,
     559                 :                                           nsHTMLStyleSheet* aSheet)
     560                 : {
     561               0 :   nsRefPtr<nsMappedAttributes> mapped;
     562                 : 
     563               0 :   bool willAdd = true;
     564               0 :   if (mImpl && mImpl->mMappedAttrs) {
     565               0 :     willAdd = mImpl->mMappedAttrs->GetAttr(aLocalName) == nsnull;
     566                 :   }
     567                 : 
     568                 :   nsresult rv = GetModifiableMapped(aContent, aSheet, willAdd,
     569               0 :                                     getter_AddRefs(mapped));
     570               0 :   NS_ENSURE_SUCCESS(rv, rv);
     571                 : 
     572               0 :   rv = mapped->SetAndTakeAttr(aLocalName, aValue);
     573               0 :   NS_ENSURE_SUCCESS(rv, rv);
     574                 : 
     575               0 :   return MakeMappedUnique(mapped);
     576                 : }
     577                 : 
     578                 : nsresult
     579               0 : nsAttrAndChildArray::SetMappedAttrStyleSheet(nsHTMLStyleSheet* aSheet)
     580                 : {
     581               0 :   if (!mImpl || !mImpl->mMappedAttrs ||
     582               0 :       aSheet == mImpl->mMappedAttrs->GetStyleSheet()) {
     583               0 :     return NS_OK;
     584                 :   }
     585                 : 
     586               0 :   nsRefPtr<nsMappedAttributes> mapped;
     587                 :   nsresult rv = GetModifiableMapped(nsnull, nsnull, false, 
     588               0 :                                     getter_AddRefs(mapped));
     589               0 :   NS_ENSURE_SUCCESS(rv, rv);
     590                 : 
     591               0 :   mapped->SetStyleSheet(aSheet);
     592                 : 
     593               0 :   return MakeMappedUnique(mapped);
     594                 : }
     595                 : 
     596                 : void
     597               0 : nsAttrAndChildArray::WalkMappedAttributeStyleRules(nsRuleWalker* aRuleWalker)
     598                 : {
     599               0 :   if (mImpl && mImpl->mMappedAttrs) {
     600               0 :     aRuleWalker->Forward(mImpl->mMappedAttrs);
     601                 :   }
     602               0 : }
     603                 : 
     604                 : void
     605               0 : nsAttrAndChildArray::Compact()
     606                 : {
     607               0 :   if (!mImpl) {
     608               0 :     return;
     609                 :   }
     610                 : 
     611                 :   // First compress away empty attrslots
     612               0 :   PRUint32 slotCount = AttrSlotCount();
     613               0 :   PRUint32 attrCount = NonMappedAttrCount();
     614               0 :   PRUint32 childCount = ChildCount();
     615                 : 
     616               0 :   if (attrCount < slotCount) {
     617               0 :     memmove(mImpl->mBuffer + attrCount * ATTRSIZE,
     618                 :             mImpl->mBuffer + slotCount * ATTRSIZE,
     619               0 :             childCount * sizeof(nsIContent*));
     620               0 :     SetAttrSlotCount(attrCount);
     621                 :   }
     622                 : 
     623                 :   // Then resize or free buffer
     624               0 :   PRUint32 newSize = attrCount * ATTRSIZE + childCount;
     625               0 :   if (!newSize && !mImpl->mMappedAttrs) {
     626               0 :     PR_Free(mImpl);
     627               0 :     mImpl = nsnull;
     628                 :   }
     629               0 :   else if (newSize < mImpl->mBufferSize) {
     630               0 :     mImpl = static_cast<Impl*>(PR_Realloc(mImpl, (newSize + NS_IMPL_EXTRA_SIZE) * sizeof(nsIContent*)));
     631               0 :     NS_ASSERTION(mImpl, "failed to reallocate to smaller buffer");
     632                 : 
     633               0 :     mImpl->mBufferSize = newSize;
     634                 :   }
     635                 : }
     636                 : 
     637                 : void
     638           38704 : nsAttrAndChildArray::Clear()
     639                 : {
     640           38704 :   if (!mImpl) {
     641               0 :     return;
     642                 :   }
     643                 : 
     644           38704 :   if (mImpl->mMappedAttrs) {
     645               0 :     NS_RELEASE(mImpl->mMappedAttrs);
     646                 :   }
     647                 : 
     648           38704 :   PRUint32 i, slotCount = AttrSlotCount();
     649           50150 :   for (i = 0; i < slotCount && AttrSlotIsTaken(i); ++i) {
     650           11446 :     ATTRS(mImpl)[i].~InternalAttr();
     651                 :   }
     652                 : 
     653           77408 :   nsAutoScriptBlocker scriptBlocker;
     654           38704 :   PRUint32 end = slotCount * ATTRSIZE + ChildCount();
     655           38704 :   for (i = slotCount * ATTRSIZE; i < end; ++i) {
     656               0 :     nsIContent* child = static_cast<nsIContent*>(mImpl->mBuffer[i]);
     657                 :     // making this false so tree teardown doesn't end up being
     658                 :     // O(N*D) (number of nodes times average depth of tree).
     659               0 :     child->UnbindFromTree(false); // XXX is it better to let the owner do this?
     660                 :     // Make sure to unlink our kids from each other, since someone
     661                 :     // else could stil be holding references to some of them.
     662                 : 
     663                 :     // XXXbz We probably can't push this assignment down into the |aNullParent|
     664                 :     // case of UnbindFromTree because we still need the assignment in
     665                 :     // RemoveChildAt.  In particular, ContentRemoved fires between
     666                 :     // RemoveChildAt and UnbindFromTree, and in ContentRemoved the sibling
     667                 :     // chain needs to be correct.  Though maybe we could set the prev and next
     668                 :     // to point to each other but keep the kid being removed pointing to them
     669                 :     // through ContentRemoved so consumers can find where it used to be in the
     670                 :     // list?
     671               0 :     child->mPreviousSibling = child->mNextSibling = nsnull;
     672               0 :     NS_RELEASE(child);
     673                 :   }
     674                 : 
     675           38704 :   SetAttrSlotAndChildCount(0, 0);
     676                 : }
     677                 : 
     678                 : PRUint32
     679           71547 : nsAttrAndChildArray::NonMappedAttrCount() const
     680                 : {
     681           71547 :   if (!mImpl) {
     682            1524 :     return 0;
     683                 :   }
     684                 : 
     685           70023 :   PRUint32 count = AttrSlotCount();
     686          140046 :   while (count > 0 && !mImpl->mBuffer[(count - 1) * ATTRSIZE]) {
     687               0 :     --count;
     688                 :   }
     689                 : 
     690           70023 :   return count;
     691                 : }
     692                 : 
     693                 : PRUint32
     694           99808 : nsAttrAndChildArray::MappedAttrCount() const
     695                 : {
     696           99808 :   return mImpl && mImpl->mMappedAttrs ? (PRUint32)mImpl->mMappedAttrs->Count() : 0;
     697                 : }
     698                 : 
     699                 : nsresult
     700               0 : nsAttrAndChildArray::GetModifiableMapped(nsMappedAttributeElement* aContent,
     701                 :                                          nsHTMLStyleSheet* aSheet,
     702                 :                                          bool aWillAddAttr,
     703                 :                                          nsMappedAttributes** aModifiable)
     704                 : {
     705               0 :   *aModifiable = nsnull;
     706                 : 
     707               0 :   if (mImpl && mImpl->mMappedAttrs) {
     708               0 :     *aModifiable = mImpl->mMappedAttrs->Clone(aWillAddAttr);
     709               0 :     NS_ENSURE_TRUE(*aModifiable, NS_ERROR_OUT_OF_MEMORY);
     710                 : 
     711               0 :     NS_ADDREF(*aModifiable);
     712                 :     
     713               0 :     return NS_OK;
     714                 :   }
     715                 : 
     716               0 :   NS_ASSERTION(aContent, "Trying to create modifiable without content");
     717                 : 
     718                 :   nsMapRuleToAttributesFunc mapRuleFunc =
     719               0 :     aContent->GetAttributeMappingFunction();
     720               0 :   *aModifiable = new nsMappedAttributes(aSheet, mapRuleFunc);
     721               0 :   NS_ENSURE_TRUE(*aModifiable, NS_ERROR_OUT_OF_MEMORY);
     722                 : 
     723               0 :   NS_ADDREF(*aModifiable);
     724                 : 
     725               0 :   return NS_OK;
     726                 : }
     727                 : 
     728                 : nsresult
     729               0 : nsAttrAndChildArray::MakeMappedUnique(nsMappedAttributes* aAttributes)
     730                 : {
     731               0 :   NS_ASSERTION(aAttributes, "missing attributes");
     732                 : 
     733               0 :   if (!mImpl && !GrowBy(1)) {
     734               0 :     return NS_ERROR_OUT_OF_MEMORY;
     735                 :   }
     736                 : 
     737               0 :   if (!aAttributes->GetStyleSheet()) {
     738                 :     // This doesn't currently happen, but it could if we do loading right
     739                 : 
     740               0 :     nsRefPtr<nsMappedAttributes> mapped(aAttributes);
     741               0 :     mapped.swap(mImpl->mMappedAttrs);
     742                 : 
     743               0 :     return NS_OK;
     744                 :   }
     745                 : 
     746                 :   nsRefPtr<nsMappedAttributes> mapped =
     747               0 :     aAttributes->GetStyleSheet()->UniqueMappedAttributes(aAttributes);
     748               0 :   NS_ENSURE_TRUE(mapped, NS_ERROR_OUT_OF_MEMORY);
     749                 : 
     750               0 :   if (mapped != aAttributes) {
     751                 :     // Reset the stylesheet of aAttributes so that it doesn't spend time
     752                 :     // trying to remove itself from the hash. There is no risk that aAttributes
     753                 :     // is in the hash since it will always have come from GetModifiableMapped,
     754                 :     // which never returns maps that are in the hash (such hashes are by
     755                 :     // nature not modifiable).
     756               0 :     aAttributes->DropStyleSheetReference();
     757                 :   }
     758               0 :   mapped.swap(mImpl->mMappedAttrs);
     759                 : 
     760               0 :   return NS_OK;
     761                 : }
     762                 : 
     763                 : 
     764                 : bool
     765           45741 : nsAttrAndChildArray::GrowBy(PRUint32 aGrowSize)
     766                 : {
     767           45741 :   PRUint32 size = mImpl ? mImpl->mBufferSize + NS_IMPL_EXTRA_SIZE : 0;
     768           45741 :   PRUint32 minSize = size + aGrowSize;
     769                 : 
     770           45741 :   if (minSize <= ATTRCHILD_ARRAY_LINEAR_THRESHOLD) {
     771           45514 :     do {
     772           45514 :       size += ATTRCHILD_ARRAY_GROWSIZE;
     773                 :     } while (size < minSize);
     774                 :   }
     775                 :   else {
     776             227 :     size = PR_BIT(PR_CeilingLog2(minSize));
     777                 :   }
     778                 : 
     779           45741 :   bool needToInitialize = !mImpl;
     780           45741 :   Impl* newImpl = static_cast<Impl*>(PR_Realloc(mImpl, size * sizeof(void*)));
     781           45741 :   NS_ENSURE_TRUE(newImpl, false);
     782                 : 
     783           45741 :   mImpl = newImpl;
     784                 : 
     785                 :   // Set initial counts if we didn't have a buffer before
     786           45741 :   if (needToInitialize) {
     787           38708 :     mImpl->mMappedAttrs = nsnull;
     788           38708 :     SetAttrSlotAndChildCount(0, 0);
     789                 :   }
     790                 : 
     791           45741 :   mImpl->mBufferSize = size - NS_IMPL_EXTRA_SIZE;
     792                 : 
     793           45741 :   return true;
     794                 : }
     795                 : 
     796                 : bool
     797           11448 : nsAttrAndChildArray::AddAttrSlot()
     798                 : {
     799           11448 :   PRUint32 slotCount = AttrSlotCount();
     800           11448 :   PRUint32 childCount = ChildCount();
     801                 : 
     802                 :   // Grow buffer if needed
     803           19363 :   if (!(mImpl && mImpl->mBufferSize >= (slotCount + 1) * ATTRSIZE + childCount) &&
     804            7915 :       !GrowBy(ATTRSIZE)) {
     805               0 :     return false;
     806                 :   }
     807           11448 :   void** offset = mImpl->mBuffer + slotCount * ATTRSIZE;
     808                 : 
     809           11448 :   if (childCount > 0) {
     810               0 :     memmove(&ATTRS(mImpl)[slotCount + 1], &ATTRS(mImpl)[slotCount],
     811               0 :             childCount * sizeof(nsIContent*));
     812                 :   }
     813                 : 
     814           11448 :   SetAttrSlotCount(slotCount + 1);
     815           11448 :   offset[0] = nsnull;
     816           11448 :   offset[1] = nsnull;
     817                 : 
     818           11448 :   return true;
     819                 : }
     820                 : 
     821                 : inline void
     822          111957 : nsAttrAndChildArray::SetChildAtPos(void** aPos, nsIContent* aChild,
     823                 :                                    PRUint32 aIndex, PRUint32 aChildCount)
     824                 : {
     825          111957 :   NS_PRECONDITION(!aChild->GetNextSibling(), "aChild with next sibling?");
     826          111957 :   NS_PRECONDITION(!aChild->GetPreviousSibling(), "aChild with prev sibling?");
     827                 : 
     828          111957 :   *aPos = aChild;
     829          111957 :   NS_ADDREF(aChild);
     830          111957 :   if (aIndex != 0) {
     831           74825 :     nsIContent* previous = static_cast<nsIContent*>(*(aPos - 1));
     832           74825 :     aChild->mPreviousSibling = previous;
     833           74825 :     previous->mNextSibling = aChild;
     834                 :   }
     835          111957 :   if (aIndex != aChildCount) {
     836              12 :     nsIContent* next = static_cast<nsIContent*>(*(aPos + 1));
     837              12 :     aChild->mNextSibling = next;
     838              12 :     next->mPreviousSibling = aChild;
     839                 :   }
     840          111957 : }
     841                 : 
     842                 : size_t
     843               0 : nsAttrAndChildArray::SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf) const
     844                 : {
     845               0 :   size_t n = 0;
     846               0 :   if (mImpl) {
     847                 :     // Don't add the size taken by *mMappedAttrs because it's shared.
     848                 : 
     849               0 :     n += aMallocSizeOf(mImpl);
     850                 : 
     851               0 :     PRUint32 slotCount = AttrSlotCount();
     852               0 :     for (PRUint32 i = 0; i < slotCount && AttrSlotIsTaken(i); ++i) {
     853               0 :       nsAttrValue* value = &ATTRS(mImpl)[i].mValue;
     854               0 :       n += value->SizeOfExcludingThis(aMallocSizeOf);
     855                 :     }
     856                 :   }
     857                 : 
     858               0 :   return n;
     859                 : }
     860                 : 

Generated by: LCOV version 1.7