HTMLTableRowElement.cpp (7330B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 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/. */ 6 7 #include "mozilla/dom/HTMLTableRowElement.h" 8 9 #include "mozilla/MappedDeclarationsBuilder.h" 10 #include "mozilla/dom/BindingUtils.h" 11 #include "mozilla/dom/HTMLTableElement.h" 12 #include "mozilla/dom/HTMLTableRowElementBinding.h" 13 #include "nsAttrValueInlines.h" 14 #include "nsContentList.h" 15 #include "nsContentUtils.h" 16 17 NS_IMPL_NS_NEW_HTML_ELEMENT(TableRow) 18 19 namespace mozilla::dom { 20 21 HTMLTableRowElement::~HTMLTableRowElement() = default; 22 23 JSObject* HTMLTableRowElement::WrapNode(JSContext* aCx, 24 JS::Handle<JSObject*> aGivenProto) { 25 return HTMLTableRowElement_Binding::Wrap(aCx, this, aGivenProto); 26 } 27 28 NS_IMPL_CYCLE_COLLECTION_INHERITED(HTMLTableRowElement, nsGenericHTMLElement, 29 mCells) 30 31 NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED_0(HTMLTableRowElement, 32 nsGenericHTMLElement) 33 34 NS_IMPL_ELEMENT_CLONE(HTMLTableRowElement) 35 36 // protected method 37 HTMLTableSectionElement* HTMLTableRowElement::GetSection() const { 38 nsIContent* parent = GetParent(); 39 if (parent && parent->IsAnyOfHTMLElements(nsGkAtoms::thead, nsGkAtoms::tbody, 40 nsGkAtoms::tfoot)) { 41 return static_cast<HTMLTableSectionElement*>(parent); 42 } 43 return nullptr; 44 } 45 46 // protected method 47 HTMLTableElement* HTMLTableRowElement::GetTable() const { 48 nsIContent* parent = GetParent(); 49 if (!parent) { 50 return nullptr; 51 } 52 53 // We may not be in a section 54 HTMLTableElement* table = HTMLTableElement::FromNode(parent); 55 if (table) { 56 return table; 57 } 58 59 return HTMLTableElement::FromNodeOrNull(parent->GetParent()); 60 } 61 62 int32_t HTMLTableRowElement::RowIndex() const { 63 HTMLTableElement* table = GetTable(); 64 if (!table) { 65 return -1; 66 } 67 68 nsIHTMLCollection* rows = table->Rows(); 69 70 uint32_t numRows = rows->Length(); 71 72 for (uint32_t i = 0; i < numRows; i++) { 73 if (rows->GetElementAt(i) == this) { 74 return i; 75 } 76 } 77 78 return -1; 79 } 80 81 int32_t HTMLTableRowElement::SectionRowIndex() const { 82 HTMLTableSectionElement* section = GetSection(); 83 if (!section) { 84 return -1; 85 } 86 87 nsCOMPtr<nsIHTMLCollection> coll = section->Rows(); 88 uint32_t numRows = coll->Length(); 89 for (uint32_t i = 0; i < numRows; i++) { 90 if (coll->GetElementAt(i) == this) { 91 return i; 92 } 93 } 94 95 return -1; 96 } 97 98 static bool IsCell(Element* aElement, int32_t aNamespaceID, nsAtom* aAtom, 99 void* aData) { 100 return aElement->IsAnyOfHTMLElements(nsGkAtoms::td, nsGkAtoms::th); 101 } 102 103 nsIHTMLCollection* HTMLTableRowElement::Cells() { 104 if (!mCells) { 105 mCells = new nsContentList(this, IsCell, 106 nullptr, // destroy func 107 nullptr, // closure data 108 false, nullptr, kNameSpaceID_XHTML, false); 109 } 110 111 return mCells; 112 } 113 114 already_AddRefed<nsGenericHTMLElement> HTMLTableRowElement::InsertCell( 115 int32_t aIndex, ErrorResult& aError) { 116 if (aIndex < -1) { 117 aError.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR); 118 return nullptr; 119 } 120 121 // Make sure mCells is initialized. 122 nsIHTMLCollection* cells = Cells(); 123 124 NS_ASSERTION(mCells, "How did that happen?"); 125 126 nsCOMPtr<nsINode> nextSibling; 127 // -1 means append, so should use null nextSibling 128 if (aIndex != -1) { 129 nextSibling = cells->Item(aIndex); 130 // Check whether we're inserting past end of list. We want to avoid doing 131 // this unless we really have to, since this has to walk all our kids. If 132 // we have a nextSibling, we're clearly not past end of list. 133 if (!nextSibling) { 134 uint32_t cellCount = cells->Length(); 135 if (aIndex > int32_t(cellCount)) { 136 aError.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR); 137 return nullptr; 138 } 139 } 140 } 141 142 // create the cell 143 RefPtr<mozilla::dom::NodeInfo> nodeInfo; 144 nsContentUtils::QNameChanged(mNodeInfo, nsGkAtoms::td, 145 getter_AddRefs(nodeInfo)); 146 147 RefPtr<nsGenericHTMLElement> cell = 148 NS_NewHTMLTableCellElement(nodeInfo.forget()); 149 if (!cell) { 150 aError.Throw(NS_ERROR_OUT_OF_MEMORY); 151 return nullptr; 152 } 153 154 nsINode::InsertBefore(*cell, nextSibling, aError); 155 156 return cell.forget(); 157 } 158 159 void HTMLTableRowElement::DeleteCell(int32_t aValue, ErrorResult& aError) { 160 if (aValue < -1) { 161 aError.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR); 162 return; 163 } 164 165 nsIHTMLCollection* cells = Cells(); 166 167 uint32_t refIndex; 168 if (aValue == -1) { 169 refIndex = cells->Length(); 170 if (refIndex == 0) { 171 return; 172 } 173 174 --refIndex; 175 } else { 176 refIndex = (uint32_t)aValue; 177 } 178 179 nsCOMPtr<nsINode> cell = cells->Item(refIndex); 180 if (!cell) { 181 aError.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR); 182 return; 183 } 184 185 nsINode::RemoveChild(*cell, aError); 186 } 187 188 bool HTMLTableRowElement::ParseAttribute(int32_t aNamespaceID, 189 nsAtom* aAttribute, 190 const nsAString& aValue, 191 nsIPrincipal* aMaybeScriptedPrincipal, 192 nsAttrValue& aResult) { 193 /* 194 * ignore these attributes, stored simply as strings 195 * 196 * ch 197 */ 198 199 if (aNamespaceID == kNameSpaceID_None) { 200 if (aAttribute == nsGkAtoms::height) { 201 // Per spec should be ParseNonzeroHTMLDimension, but no browsers do that. 202 // See https://github.com/whatwg/html/issues/4716 203 return aResult.ParseHTMLDimension(aValue); 204 } 205 if (aAttribute == nsGkAtoms::align) { 206 return ParseTableCellHAlignValue(aValue, aResult); 207 } 208 if (aAttribute == nsGkAtoms::bgcolor) { 209 return aResult.ParseColor(aValue); 210 } 211 if (aAttribute == nsGkAtoms::valign) { 212 return ParseTableVAlignValue(aValue, aResult); 213 } 214 } 215 216 return nsGenericHTMLElement::ParseBackgroundAttribute( 217 aNamespaceID, aAttribute, aValue, aResult) || 218 nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue, 219 aMaybeScriptedPrincipal, aResult); 220 } 221 222 void HTMLTableRowElement::MapAttributesIntoRule( 223 MappedDeclarationsBuilder& aBuilder) { 224 nsGenericHTMLElement::MapHeightAttributeInto(aBuilder); 225 nsGenericHTMLElement::MapTableCellHAlignAttributeInto(aBuilder); 226 nsGenericHTMLElement::MapTableVAlignAttributeInto(aBuilder); 227 nsGenericHTMLElement::MapBackgroundAttributesInto(aBuilder); 228 nsGenericHTMLElement::MapCommonAttributesInto(aBuilder); 229 } 230 231 NS_IMETHODIMP_(bool) 232 HTMLTableRowElement::IsAttributeMapped(const nsAtom* aAttribute) const { 233 static const MappedAttributeEntry attributes[] = { 234 {nsGkAtoms::align}, {nsGkAtoms::valign}, {nsGkAtoms::height}, {nullptr}}; 235 236 static const MappedAttributeEntry* const map[] = { 237 attributes, 238 sCommonAttributeMap, 239 sBackgroundAttributeMap, 240 }; 241 242 return FindAttributeDependence(aAttribute, map); 243 } 244 245 nsMapRuleToAttributesFunc HTMLTableRowElement::GetAttributeMappingFunction() 246 const { 247 return &MapAttributesIntoRule; 248 } 249 250 } // namespace mozilla::dom