1 /* 2 * Copyright (C) 2008 Apple Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of 14 * its contributors may be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include "config.h" 30 #include "HTMLTableRowsCollection.h" 31 32 #include "HTMLNames.h" 33 #include "HTMLTableElement.h" 34 #include "HTMLTableRowElement.h" 35 36 namespace WebCore { 37 38 using namespace HTMLNames; 39 40 static bool isInHead(Element* row) 41 { 42 return row->parentNode() && static_cast<Element*>(row->parentNode())->hasLocalName(theadTag); 43 } 44 45 static bool isInBody(Element* row) 46 { 47 return row->parentNode() && static_cast<Element*>(row->parentNode())->hasLocalName(tbodyTag); 48 } 49 50 static bool isInFoot(Element* row) 51 { 52 return row->parentNode() && static_cast<Element*>(row->parentNode())->hasLocalName(tfootTag); 53 } 54 55 HTMLTableRowElement* HTMLTableRowsCollection::rowAfter(HTMLTableElement* table, HTMLTableRowElement* previous) 56 { 57 Node* child = 0; 58 59 // Start by looking for the next row in this section. 60 // Continue only if there is none. 61 if (previous && previous->parentNode() != table) { 62 for (child = previous->nextSibling(); child; child = child->nextSibling()) { 63 if (child->hasTagName(trTag)) 64 return static_cast<HTMLTableRowElement*>(child); 65 } 66 } 67 68 // If still looking at head sections, find the first row in the next head section. 69 if (!previous) 70 child = table->firstChild(); 71 else if (isInHead(previous)) 72 child = previous->parentNode()->nextSibling(); 73 for (; child; child = child->nextSibling()) { 74 if (child->hasTagName(theadTag)) { 75 for (Node* grandchild = child->firstChild(); grandchild; grandchild = grandchild->nextSibling()) { 76 if (grandchild->hasTagName(trTag)) 77 return static_cast<HTMLTableRowElement*>(grandchild); 78 } 79 } 80 } 81 82 // If still looking at top level and bodies, find the next row in top level or the first in the next body section. 83 if (!previous || isInHead(previous)) 84 child = table->firstChild(); 85 else if (previous->parentNode() == table) 86 child = previous->nextSibling(); 87 else if (isInBody(previous)) 88 child = previous->parentNode()->nextSibling(); 89 for (; child; child = child->nextSibling()) { 90 if (child->hasTagName(trTag)) 91 return static_cast<HTMLTableRowElement*>(child); 92 if (child->hasTagName(tbodyTag)) { 93 for (Node* grandchild = child->firstChild(); grandchild; grandchild = grandchild->nextSibling()) { 94 if (grandchild->hasTagName(trTag)) 95 return static_cast<HTMLTableRowElement*>(grandchild); 96 } 97 } 98 } 99 100 // Find the first row in the next foot section. 101 if (!previous || !isInFoot(previous)) 102 child = table->firstChild(); 103 else 104 child = previous->parentNode()->nextSibling(); 105 for (; child; child = child->nextSibling()) { 106 if (child->hasTagName(tfootTag)) { 107 for (Node* grandchild = child->firstChild(); grandchild; grandchild = grandchild->nextSibling()) { 108 if (grandchild->hasTagName(trTag)) 109 return static_cast<HTMLTableRowElement*>(grandchild); 110 } 111 } 112 } 113 114 return 0; 115 } 116 117 HTMLTableRowElement* HTMLTableRowsCollection::lastRow(HTMLTableElement* table) 118 { 119 for (Node* child = table->lastChild(); child; child = child->previousSibling()) { 120 if (child->hasTagName(tfootTag)) { 121 for (Node* grandchild = child->lastChild(); grandchild; grandchild = grandchild->previousSibling()) { 122 if (grandchild->hasTagName(trTag)) 123 return static_cast<HTMLTableRowElement*>(grandchild); 124 } 125 } 126 } 127 128 for (Node* child = table->lastChild(); child; child = child->previousSibling()) { 129 if (child->hasTagName(trTag)) 130 return static_cast<HTMLTableRowElement*>(child); 131 if (child->hasTagName(tbodyTag)) { 132 for (Node* grandchild = child->lastChild(); grandchild; grandchild = grandchild->previousSibling()) { 133 if (grandchild->hasTagName(trTag)) 134 return static_cast<HTMLTableRowElement*>(grandchild); 135 } 136 } 137 } 138 139 for (Node* child = table->lastChild(); child; child = child->previousSibling()) { 140 if (child->hasTagName(theadTag)) { 141 for (Node* grandchild = child->lastChild(); grandchild; grandchild = grandchild->previousSibling()) { 142 if (grandchild->hasTagName(trTag)) 143 return static_cast<HTMLTableRowElement*>(grandchild); 144 } 145 } 146 } 147 148 return 0; 149 } 150 151 HTMLTableRowsCollection::HTMLTableRowsCollection(PassRefPtr<HTMLTableElement> table) 152 : HTMLCollection(table, OtherCollection, 0) 153 { 154 } 155 156 PassRefPtr<HTMLTableRowsCollection> HTMLTableRowsCollection::create(PassRefPtr<HTMLTableElement> table) 157 { 158 return adoptRef(new HTMLTableRowsCollection(table)); 159 } 160 161 Element* HTMLTableRowsCollection::itemAfter(Element* previous) const 162 { 163 ASSERT(!previous || previous->hasLocalName(trTag)); 164 return rowAfter(static_cast<HTMLTableElement*>(base()), static_cast<HTMLTableRowElement*>(previous)); 165 } 166 167 } 168