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 |