1/* 2 * Copyright (c) 2011 Motorola Mobility, Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without modification, 5 * are permitted provided that the following conditions are met: 6 * 7 * Redistributions of source code must retain the above copyright notice, 8 * this list of conditions and the following disclaimer. 9 * 10 * Redistributions in binary form must reproduce the above copyright notice, 11 * this list of conditions and the following disclaimer in the documentation and/or 12 * other materials provided with the distribution. 13 * 14 * Neither the name of Motorola Mobility, Inc. nor the names of its contributors may 15 * be used to endorse or promote products derived from this software without 16 * specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 20 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 21 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 22 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 23 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 25 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 26 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 27 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31#include "config.h" 32 33#if ENABLE(MICRODATA) 34 35#include "HTMLPropertiesCollection.h" 36 37#include "DOMSettableTokenList.h" 38#include "HTMLElement.h" 39#include "HTMLNames.h" 40#include "Node.h" 41#include "NodeTraversal.h" 42#include "PropertyNodeList.h" 43 44namespace WebCore { 45 46using namespace HTMLNames; 47 48PassRefPtr<HTMLPropertiesCollection> HTMLPropertiesCollection::create(Node* itemNode, CollectionType) 49{ 50 return adoptRef(new HTMLPropertiesCollection(itemNode)); 51} 52 53HTMLPropertiesCollection::HTMLPropertiesCollection(Node* itemNode) 54 : HTMLCollection(itemNode, ItemProperties, OverridesItemAfter) 55{ 56} 57 58HTMLPropertiesCollection::~HTMLPropertiesCollection() 59{ 60} 61 62void HTMLPropertiesCollection::updateRefElements() const 63{ 64 if (isItemRefElementsCacheValid()) 65 return; 66 67 m_itemRefElements.clear(); 68 setItemRefElementsCacheValid(); 69 toHTMLElement(ownerNode())->getItemRefElements(m_itemRefElements); 70} 71 72static Node* nextNodeWithProperty(Node* rootNode, Node* previous, Node* ownerNode) 73{ 74 // An Microdata item may contain properties which in turn are items themselves. Properties can 75 // also themselves be groups of name-value pairs, by putting the itemscope attribute on the element 76 // that declares the property. If the property has an itemscope attribute specified then we need 77 // to traverse the next sibling. 78 return previous == ownerNode || (previous->isHTMLElement() && !toHTMLElement(previous)->fastHasAttribute(itemscopeAttr)) 79 ? NodeTraversal::next(previous, rootNode) 80 : NodeTraversal::nextSkippingChildren(previous, rootNode); 81} 82 83Element* HTMLPropertiesCollection::virtualItemAfter(unsigned& offsetInArray, Element* previousItem) const 84{ 85 while (offsetInArray < m_itemRefElements.size()) { 86 if (Element* next = virtualItemAfter(m_itemRefElements[offsetInArray], previousItem)) 87 return next; 88 offsetInArray++; 89 previousItem = 0; 90 } 91 return 0; 92} 93 94HTMLElement* HTMLPropertiesCollection::virtualItemAfter(HTMLElement* rootNode, Element* previous) const 95{ 96 Node* current; 97 Node* ownerNode = this->ownerNode(); 98 current = previous ? nextNodeWithProperty(rootNode, previous, ownerNode) : rootNode; 99 100 for (; current; current = nextNodeWithProperty(rootNode, current, ownerNode)) { 101 if (current == ownerNode || !current->isHTMLElement()) 102 continue; 103 HTMLElement* element = toHTMLElement(current); 104 if (element->fastHasAttribute(itempropAttr) && element->itemProp()->length()) { 105 return element; 106 } 107 } 108 109 return 0; 110} 111 112void HTMLPropertiesCollection::updateNameCache() const 113{ 114 if (hasNameCache()) 115 return; 116 117 updateRefElements(); 118 119 for (unsigned i = 0; i < m_itemRefElements.size(); ++i) { 120 HTMLElement* refElement = m_itemRefElements[i]; 121 for (HTMLElement* element = virtualItemAfter(refElement, 0); element; element = virtualItemAfter(refElement, element)) { 122 DOMSettableTokenList* itemProperty = element->itemProp(); 123 for (unsigned propertyIndex = 0; propertyIndex < itemProperty->length(); ++propertyIndex) 124 updatePropertyCache(itemProperty->item(propertyIndex)); 125 } 126 } 127 128 setHasNameCache(); 129} 130 131PassRefPtr<DOMStringList> HTMLPropertiesCollection::names() const 132{ 133 updateNameCache(); 134 if (!m_propertyNames) 135 m_propertyNames = DOMStringList::create(); 136 return m_propertyNames; 137} 138 139PassRefPtr<PropertyNodeList> HTMLPropertiesCollection::propertyNodeList(const String& name) const 140{ 141 return ownerNode()->propertyNodeList(name); 142} 143 144bool HTMLPropertiesCollection::hasNamedItem(const AtomicString& name) const 145{ 146 updateNameCache(); 147 if (m_propertyNames) 148 return m_propertyNames->contains(name); 149 return false; 150} 151 152} // namespace WebCore 153 154#endif // ENABLE(MICRODATA) 155