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 template <class HTMLCollectionType> |
287 { | 284 class IsMatch { |
288 return collection.elementMatches(element); | 285 public: |
289 } | 286 IsMatch(const HTMLCollectionType& list) |
| 287 : m_list(list) |
| 288 { } |
290 | 289 |
291 template <> inline bool isMatchingElement(const HTMLTagCollection& collection, c
onst Element& element) | 290 bool operator() (Element& element) const |
292 { | 291 { |
293 return collection.elementMatches(element); | 292 return m_list.elementMatches(element); |
294 } | 293 } |
| 294 |
| 295 private: |
| 296 const HTMLCollectionType& m_list; |
| 297 }; |
295 | 298 |
296 Element* HTMLCollection::virtualItemAfter(Element*) const | 299 Element* HTMLCollection::virtualItemAfter(Element*) const |
297 { | 300 { |
298 ASSERT_NOT_REACHED(); | 301 ASSERT_NOT_REACHED(); |
299 return 0; | 302 return 0; |
300 } | 303 } |
301 | 304 |
302 static inline bool nameShouldBeVisibleInDocumentAll(const HTMLElement& element) | 305 static inline bool nameShouldBeVisibleInDocumentAll(const HTMLElement& element) |
303 { | 306 { |
304 // http://www.whatwg.org/specs/web-apps/current-work/multipage/common-dom-in
terfaces.html#dom-htmlallcollection-nameditem: | 307 // 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, | 308 // The document.all collection returns only certain types of elements by nam
e, |
306 // although it returns any type of element by id. | 309 // although it returns any type of element by id. |
307 return element.hasTagName(aTag) | 310 return element.hasTagName(aTag) |
308 || element.hasTagName(appletTag) | 311 || element.hasTagName(appletTag) |
309 || element.hasTagName(areaTag) | 312 || element.hasTagName(areaTag) |
310 || element.hasTagName(embedTag) | 313 || element.hasTagName(embedTag) |
311 || element.hasTagName(formTag) | 314 || element.hasTagName(formTag) |
312 || element.hasTagName(frameTag) | 315 || element.hasTagName(frameTag) |
313 || element.hasTagName(framesetTag) | 316 || element.hasTagName(framesetTag) |
314 || element.hasTagName(iframeTag) | 317 || element.hasTagName(iframeTag) |
315 || element.hasTagName(imgTag) | 318 || element.hasTagName(imgTag) |
316 || element.hasTagName(inputTag) | 319 || element.hasTagName(inputTag) |
317 || element.hasTagName(objectTag) | 320 || element.hasTagName(objectTag) |
318 || element.hasTagName(selectTag); | 321 || element.hasTagName(selectTag); |
319 } | 322 } |
320 | 323 |
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 | 324 Element* HTMLCollection::traverseToFirstElement() const |
356 { | 325 { |
357 switch (type()) { | 326 switch (type()) { |
358 case HTMLTagCollectionType: | 327 case HTMLTagCollectionType: |
359 return firstMatchingElement(toHTMLTagCollection(*this)); | 328 return ElementTraversal::firstWithin(rootNode(), IsMatch<HTMLTagCollecti
on>(toHTMLTagCollection(*this))); |
360 case ClassCollectionType: | 329 case ClassCollectionType: |
361 return firstMatchingElement(toClassCollection(*this)); | 330 return ElementTraversal::firstWithin(rootNode(), IsMatch<ClassCollection
>(toClassCollection(*this))); |
362 default: | 331 default: |
363 if (overridesItemAfter()) | 332 if (overridesItemAfter()) |
364 return virtualItemAfter(0); | 333 return virtualItemAfter(0); |
365 if (shouldOnlyIncludeDirectChildren()) | 334 if (shouldOnlyIncludeDirectChildren()) |
366 return firstMatchingChildElement(*this); | 335 return ElementTraversal::firstChild(rootNode(), IsMatch<HTMLCollecti
on>(*this)); |
367 return firstMatchingElement(*this); | 336 return ElementTraversal::firstWithin(rootNode(), IsMatch<HTMLCollection>
(*this)); |
368 } | 337 } |
369 } | 338 } |
370 | 339 |
371 Element* HTMLCollection::traverseToLastElement() const | 340 Element* HTMLCollection::traverseToLastElement() const |
372 { | 341 { |
373 ASSERT(canTraverseBackward()); | 342 ASSERT(canTraverseBackward()); |
374 if (shouldOnlyIncludeDirectChildren()) | 343 if (shouldOnlyIncludeDirectChildren()) |
375 return lastMatchingChildElement(*this); | 344 return ElementTraversal::lastChild(rootNode(), IsMatch<HTMLCollection>(*
this)); |
376 return lastMatchingElement(*this); | 345 return ElementTraversal::lastWithin(rootNode(), IsMatch<HTMLCollection>(*thi
s)); |
377 } | 346 } |
378 | 347 |
379 Element* HTMLCollection::traverseForwardToOffset(unsigned offset, Element& curre
ntElement, unsigned& currentOffset) const | 348 Element* HTMLCollection::traverseForwardToOffset(unsigned offset, Element& curre
ntElement, unsigned& currentOffset) const |
380 { | 349 { |
381 ASSERT(currentOffset < offset); | 350 ASSERT(currentOffset < offset); |
382 switch (type()) { | 351 switch (type()) { |
383 case HTMLTagCollectionType: | 352 case HTMLTagCollectionType: |
384 return traverseMatchingElementsForwardToOffset(toHTMLTagCollection(*this
), offset, currentElement, currentOffset); | 353 return traverseMatchingElementsForwardToOffset(currentElement, &rootNode
(), offset, currentOffset, IsMatch<HTMLTagCollection>(toHTMLTagCollection(*this)
)); |
385 case ClassCollectionType: | 354 case ClassCollectionType: |
386 return traverseMatchingElementsForwardToOffset(toClassCollection(*this),
offset, currentElement, currentOffset); | 355 return traverseMatchingElementsForwardToOffset(currentElement, &rootNode
(), offset, currentOffset, IsMatch<ClassCollection>(toClassCollection(*this))); |
387 default: | 356 default: |
388 if (overridesItemAfter()) { | 357 if (overridesItemAfter()) { |
389 for (Element* next = virtualItemAfter(¤tElement); next; next =
virtualItemAfter(next)) { | 358 for (Element* next = virtualItemAfter(¤tElement); next; next =
virtualItemAfter(next)) { |
390 if (++currentOffset == offset) | 359 if (++currentOffset == offset) |
391 return next; | 360 return next; |
392 } | 361 } |
393 return 0; | 362 return 0; |
394 } | 363 } |
395 if (shouldOnlyIncludeDirectChildren()) { | 364 if (shouldOnlyIncludeDirectChildren()) { |
396 for (Element* next = nextMatchingChildElement(*this, currentElement)
; next; next = nextMatchingChildElement(*this, *next)) { | 365 IsMatch<HTMLCollection> isMatch(*this); |
| 366 for (Element* next = ElementTraversal::nextSibling(currentElement, i
sMatch); next; next = ElementTraversal::nextSibling(*next, isMatch)) { |
397 if (++currentOffset == offset) | 367 if (++currentOffset == offset) |
398 return next; | 368 return next; |
399 } | 369 } |
400 return 0; | 370 return 0; |
401 } | 371 } |
402 return traverseMatchingElementsForwardToOffset(*this, offset, currentEle
ment, currentOffset); | 372 return traverseMatchingElementsForwardToOffset(currentElement, &rootNode
(), offset, currentOffset, IsMatch<HTMLCollection>(*this)); |
403 } | 373 } |
404 } | 374 } |
405 | 375 |
406 Element* HTMLCollection::traverseBackwardToOffset(unsigned offset, Element& curr
entElement, unsigned& currentOffset) const | 376 Element* HTMLCollection::traverseBackwardToOffset(unsigned offset, Element& curr
entElement, unsigned& currentOffset) const |
407 { | 377 { |
408 ASSERT(currentOffset > offset); | 378 ASSERT(currentOffset > offset); |
409 ASSERT(canTraverseBackward()); | 379 ASSERT(canTraverseBackward()); |
410 if (shouldOnlyIncludeDirectChildren()) { | 380 if (shouldOnlyIncludeDirectChildren()) { |
411 for (Element* previous = previousMatchingChildElement(*this, currentElem
ent); previous; previous = previousMatchingChildElement(*this, *previous)) { | 381 IsMatch<HTMLCollection> isMatch(*this); |
| 382 for (Element* previous = ElementTraversal::previousSibling(currentElemen
t, isMatch); previous; previous = ElementTraversal::previousSibling(*previous, i
sMatch)) { |
412 if (--currentOffset == offset) | 383 if (--currentOffset == offset) |
413 return previous; | 384 return previous; |
414 } | 385 } |
415 return 0; | 386 return 0; |
416 } | 387 } |
417 return traverseMatchingElementsBackwardToOffset(*this, offset, currentElemen
t, currentOffset); | 388 return traverseMatchingElementsBackwardToOffset(currentElement, &rootNode(),
offset, currentOffset, IsMatch<HTMLCollection>(*this)); |
418 } | 389 } |
419 | 390 |
420 Element* HTMLCollection::namedItem(const AtomicString& name) const | 391 Element* HTMLCollection::namedItem(const AtomicString& name) const |
421 { | 392 { |
422 // http://msdn.microsoft.com/workshop/author/dhtml/reference/methods/namedit
em.asp | 393 // http://msdn.microsoft.com/workshop/author/dhtml/reference/methods/namedit
em.asp |
423 // This method first searches for an object with a matching id | 394 // 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 | 395 // 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 | 396 // object with a matching name attribute, but only on those elements |
426 // that are allowed a name attribute. | 397 // that are allowed a name attribute. |
427 updateIdNameCache(); | 398 updateIdNameCache(); |
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
525 } | 496 } |
526 | 497 |
527 void HTMLCollection::trace(Visitor* visitor) | 498 void HTMLCollection::trace(Visitor* visitor) |
528 { | 499 { |
529 visitor->trace(m_namedItemCache); | 500 visitor->trace(m_namedItemCache); |
530 visitor->trace(m_collectionIndexCache); | 501 visitor->trace(m_collectionIndexCache); |
531 LiveNodeListBase::trace(visitor); | 502 LiveNodeListBase::trace(visitor); |
532 } | 503 } |
533 | 504 |
534 } // namespace blink | 505 } // namespace blink |
OLD | NEW |