layout/tables/SpanningCellSorter.cpp

Wed, 31 Dec 2014 06:55:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:55:50 +0100
changeset 2
7e26c7da4463
permissions
-rw-r--r--

Added tag UPSTREAM_283F7C6 for changeset ca08bd8f51b2

     1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
     2 // vim:cindent:ts=4:et:sw=4:
     3 /* This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 /*
     8  * Code to sort cells by their colspan, used by BasicTableLayoutStrategy.
     9  */
    11 #include "SpanningCellSorter.h"
    12 #include "nsQuickSort.h"
    13 #include "nsIPresShell.h"
    15 //#define DEBUG_SPANNING_CELL_SORTER
    17 SpanningCellSorter::SpanningCellSorter()
    18   : mState(ADDING)
    19   , mSortedHashTable(nullptr)
    20 {
    21     memset(mArray, 0, sizeof(mArray));
    22     mHashTable.entryCount = 0;
    23 }
    25 SpanningCellSorter::~SpanningCellSorter()
    26 {
    27     if (mHashTable.entryCount) {
    28         PL_DHashTableFinish(&mHashTable);
    29         mHashTable.entryCount = 0;
    30     }
    31     delete [] mSortedHashTable;
    32 }
    34 /* static */ const PLDHashTableOps
    35 SpanningCellSorter::HashTableOps = {
    36     PL_DHashAllocTable,
    37     PL_DHashFreeTable,
    38     HashTableHashKey,
    39     HashTableMatchEntry,
    40     PL_DHashMoveEntryStub,
    41     PL_DHashClearEntryStub,
    42     PL_DHashFinalizeStub,
    43     nullptr
    44 };
    46 /* static */ PLDHashNumber
    47 SpanningCellSorter::HashTableHashKey(PLDHashTable *table, const void *key)
    48 {
    49     return NS_PTR_TO_INT32(key);
    50 }
    52 /* static */ bool
    53 SpanningCellSorter::HashTableMatchEntry(PLDHashTable *table,
    54                                         const PLDHashEntryHdr *hdr,
    55                                         const void *key)
    56 {
    57     const HashTableEntry *entry = static_cast<const HashTableEntry*>(hdr);
    58     return NS_PTR_TO_INT32(key) == entry->mColSpan;
    59 }
    61 bool
    62 SpanningCellSorter::AddCell(int32_t aColSpan, int32_t aRow, int32_t aCol)
    63 {
    64     NS_ASSERTION(mState == ADDING, "cannot call AddCell after GetNext");
    65     NS_ASSERTION(aColSpan >= ARRAY_BASE, "cannot add cells with colspan<2");
    67     Item *i = (Item*) mozilla::AutoStackArena::Allocate(sizeof(Item));
    68     NS_ENSURE_TRUE(i != nullptr, false);
    70     i->row = aRow;
    71     i->col = aCol;
    73     if (UseArrayForSpan(aColSpan)) {
    74         int32_t index = SpanToIndex(aColSpan);
    75         i->next = mArray[index];
    76         mArray[index] = i;
    77     } else {
    78         if (!mHashTable.entryCount) {
    79             PL_DHashTableInit(&mHashTable, &HashTableOps, nullptr,
    80                               sizeof(HashTableEntry), PL_DHASH_MIN_SIZE);
    81         }
    82         HashTableEntry *entry = static_cast<HashTableEntry*>
    83                                            (PL_DHashTableOperate(&mHashTable, NS_INT32_TO_PTR(aColSpan),
    84                                  PL_DHASH_ADD));
    85         NS_ENSURE_TRUE(entry, false);
    87         NS_ASSERTION(entry->mColSpan == 0 || entry->mColSpan == aColSpan,
    88                      "wrong entry");
    89         NS_ASSERTION((entry->mColSpan == 0) == (entry->mItems == nullptr),
    90                      "entry should be either new or properly initialized");
    91         entry->mColSpan = aColSpan;
    93         i->next = entry->mItems;
    94         entry->mItems = i;
    95     }
    97     return true;
    98 }
   100 /* static */ PLDHashOperator
   101 SpanningCellSorter::FillSortedArray(PLDHashTable *table, PLDHashEntryHdr *hdr,
   102                                     uint32_t number, void *arg)
   103 {
   104     HashTableEntry *entry = static_cast<HashTableEntry*>(hdr);
   105     HashTableEntry **sh = static_cast<HashTableEntry**>(arg);
   107     sh[number] = entry;
   109     return PL_DHASH_NEXT;
   110 }
   112 /* static */ int
   113 SpanningCellSorter::SortArray(const void *a, const void *b, void *closure)
   114 {
   115     int32_t spanA = (*static_cast<HashTableEntry*const*>(a))->mColSpan;
   116     int32_t spanB = (*static_cast<HashTableEntry*const*>(b))->mColSpan;
   118     if (spanA < spanB)
   119         return -1;
   120     if (spanA == spanB)
   121         return 0;
   122     return 1;
   123 }
   125 SpanningCellSorter::Item*
   126 SpanningCellSorter::GetNext(int32_t *aColSpan)
   127 {
   128     NS_ASSERTION(mState != DONE, "done enumerating, stop calling");
   130     switch (mState) {
   131         case ADDING:
   132             /* prepare to enumerate the array */
   133             mState = ENUMERATING_ARRAY;
   134             mEnumerationIndex = 0;
   135             /* fall through */
   136         case ENUMERATING_ARRAY:
   137             while (mEnumerationIndex < ARRAY_SIZE && !mArray[mEnumerationIndex])
   138                 ++mEnumerationIndex;
   139             if (mEnumerationIndex < ARRAY_SIZE) {
   140                 Item *result = mArray[mEnumerationIndex];
   141                 *aColSpan = IndexToSpan(mEnumerationIndex);
   142                 NS_ASSERTION(result, "logic error");
   143 #ifdef DEBUG_SPANNING_CELL_SORTER
   144                 printf("SpanningCellSorter[%p]:"
   145                        " returning list for colspan=%d from array\n",
   146                        static_cast<void*>(this), *aColSpan);
   147 #endif
   148                 ++mEnumerationIndex;
   149                 return result;
   150             }
   151             /* prepare to enumerate the hash */
   152             mState = ENUMERATING_HASH;
   153             mEnumerationIndex = 0;
   154             if (mHashTable.entryCount) {
   155                 HashTableEntry **sh =
   156                     new HashTableEntry*[mHashTable.entryCount];
   157                 if (!sh) {
   158                     // give up
   159                     mState = DONE;
   160                     return nullptr;
   161                 }
   162                 PL_DHashTableEnumerate(&mHashTable, FillSortedArray, sh);
   163                 NS_QuickSort(sh, mHashTable.entryCount, sizeof(sh[0]),
   164                              SortArray, nullptr);
   165                 mSortedHashTable = sh;
   166             }
   167             /* fall through */
   168         case ENUMERATING_HASH:
   169             if (mEnumerationIndex < mHashTable.entryCount) {
   170                 Item *result = mSortedHashTable[mEnumerationIndex]->mItems;
   171                 *aColSpan = mSortedHashTable[mEnumerationIndex]->mColSpan;
   172                 NS_ASSERTION(result, "holes in hash table");
   173 #ifdef DEBUG_SPANNING_CELL_SORTER
   174                 printf("SpanningCellSorter[%p]:"
   175                        " returning list for colspan=%d from hash\n",
   176                        static_cast<void*>(this), *aColSpan);
   177 #endif
   178                 ++mEnumerationIndex;
   179                 return result;
   180             }
   181             mState = DONE;
   182             /* fall through */
   183         case DONE:
   184             ;
   185     }
   186     return nullptr;
   187 }

mercurial