1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/layout/base/nsGenConList.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,180 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +// vim:cindent:ts=2:et:sw=2: 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +/* base class for nsCounterList and nsQuoteList */ 1.11 + 1.12 +#include "nsGenConList.h" 1.13 +#include "nsLayoutUtils.h" 1.14 +#include "nsIContent.h" 1.15 + 1.16 +void 1.17 +nsGenConList::Clear() 1.18 +{ 1.19 + //Delete entire list 1.20 + if (!mFirstNode) 1.21 + return; 1.22 + for (nsGenConNode *node = Next(mFirstNode); node != mFirstNode; 1.23 + node = Next(mFirstNode)) 1.24 + { 1.25 + Remove(node); 1.26 + delete node; 1.27 + } 1.28 + delete mFirstNode; 1.29 + 1.30 + mFirstNode = nullptr; 1.31 + mSize = 0; 1.32 +} 1.33 + 1.34 +bool 1.35 +nsGenConList::DestroyNodesFor(nsIFrame* aFrame) 1.36 +{ 1.37 + if (!mFirstNode) 1.38 + return false; // list empty 1.39 + nsGenConNode* node; 1.40 + bool destroyed = false; 1.41 + while (mFirstNode->mPseudoFrame == aFrame) { 1.42 + destroyed = true; 1.43 + node = Next(mFirstNode); 1.44 + bool isLastNode = node == mFirstNode; // before they're dangling 1.45 + Remove(mFirstNode); 1.46 + delete mFirstNode; 1.47 + if (isLastNode) { 1.48 + mFirstNode = nullptr; 1.49 + return true; 1.50 + } 1.51 + else { 1.52 + mFirstNode = node; 1.53 + } 1.54 + } 1.55 + node = Next(mFirstNode); 1.56 + while (node != mFirstNode) { 1.57 + if (node->mPseudoFrame == aFrame) { 1.58 + destroyed = true; 1.59 + nsGenConNode *nextNode = Next(node); 1.60 + Remove(node); 1.61 + delete node; 1.62 + node = nextNode; 1.63 + } else { 1.64 + node = Next(node); 1.65 + } 1.66 + } 1.67 + return destroyed; 1.68 +} 1.69 + 1.70 +/** 1.71 + * Compute the type of the pseudo and the content for the pseudo that 1.72 + * we'll use for comparison purposes. 1.73 + * @param aContent the content to use is stored here; it's the element 1.74 + * that generated the ::before or ::after content, or (if not for generated 1.75 + * content), the frame's own element 1.76 + * @return -1 for ::before, +1 for ::after, and 0 otherwise. 1.77 + */ 1.78 +inline int32_t PseudoCompareType(nsIFrame* aFrame, nsIContent** aContent) 1.79 +{ 1.80 + nsIAtom *pseudo = aFrame->StyleContext()->GetPseudo(); 1.81 + if (pseudo == nsCSSPseudoElements::before) { 1.82 + *aContent = aFrame->GetContent()->GetParent(); 1.83 + return -1; 1.84 + } 1.85 + if (pseudo == nsCSSPseudoElements::after) { 1.86 + *aContent = aFrame->GetContent()->GetParent(); 1.87 + return 1; 1.88 + } 1.89 + *aContent = aFrame->GetContent(); 1.90 + return 0; 1.91 +} 1.92 + 1.93 +/* static */ bool 1.94 +nsGenConList::NodeAfter(const nsGenConNode* aNode1, const nsGenConNode* aNode2) 1.95 +{ 1.96 + nsIFrame *frame1 = aNode1->mPseudoFrame; 1.97 + nsIFrame *frame2 = aNode2->mPseudoFrame; 1.98 + if (frame1 == frame2) { 1.99 + NS_ASSERTION(aNode2->mContentIndex != aNode1->mContentIndex, "identical"); 1.100 + return aNode1->mContentIndex > aNode2->mContentIndex; 1.101 + } 1.102 + nsIContent *content1; 1.103 + nsIContent *content2; 1.104 + int32_t pseudoType1 = PseudoCompareType(frame1, &content1); 1.105 + int32_t pseudoType2 = PseudoCompareType(frame2, &content2); 1.106 + if (pseudoType1 == 0 || pseudoType2 == 0) { 1.107 + if (content1 == content2) { 1.108 + NS_ASSERTION(pseudoType1 != pseudoType2, "identical"); 1.109 + return pseudoType2 == 0; 1.110 + } 1.111 + // We want to treat an element as coming before its :before (preorder 1.112 + // traversal), so treating both as :before now works. 1.113 + if (pseudoType1 == 0) pseudoType1 = -1; 1.114 + if (pseudoType2 == 0) pseudoType2 = -1; 1.115 + } else { 1.116 + if (content1 == content2) { 1.117 + NS_ASSERTION(pseudoType1 != pseudoType2, "identical"); 1.118 + return pseudoType1 == 1; 1.119 + } 1.120 + } 1.121 + // XXX Switch to the frame version of DoCompareTreePosition? 1.122 + int32_t cmp = nsLayoutUtils::DoCompareTreePosition(content1, content2, 1.123 + pseudoType1, -pseudoType2); 1.124 + NS_ASSERTION(cmp != 0, "same content, different frames"); 1.125 + return cmp > 0; 1.126 +} 1.127 + 1.128 +void 1.129 +nsGenConList::Insert(nsGenConNode* aNode) 1.130 +{ 1.131 + if (mFirstNode) { 1.132 + // Check for append. 1.133 + if (NodeAfter(aNode, Prev(mFirstNode))) { 1.134 + PR_INSERT_BEFORE(aNode, mFirstNode); 1.135 + } 1.136 + else { 1.137 + // Binary search. 1.138 + 1.139 + // the range of indices at which |aNode| could end up. 1.140 + // (We already know it can't be at index mSize.) 1.141 + uint32_t first = 0, last = mSize - 1; 1.142 + 1.143 + // A cursor to avoid walking more than the length of the list. 1.144 + nsGenConNode *curNode = Prev(mFirstNode); 1.145 + uint32_t curIndex = mSize - 1; 1.146 + 1.147 + while (first != last) { 1.148 + uint32_t test = (first + last) / 2; 1.149 + if (last == curIndex) { 1.150 + for ( ; curIndex != test; --curIndex) 1.151 + curNode = Prev(curNode); 1.152 + } else { 1.153 + for ( ; curIndex != test; ++curIndex) 1.154 + curNode = Next(curNode); 1.155 + } 1.156 + 1.157 + if (NodeAfter(aNode, curNode)) { 1.158 + first = test + 1; 1.159 + // if we exit the loop, we need curNode to be right 1.160 + ++curIndex; 1.161 + curNode = Next(curNode); 1.162 + } else { 1.163 + last = test; 1.164 + } 1.165 + } 1.166 + PR_INSERT_BEFORE(aNode, curNode); 1.167 + if (curNode == mFirstNode) { 1.168 + mFirstNode = aNode; 1.169 + } 1.170 + } 1.171 + } 1.172 + else { 1.173 + // initialize list with first node 1.174 + PR_INIT_CLIST(aNode); 1.175 + mFirstNode = aNode; 1.176 + } 1.177 + ++mSize; 1.178 + 1.179 + NS_ASSERTION(aNode == mFirstNode || NodeAfter(aNode, Prev(aNode)), 1.180 + "sorting error"); 1.181 + NS_ASSERTION(IsLast(aNode) || NodeAfter(Next(aNode), aNode), 1.182 + "sorting error"); 1.183 +}