LCOV - app.info - content/base/src/nsAttrAndChildArray.cpp

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-07-07 | 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          141366 : nsAttrAndChildArray::GetSafeChildAt(PRUint32 aPos) const
         141                 : {
         142          141366 :   if (aPos < ChildCount()) {
         143          141366 :     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           71739 : nsAttrAndChildArray::AttrCount() const
         324                 : {
         325           71739 :   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           15869 : nsAttrAndChildArray::AttrNameAt(PRUint32 aPos) const
         472                 : {
         473           15869 :   NS_ASSERTION(aPos < AttrCount(),
         474                 :                "out-of-bounds access in nsAttrAndChildArray");
         475                 :
         476           15869 :   PRUint32 mapped = MappedAttrCount();
         477           15869 :   if (aPos < mapped) {
         478               0 :     return mImpl->mMappedAttrs->NameAt(aPos);
         479                 :   }
         480                 :
         481           15869 :   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           71739 : nsAttrAndChildArray::NonMappedAttrCount() const
         680                 : {
         681           71739 :   if (!mImpl) {
         682            1522 :     return 0;
         683                 :   }
         684                 :
         685           70217 :   PRUint32 count = AttrSlotCount();
         686          140434 :   while (count > 0 && !mImpl->mBuffer[(count - 1) * ATTRSIZE]) {
         687               0 :     --count;
         688                 :   }
         689                 :
         690           70217 :   return count;
         691                 : }
         692                 :
         693                 : PRUint32
         694           99999 : nsAttrAndChildArray::MappedAttrCount() const
         695                 : {
         696           99999 :   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