Changeset 113862 in webkit
- Timestamp:
- Apr 11, 2012 8:20:04 AM (12 years ago)
- Location:
- trunk/Source/WebCore
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/ChangeLog
r113859 r113862 1 2012-04-11 Arko Saha <arko@motorola.com> 2 3 Microdata: Implement cache mechanism for HTMLPropertiesCollection. 4 https://bugs.webkit.org/show_bug.cgi?id=80490 5 6 Reviewed by Ryosuke Niwa. 7 8 Implemented caching mechanism for HTMLPropertiesCollection. 9 propertyCache - contains microdata item properties. 10 itemRefElements - contains sorted microdata item and itemref elements. 11 propertyNames - contains microdata property names of the elements in the collection. 12 itemRefElementPosition - store the current position of itemRefElements. 13 hasItemRefElements - set to ture once we have sorted microdata item and itemref elements list i.e, itemRefElements. 14 Cache is invalidated only when dom tree modified. Whenever any query is made on HTMLPropertiesCollection, 15 result is returned from the cache. Earliar we used to calculate properties node list every time a query is made. 16 17 * html/HTMLPropertiesCollection.cpp: 18 (WebCore): 19 (WebCore::HTMLPropertiesCollection::HTMLPropertiesCollection): 20 (WebCore::HTMLPropertiesCollection::invalidateCacheIfNeeded): 21 (WebCore::HTMLPropertiesCollection::updateRefElements): Appends microdata item element and elements which 22 are added through itemref attribute in itemRefElements (in tree order). 23 (WebCore::nextNodeWithProperty): 24 (WebCore::HTMLPropertiesCollection::itemAfter): Takes parent base and previous item property as argument. 25 Finds the next item property in base. 26 (WebCore::HTMLPropertiesCollection::calcLength): Calculates the length of properties collection if length 27 is not available in the cache. 28 (WebCore::HTMLPropertiesCollection::length): 29 (WebCore::HTMLPropertiesCollection::firstProperty): Returns the first property in the collection. 30 (WebCore::HTMLPropertiesCollection::item): 31 (WebCore::HTMLPropertiesCollection::findProperties): Finds microdata item properties in the base element. 32 Appends the properties in propertyCache and property names in propertyNames. 33 (WebCore::HTMLPropertiesCollection::updateNameCache): It updates the propertyCache and propertyNames if hasNameCache is false. 34 (WebCore::HTMLPropertiesCollection::names): 35 (WebCore::HTMLPropertiesCollection::namedItem): 36 (WebCore::HTMLPropertiesCollection::hasNamedItem): 37 * html/HTMLPropertiesCollection.h: 38 (HTMLPropertiesCollection): 39 1 40 2012-04-10 Jocelyn Turcotte <jocelyn.turcotte@nokia.com> 2 41 -
trunk/Source/WebCore/html/HTMLPropertiesCollection.cpp
r109200 r113862 46 46 using namespace HTMLNames; 47 47 48 static inline bool compareTreeOrder(Node* node1, Node* node2)49 {50 return (node2->compareDocumentPosition(node1) & (Node::DOCUMENT_POSITION_PRECEDING | Node::DOCUMENT_POSITION_DISCONNECTED)) == Node::DOCUMENT_POSITION_PRECEDING;51 }52 53 48 PassOwnPtr<HTMLPropertiesCollection> HTMLPropertiesCollection::create(Node* itemNode) 54 49 { … … 58 53 HTMLPropertiesCollection::HTMLPropertiesCollection(Node* itemNode) 59 54 : HTMLCollection(itemNode, ItemProperties) 60 , m_propertyNames(DOMStringList::create())61 55 { 62 56 } … … 66 60 } 67 61 68 void HTMLPropertiesCollection::findPropetiesOfAnItem(Node* root) const 69 { 70 // 5.2.5 Associating names with items. 71 Vector<Node*> memory; 72 73 memory.append(root); 74 75 Vector<Node*> pending; 76 // Add the child elements of root, if any, to pending. 77 for (Node* child = root->firstChild(); child; child = child->nextSibling()) 78 if (child->isHTMLElement()) 79 pending.append(child); 80 81 // If root has an itemref attribute, split the value of that itemref attribute on spaces. 82 // For each resulting token ID, if there is an element in the home subtree of root with the ID ID, 83 // then add the first such element to pending. 84 if (toHTMLElement(root)->fastHasAttribute(itemrefAttr)) { 85 DOMSettableTokenList* itemRef = root->itemRef(); 86 87 for (size_t i = 0; i < itemRef->length(); ++i) { 88 AtomicString id = itemRef->item(i); 89 90 Element* element = root->document()->getElementById(id); 91 if (element && element->isHTMLElement()) 92 pending.append(element); 93 } 94 } 95 96 // Loop till we have processed all pending elements 97 while (!pending.isEmpty()) { 98 99 // Remove first element from pending and let current be that element. 100 Node* current = pending[0]; 101 pending.remove(0); 102 103 // If current is already in memory, there is a microdata error; 104 if (memory.contains(current)) { 105 // microdata error; 62 void HTMLPropertiesCollection::invalidateCacheIfNeeded() const 63 { 64 uint64_t docversion = base()->document()->domTreeVersion(); 65 66 if (m_cache.version == docversion) 67 return; 68 69 m_cache.clear(); 70 m_cache.version = docversion; 71 } 72 73 void HTMLPropertiesCollection::updateRefElements() const 74 { 75 if (m_cache.hasItemRefElements) 76 return; 77 78 Vector<Element*> itemRefElements; 79 HTMLElement* baseElement = toHTMLElement(base()); 80 81 if (!baseElement->fastHasAttribute(itemrefAttr)) { 82 itemRefElements.append(baseElement); 83 m_cache.setItemRefElements(itemRefElements); 84 return; 85 } 86 87 DOMSettableTokenList* itemRef = baseElement->itemRef(); 88 RefPtr<DOMSettableTokenList> processedItemRef = DOMSettableTokenList::create(); 89 Node* rootNode = baseElement->treeScope()->rootNode(); 90 91 for (Node* current = rootNode->firstChild(); current; current = current->traverseNextNode(rootNode)) { 92 if (!current->isHTMLElement()) 106 93 continue; 107 }108 109 memory.append(current);110 111 // If current does not have an itemscope attribute, then: add all the child elements of current to pending.112 94 HTMLElement* element = toHTMLElement(current); 113 if (!element->fastHasAttribute(itemscopeAttr)) { 114 for (Node* child = current->firstChild(); child; child = child->nextSibling()) 115 if (child->isHTMLElement()) 116 pending.append(child); 117 } 118 119 // If current has an itemprop attribute specified, add it to results. 120 if (element->fastHasAttribute(itempropAttr)) 121 m_properties.append(current); 122 } 95 96 if (element == baseElement) { 97 itemRefElements.append(element); 98 continue; 99 } 100 101 const AtomicString& id = element->getIdAttribute(); 102 if (!processedItemRef->tokens().contains(id) && itemRef->tokens().contains(id)) { 103 processedItemRef->setValue(id); 104 if (!element->isDescendantOf(baseElement)) 105 itemRefElements.append(element); 106 } 107 } 108 109 m_cache.setItemRefElements(itemRefElements); 110 } 111 112 static Node* nextNodeWithProperty(Node* base, Node* node) 113 { 114 // An Microdata item may contain properties which in turn are items themselves. Properties can 115 // also themselves be groups of name-value pairs, by putting the itemscope attribute on the element 116 // that declares the property. If the property has an itemscope attribute specified then we need 117 // to traverse the next sibling. 118 return node == base || (node->isHTMLElement() && !toHTMLElement(node)->fastHasAttribute(itemscopeAttr)) 119 ? node->traverseNextNode(base) : node->traverseNextSibling(base); 120 } 121 122 Element* HTMLPropertiesCollection::itemAfter(Element* base, Element* previous) const 123 { 124 Node* current; 125 current = previous ? nextNodeWithProperty(base, previous) : base; 126 127 for (; current; current = nextNodeWithProperty(base, current)) { 128 if (!current->isHTMLElement()) 129 continue; 130 HTMLElement* element = toHTMLElement(current); 131 if (element->fastHasAttribute(itempropAttr)) { 132 return element; 133 } 134 } 135 136 return 0; 137 } 138 139 unsigned HTMLPropertiesCollection::calcLength() const 140 { 141 unsigned length = 0; 142 updateRefElements(); 143 144 const Vector<Element*>& itemRefElements = m_cache.getItemRefElements(); 145 for (unsigned i = 0; i < itemRefElements.size(); ++i) { 146 for (Element* element = itemAfter(itemRefElements[i], 0); element; element = itemAfter(itemRefElements[i], element)) 147 ++length; 148 } 149 150 return length; 123 151 } 124 152 125 153 unsigned HTMLPropertiesCollection::length() const 126 154 { 127 if (! base()->isHTMLElement() || !toHTMLElement(base())->fastHasAttribute(itemscopeAttr))155 if (!toHTMLElement(base())->fastHasAttribute(itemscopeAttr)) 128 156 return 0; 129 157 130 m_properties.clear(); 131 findPropetiesOfAnItem(base()); 132 return m_properties.size(); 158 invalidateCacheIfNeeded(); 159 160 if (!m_cache.hasLength) 161 m_cache.updateLength(calcLength()); 162 163 return m_cache.length; 164 } 165 166 Element* HTMLPropertiesCollection::firstProperty() const 167 { 168 Element* element = 0; 169 m_cache.resetPosition(); 170 const Vector<Element*>& itemRefElements = m_cache.getItemRefElements(); 171 for (unsigned i = 0; i < itemRefElements.size(); ++i) { 172 element = itemAfter(itemRefElements[i], 0); 173 if (element) { 174 m_cache.itemRefElementPosition = i; 175 break; 176 } 177 } 178 179 return element; 133 180 } 134 181 135 182 Node* HTMLPropertiesCollection::item(unsigned index) const 136 183 { 137 if (! base()->isHTMLElement() || !toHTMLElement(base())->fastHasAttribute(itemscopeAttr))184 if (!toHTMLElement(base())->fastHasAttribute(itemscopeAttr)) 138 185 return 0; 139 186 140 m_properties.clear(); 141 findPropetiesOfAnItem(base()); 142 143 if (m_properties.size() <= index) 187 invalidateCacheIfNeeded(); 188 if (m_cache.current && m_cache.position == index) 189 return m_cache.current; 190 191 if (m_cache.hasLength && m_cache.length <= index) 144 192 return 0; 145 193 146 std::sort(m_properties.begin(), m_properties.end(), compareTreeOrder); 147 return m_properties[index]; 194 updateRefElements(); 195 if (!m_cache.current || m_cache.position > index) { 196 m_cache.current = firstProperty(); 197 if (!m_cache.current) 198 return 0; 199 } 200 201 unsigned currentPosition = m_cache.position; 202 Element* element = m_cache.current; 203 unsigned itemRefElementPos = m_cache.itemRefElementPosition; 204 const Vector<Element*>& itemRefElements = m_cache.getItemRefElements(); 205 206 bool found = (m_cache.position == index); 207 208 for (unsigned i = itemRefElementPos; i < itemRefElements.size() && !found; ++i) { 209 while (currentPosition < index) { 210 element = itemAfter(itemRefElements[i], element); 211 if (!element) 212 break; 213 currentPosition++; 214 215 if (currentPosition == index) { 216 found = true; 217 itemRefElementPos = i; 218 break; 219 } 220 } 221 } 222 223 m_cache.updateCurrentItem(element, index, itemRefElementPos); 224 return m_cache.current; 225 } 226 227 void HTMLPropertiesCollection::findProperties(Element* base) const 228 { 229 for (Element* element = itemAfter(base, 0); element; element = itemAfter(base, element)) { 230 DOMSettableTokenList* itemProperty = element->itemProp(); 231 for (unsigned i = 0; i < itemProperty->length(); ++i) 232 m_cache.updatePropertyCache(element, itemProperty->item(i)); 233 } 234 } 235 236 void HTMLPropertiesCollection::updateNameCache() const 237 { 238 invalidateCacheIfNeeded(); 239 if (m_cache.hasNameCache) 240 return; 241 242 updateRefElements(); 243 244 const Vector<Element*>& itemRefElements = m_cache.getItemRefElements(); 245 for (unsigned i = 0; i < itemRefElements.size(); ++i) 246 findProperties(itemRefElements[i]); 247 248 m_cache.hasNameCache = true; 148 249 } 149 250 150 251 PassRefPtr<DOMStringList> HTMLPropertiesCollection::names() const 151 252 { 152 m_properties.clear(); 153 m_propertyNames->clear(); 154 155 if (!base()->isHTMLElement() || !toHTMLElement(base())->fastHasAttribute(itemscopeAttr)) 156 return m_propertyNames; 157 158 findPropetiesOfAnItem(base()); 159 160 std::sort(m_properties.begin(), m_properties.end(), compareTreeOrder); 161 162 for (size_t i = 0; i < m_properties.size(); ++i) { 163 // For each item properties, split the value of that itemprop attribute on spaces. 164 // Add all tokens to property names, with the order preserved but with duplicates removed. 165 DOMSettableTokenList* itemProperty = m_properties[i]->itemProp(); 166 for (size_t i = 0; i < itemProperty->length(); ++i) { 167 AtomicString propertyName = itemProperty->item(i); 168 if (m_propertyNames->isEmpty() || !m_propertyNames->contains(propertyName)) 169 m_propertyNames->append(propertyName); 170 } 171 } 172 173 return m_propertyNames; 253 if (!toHTMLElement(base())->fastHasAttribute(itemscopeAttr)) 254 return DOMStringList::create(); 255 256 updateNameCache(); 257 258 return m_cache.propertyNames; 174 259 } 175 260 176 261 PassRefPtr<NodeList> HTMLPropertiesCollection::namedItem(const String& name) const 177 262 { 178 if (! base()->isHTMLElement() || !toHTMLElement(base())->fastHasAttribute(itemscopeAttr))263 if (!toHTMLElement(base())->fastHasAttribute(itemscopeAttr)) 179 264 return 0; 180 265 181 m_properties.clear();182 266 Vector<RefPtr<Node> > namedItems; 183 findPropetiesOfAnItem(base()); 184 185 std::sort(m_properties.begin(), m_properties.end(), compareTreeOrder); 186 187 // For each item properties, split the value of that itemprop attribute on spaces. 188 // Add element to namedItem that contains a property named name, with the order preserved. 189 for (size_t i = 0; i < m_properties.size(); ++i) { 190 DOMSettableTokenList* itemProperty = m_properties[i]->itemProp(); 191 if (itemProperty->tokens().contains(name)) 192 namedItems.append(m_properties[i]); 193 } 267 268 updateNameCache(); 269 270 Vector<Element*>* propertyResults = m_cache.propertyCache.get(AtomicString(name).impl()); 271 for (unsigned i = 0; propertyResults && i < propertyResults->size(); ++i) 272 namedItems.append(propertyResults->at(i)); 194 273 195 274 // FIXME: HTML5 specifies that this should return PropertyNodeList. … … 199 278 bool HTMLPropertiesCollection::hasNamedItem(const AtomicString& name) const 200 279 { 201 if (! base()->isHTMLElement() || !toHTMLElement(base())->fastHasAttribute(itemscopeAttr))280 if (!toHTMLElement(base())->fastHasAttribute(itemscopeAttr)) 202 281 return false; 203 282 204 m_properties.clear(); 205 findPropetiesOfAnItem(base()); 206 207 // For each item properties, split the value of that itemprop attribute on spaces. 208 // Return true if element contains a property named name. 209 for (size_t i = 0; i < m_properties.size(); ++i) { 210 DOMSettableTokenList* itemProperty = m_properties[i]->itemProp(); 211 if (itemProperty->tokens().contains(name)) 283 updateNameCache(); 284 285 if (Vector<Element*>* propertyCache = m_cache.propertyCache.get(name.impl())) { 286 if (!propertyCache->isEmpty()) 212 287 return true; 213 288 } -
trunk/Source/WebCore/html/HTMLPropertiesCollection.h
r109200 r113862 34 34 #if ENABLE(MICRODATA) 35 35 36 #include "DOMStringList.h" 36 37 #include "HTMLCollection.h" 37 38 … … 57 58 HTMLPropertiesCollection(Node*); 58 59 59 void findPropetiesOfAnItem(Node* current) const;60 void getNamedItems(Vector<RefPtr<Node> >&, const String&) const;60 unsigned calcLength() const; 61 void findProperties(Element* base) const; 61 62 62 mutable Vector<Node*> m_properties; 63 mutable RefPtr<DOMStringList> m_propertyNames; 63 Node* findRefElements(Node* previous) const; 64 65 Element* firstProperty() const; 66 Element* itemAfter(Element* base, Element* previous) const; 67 68 void updateNameCache() const; 69 void updateRefElements() const; 70 71 void invalidateCacheIfNeeded() const; 72 73 mutable struct { 74 uint64_t version; 75 Element* current; 76 unsigned position; 77 unsigned length; 78 bool hasLength; 79 bool hasNameCache; 80 NodeCacheMap propertyCache; 81 Vector<Element*> itemRefElements; 82 RefPtr<DOMStringList> propertyNames; 83 unsigned itemRefElementPosition; 84 bool hasItemRefElements; 85 86 void clear() 87 { 88 version = 0; 89 current = 0; 90 position = 0; 91 length = 0; 92 hasLength = false; 93 hasNameCache = false; 94 propertyCache.clear(); 95 itemRefElements.clear(); 96 propertyNames.clear(); 97 itemRefElementPosition = 0; 98 hasItemRefElements = false; 99 } 100 101 void setItemRefElements(const Vector<Element*>& elements) 102 { 103 itemRefElements = elements; 104 hasItemRefElements = true; 105 } 106 107 const Vector<Element*>& getItemRefElements() 108 { 109 return itemRefElements; 110 } 111 112 void updateLength(unsigned len) 113 { 114 length = len; 115 hasLength = true; 116 } 117 118 void updatePropertyCache(Element* element, const AtomicString& propertyName) 119 { 120 if (!propertyNames) 121 propertyNames = DOMStringList::create(); 122 123 if (!propertyNames->contains(propertyName)) 124 propertyNames->append(propertyName); 125 126 Vector<Element*>* propertyResults = propertyCache.get(propertyName.impl()); 127 if (!propertyResults || !propertyResults->contains(element)) 128 append(propertyCache, propertyName, element); 129 } 130 131 void updateCurrentItem(Element* element, unsigned pos, unsigned itemRefElementPos) 132 { 133 current = element; 134 position = pos; 135 itemRefElementPosition = itemRefElementPos; 136 } 137 138 void resetPosition() 139 { 140 current = 0; 141 position = 0; 142 itemRefElementPosition = 0; 143 } 144 145 } m_cache; 146 64 147 }; 65 148
Note: See TracChangeset
for help on using the changeset viewer.