| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) | 2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) |
| 3 * (C) 1999 Antti Koivisto (koivisto@kde.org) | 3 * (C) 1999 Antti Koivisto (koivisto@kde.org) |
| 4 * Copyright (C) 2003-2008, 2011, 2012, 2014 Apple Inc. All rights reserved. | 4 * Copyright (C) 2003-2008, 2011, 2012, 2014 Apple Inc. All rights reserved. |
| 5 * Copyright (C) 2014 Samsung Electronics. All rights reserved. | 5 * Copyright (C) 2014 Samsung Electronics. All rights reserved. |
| 6 * | 6 * |
| 7 * This library is free software; you can redistribute it and/or | 7 * This library is free software; you can redistribute it and/or |
| 8 * modify it under the terms of the GNU Library General Public | 8 * modify it under the terms of the GNU Library General Public |
| 9 * License as published by the Free Software Foundation; either | 9 * License as published by the Free Software Foundation; either |
| 10 * version 2 of the License, or (at your option) any later version. | 10 * version 2 of the License, or (at your option) any later version. |
| (...skipping 237 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 248 case WindowNamedItems: | 248 case WindowNamedItems: |
| 249 case NameNodeListType: | 249 case NameNodeListType: |
| 250 case RadioNodeListType: | 250 case RadioNodeListType: |
| 251 case RadioImgNodeListType: | 251 case RadioImgNodeListType: |
| 252 case LabelsNodeListType: | 252 case LabelsNodeListType: |
| 253 ASSERT_NOT_REACHED(); | 253 ASSERT_NOT_REACHED(); |
| 254 } | 254 } |
| 255 return false; | 255 return false; |
| 256 } | 256 } |
| 257 | 257 |
| 258 template <class NodeListType> | 258 inline bool HTMLCollection::elementMatches(const Element& element) const |
| 259 inline bool isMatchingElement(const NodeListType&, const Element&); | |
| 260 | |
| 261 template <> inline bool isMatchingElement(const HTMLCollection& htmlCollection,
const Element& element) | |
| 262 { | 259 { |
| 263 // These collections apply to any kind of Elements, not just HTMLElements. | 260 // These collections apply to any kind of Elements, not just HTMLElements. |
| 264 switch (htmlCollection.type()) { | 261 switch (type()) { |
| 265 case DocAll: | 262 case DocAll: |
| 266 case NodeChildren: | 263 case NodeChildren: |
| 267 return true; | 264 return true; |
| 268 case ClassCollectionType: | 265 case ClassCollectionType: |
| 269 return toClassCollection(htmlCollection).elementMatches(element); | 266 return toClassCollection(*this).elementMatches(element); |
| 270 case TagCollectionType: | 267 case TagCollectionType: |
| 271 return toTagCollection(htmlCollection).elementMatches(element); | 268 return toTagCollection(*this).elementMatches(element); |
| 272 case HTMLTagCollectionType: | 269 case HTMLTagCollectionType: |
| 273 return toHTMLTagCollection(htmlCollection).elementMatches(element); | 270 return toHTMLTagCollection(*this).elementMatches(element); |
| 274 case DocumentNamedItems: | 271 case DocumentNamedItems: |
| 275 return toDocumentNameCollection(htmlCollection).elementMatches(element); | 272 return toDocumentNameCollection(*this).elementMatches(element); |
| 276 case WindowNamedItems: | 273 case WindowNamedItems: |
| 277 return toWindowNameCollection(htmlCollection).elementMatches(element); | 274 return toWindowNameCollection(*this).elementMatches(element); |
| 278 default: | 275 default: |
| 279 break; | 276 break; |
| 280 } | 277 } |
| 281 | 278 |
| 282 // The following only applies to HTMLElements. | 279 // The following only applies to HTMLElements. |
| 283 return element.isHTMLElement() && isMatchingHTMLElement(htmlCollection, toHT
MLElement(element)); | 280 return element.isHTMLElement() && isMatchingHTMLElement(*this, toHTMLElement
(element)); |
| 284 } | 281 } |
| 285 | 282 |
| 286 template <> inline bool isMatchingElement(const ClassCollection& collection, con
st Element& element) | 283 namespace { |
| 287 { | |
| 288 return collection.elementMatches(element); | |
| 289 } | |
| 290 | 284 |
| 291 template <> inline bool isMatchingElement(const HTMLTagCollection& collection, c
onst Element& element) | 285 template <class HTMLCollectionType> |
| 292 { | 286 class IsMatch { |
| 293 return collection.elementMatches(element); | 287 public: |
| 294 } | 288 IsMatch(const HTMLCollectionType& list) |
| 289 : m_list(list) |
| 290 { } |
| 291 |
| 292 bool operator() (const Element& element) const |
| 293 { |
| 294 return m_list.elementMatches(element); |
| 295 } |
| 296 |
| 297 private: |
| 298 const HTMLCollectionType& m_list; |
| 299 }; |
| 300 |
| 301 } // namespace |
| 302 |
| 303 template <class HTMLCollectionType> |
| 304 static inline IsMatch<HTMLCollectionType> makeIsMatch(const HTMLCollectionType&
list) { return IsMatch<HTMLCollectionType>(list); } |
| 295 | 305 |
| 296 Element* HTMLCollection::virtualItemAfter(Element*) const | 306 Element* HTMLCollection::virtualItemAfter(Element*) const |
| 297 { | 307 { |
| 298 ASSERT_NOT_REACHED(); | 308 ASSERT_NOT_REACHED(); |
| 299 return 0; | 309 return 0; |
| 300 } | 310 } |
| 301 | 311 |
| 302 static inline bool nameShouldBeVisibleInDocumentAll(const HTMLElement& element) | 312 static inline bool nameShouldBeVisibleInDocumentAll(const HTMLElement& element) |
| 303 { | 313 { |
| 304 // http://www.whatwg.org/specs/web-apps/current-work/multipage/common-dom-in
terfaces.html#dom-htmlallcollection-nameditem: | 314 // http://www.whatwg.org/specs/web-apps/current-work/multipage/common-dom-in
terfaces.html#dom-htmlallcollection-nameditem: |
| 305 // The document.all collection returns only certain types of elements by nam
e, | 315 // The document.all collection returns only certain types of elements by nam
e, |
| 306 // although it returns any type of element by id. | 316 // although it returns any type of element by id. |
| 307 return element.hasTagName(aTag) | 317 return element.hasTagName(aTag) |
| 308 || element.hasTagName(appletTag) | 318 || element.hasTagName(appletTag) |
| 309 || element.hasTagName(areaTag) | 319 || element.hasTagName(areaTag) |
| 310 || element.hasTagName(embedTag) | 320 || element.hasTagName(embedTag) |
| 311 || element.hasTagName(formTag) | 321 || element.hasTagName(formTag) |
| 312 || element.hasTagName(frameTag) | 322 || element.hasTagName(frameTag) |
| 313 || element.hasTagName(framesetTag) | 323 || element.hasTagName(framesetTag) |
| 314 || element.hasTagName(iframeTag) | 324 || element.hasTagName(iframeTag) |
| 315 || element.hasTagName(imgTag) | 325 || element.hasTagName(imgTag) |
| 316 || element.hasTagName(inputTag) | 326 || element.hasTagName(inputTag) |
| 317 || element.hasTagName(objectTag) | 327 || element.hasTagName(objectTag) |
| 318 || element.hasTagName(selectTag); | 328 || element.hasTagName(selectTag); |
| 319 } | 329 } |
| 320 | 330 |
| 321 inline Element* firstMatchingChildElement(const HTMLCollection& nodeList) | |
| 322 { | |
| 323 Element* element = ElementTraversal::firstChild(nodeList.rootNode()); | |
| 324 while (element && !isMatchingElement(nodeList, *element)) | |
| 325 element = ElementTraversal::nextSibling(*element); | |
| 326 return element; | |
| 327 } | |
| 328 | |
| 329 inline Element* lastMatchingChildElement(const HTMLCollection& nodeList) | |
| 330 { | |
| 331 Element* element = ElementTraversal::lastChild(nodeList.rootNode()); | |
| 332 while (element && !isMatchingElement(nodeList, *element)) | |
| 333 element = ElementTraversal::previousSibling(*element); | |
| 334 return element; | |
| 335 } | |
| 336 | |
| 337 inline Element* nextMatchingChildElement(const HTMLCollection& nodeList, Element
& current) | |
| 338 { | |
| 339 Element* next = ¤t; | |
| 340 do { | |
| 341 next = ElementTraversal::nextSibling(*next); | |
| 342 } while (next && !isMatchingElement(nodeList, *next)); | |
| 343 return next; | |
| 344 } | |
| 345 | |
| 346 inline Element* previousMatchingChildElement(const HTMLCollection& nodeList, Ele
ment& current) | |
| 347 { | |
| 348 Element* previous = ¤t; | |
| 349 do { | |
| 350 previous = ElementTraversal::previousSibling(*previous); | |
| 351 } while (previous && !isMatchingElement(nodeList, *previous)); | |
| 352 return previous; | |
| 353 } | |
| 354 | |
| 355 Element* HTMLCollection::traverseToFirstElement() const | 331 Element* HTMLCollection::traverseToFirstElement() const |
| 356 { | 332 { |
| 357 switch (type()) { | 333 switch (type()) { |
| 358 case HTMLTagCollectionType: | 334 case HTMLTagCollectionType: |
| 359 return firstMatchingElement(toHTMLTagCollection(*this)); | 335 return ElementTraversal::firstWithin(rootNode(), makeIsMatch(toHTMLTagCo
llection(*this))); |
| 360 case ClassCollectionType: | 336 case ClassCollectionType: |
| 361 return firstMatchingElement(toClassCollection(*this)); | 337 return ElementTraversal::firstWithin(rootNode(), makeIsMatch(toClassColl
ection(*this))); |
| 362 default: | 338 default: |
| 363 if (overridesItemAfter()) | 339 if (overridesItemAfter()) |
| 364 return virtualItemAfter(0); | 340 return virtualItemAfter(0); |
| 365 if (shouldOnlyIncludeDirectChildren()) | 341 if (shouldOnlyIncludeDirectChildren()) |
| 366 return firstMatchingChildElement(*this); | 342 return ElementTraversal::firstChild(rootNode(), makeIsMatch(*this)); |
| 367 return firstMatchingElement(*this); | 343 return ElementTraversal::firstWithin(rootNode(), makeIsMatch(*this)); |
| 368 } | 344 } |
| 369 } | 345 } |
| 370 | 346 |
| 371 Element* HTMLCollection::traverseToLastElement() const | 347 Element* HTMLCollection::traverseToLastElement() const |
| 372 { | 348 { |
| 373 ASSERT(canTraverseBackward()); | 349 ASSERT(canTraverseBackward()); |
| 374 if (shouldOnlyIncludeDirectChildren()) | 350 if (shouldOnlyIncludeDirectChildren()) |
| 375 return lastMatchingChildElement(*this); | 351 return ElementTraversal::lastChild(rootNode(), makeIsMatch(*this)); |
| 376 return lastMatchingElement(*this); | 352 return ElementTraversal::lastWithin(rootNode(), makeIsMatch(*this)); |
| 377 } | 353 } |
| 378 | 354 |
| 379 Element* HTMLCollection::traverseForwardToOffset(unsigned offset, Element& curre
ntElement, unsigned& currentOffset) const | 355 Element* HTMLCollection::traverseForwardToOffset(unsigned offset, Element& curre
ntElement, unsigned& currentOffset) const |
| 380 { | 356 { |
| 381 ASSERT(currentOffset < offset); | 357 ASSERT(currentOffset < offset); |
| 382 switch (type()) { | 358 switch (type()) { |
| 383 case HTMLTagCollectionType: | 359 case HTMLTagCollectionType: |
| 384 return traverseMatchingElementsForwardToOffset(toHTMLTagCollection(*this
), offset, currentElement, currentOffset); | 360 return traverseMatchingElementsForwardToOffset(currentElement, &rootNode
(), offset, currentOffset, makeIsMatch(toHTMLTagCollection(*this))); |
| 385 case ClassCollectionType: | 361 case ClassCollectionType: |
| 386 return traverseMatchingElementsForwardToOffset(toClassCollection(*this),
offset, currentElement, currentOffset); | 362 return traverseMatchingElementsForwardToOffset(currentElement, &rootNode
(), offset, currentOffset, makeIsMatch(toClassCollection(*this))); |
| 387 default: | 363 default: |
| 388 if (overridesItemAfter()) { | 364 if (overridesItemAfter()) { |
| 389 for (Element* next = virtualItemAfter(¤tElement); next; next =
virtualItemAfter(next)) { | 365 for (Element* next = virtualItemAfter(¤tElement); next; next =
virtualItemAfter(next)) { |
| 390 if (++currentOffset == offset) | 366 if (++currentOffset == offset) |
| 391 return next; | 367 return next; |
| 392 } | 368 } |
| 393 return 0; | 369 return 0; |
| 394 } | 370 } |
| 395 if (shouldOnlyIncludeDirectChildren()) { | 371 if (shouldOnlyIncludeDirectChildren()) { |
| 396 for (Element* next = nextMatchingChildElement(*this, currentElement)
; next; next = nextMatchingChildElement(*this, *next)) { | 372 IsMatch<HTMLCollection> isMatch(*this); |
| 373 for (Element* next = ElementTraversal::nextSibling(currentElement, i
sMatch); next; next = ElementTraversal::nextSibling(*next, isMatch)) { |
| 397 if (++currentOffset == offset) | 374 if (++currentOffset == offset) |
| 398 return next; | 375 return next; |
| 399 } | 376 } |
| 400 return 0; | 377 return 0; |
| 401 } | 378 } |
| 402 return traverseMatchingElementsForwardToOffset(*this, offset, currentEle
ment, currentOffset); | 379 return traverseMatchingElementsForwardToOffset(currentElement, &rootNode
(), offset, currentOffset, makeIsMatch(*this)); |
| 403 } | 380 } |
| 404 } | 381 } |
| 405 | 382 |
| 406 Element* HTMLCollection::traverseBackwardToOffset(unsigned offset, Element& curr
entElement, unsigned& currentOffset) const | 383 Element* HTMLCollection::traverseBackwardToOffset(unsigned offset, Element& curr
entElement, unsigned& currentOffset) const |
| 407 { | 384 { |
| 408 ASSERT(currentOffset > offset); | 385 ASSERT(currentOffset > offset); |
| 409 ASSERT(canTraverseBackward()); | 386 ASSERT(canTraverseBackward()); |
| 410 if (shouldOnlyIncludeDirectChildren()) { | 387 if (shouldOnlyIncludeDirectChildren()) { |
| 411 for (Element* previous = previousMatchingChildElement(*this, currentElem
ent); previous; previous = previousMatchingChildElement(*this, *previous)) { | 388 IsMatch<HTMLCollection> isMatch(*this); |
| 389 for (Element* previous = ElementTraversal::previousSibling(currentElemen
t, isMatch); previous; previous = ElementTraversal::previousSibling(*previous, i
sMatch)) { |
| 412 if (--currentOffset == offset) | 390 if (--currentOffset == offset) |
| 413 return previous; | 391 return previous; |
| 414 } | 392 } |
| 415 return 0; | 393 return 0; |
| 416 } | 394 } |
| 417 return traverseMatchingElementsBackwardToOffset(*this, offset, currentElemen
t, currentOffset); | 395 return traverseMatchingElementsBackwardToOffset(currentElement, &rootNode(),
offset, currentOffset, makeIsMatch(*this)); |
| 418 } | 396 } |
| 419 | 397 |
| 420 Element* HTMLCollection::namedItem(const AtomicString& name) const | 398 Element* HTMLCollection::namedItem(const AtomicString& name) const |
| 421 { | 399 { |
| 422 // http://msdn.microsoft.com/workshop/author/dhtml/reference/methods/namedit
em.asp | 400 // http://msdn.microsoft.com/workshop/author/dhtml/reference/methods/namedit
em.asp |
| 423 // This method first searches for an object with a matching id | 401 // This method first searches for an object with a matching id |
| 424 // attribute. If a match is not found, the method then searches for an | 402 // attribute. If a match is not found, the method then searches for an |
| 425 // object with a matching name attribute, but only on those elements | 403 // object with a matching name attribute, but only on those elements |
| 426 // that are allowed a name attribute. | 404 // that are allowed a name attribute. |
| 427 updateIdNameCache(); | 405 updateIdNameCache(); |
| (...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 525 } | 503 } |
| 526 | 504 |
| 527 void HTMLCollection::trace(Visitor* visitor) | 505 void HTMLCollection::trace(Visitor* visitor) |
| 528 { | 506 { |
| 529 visitor->trace(m_namedItemCache); | 507 visitor->trace(m_namedItemCache); |
| 530 visitor->trace(m_collectionIndexCache); | 508 visitor->trace(m_collectionIndexCache); |
| 531 LiveNodeListBase::trace(visitor); | 509 LiveNodeListBase::trace(visitor); |
| 532 } | 510 } |
| 533 | 511 |
| 534 } // namespace blink | 512 } // namespace blink |
| OLD | NEW |