OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2004, 2005, 2006, 2007, 2008 Nikolas Zimmermann <zimmermann@kde
.org> | 2 * Copyright (C) 2004, 2005, 2006, 2007, 2008 Nikolas Zimmermann <zimmermann@kde
.org> |
3 * Copyright (C) 2004, 2005, 2006, 2007 Rob Buis <buis@kde.org> | 3 * Copyright (C) 2004, 2005, 2006, 2007 Rob Buis <buis@kde.org> |
4 * Copyright (C) Research In Motion Limited 2009-2010. All rights reserved. | 4 * Copyright (C) Research In Motion Limited 2009-2010. All rights reserved. |
5 * Copyright (C) 2011 Torch Mobile (Beijing) Co. Ltd. All rights reserved. | 5 * Copyright (C) 2011 Torch Mobile (Beijing) Co. Ltd. All rights reserved. |
6 * Copyright (C) 2012 University of Szeged | 6 * Copyright (C) 2012 University of Szeged |
7 * Copyright (C) 2012 Renata Hodovan <reni@webkit.org> | 7 * Copyright (C) 2012 Renata Hodovan <reni@webkit.org> |
8 * | 8 * |
9 * This library is free software; you can redistribute it and/or | 9 * This library is free software; you can redistribute it and/or |
10 * modify it under the terms of the GNU Library General Public | 10 * modify it under the terms of the GNU Library General Public |
(...skipping 346 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
357 auto targetRange = Traversal<SVGElement>::inclusiveDescendantsOf(targetRoot)
; | 357 auto targetRange = Traversal<SVGElement>::inclusiveDescendantsOf(targetRoot)
; |
358 auto targetIterator = targetRange.begin(); | 358 auto targetIterator = targetRange.begin(); |
359 for (SVGElement& instance : Traversal<SVGElement>::inclusiveDescendantsOf(in
stanceRoot)) { | 359 for (SVGElement& instance : Traversal<SVGElement>::inclusiveDescendantsOf(in
stanceRoot)) { |
360 ASSERT(!instance.correspondingElement()); | 360 ASSERT(!instance.correspondingElement()); |
361 instance.setCorrespondingElement(&*targetIterator); | 361 instance.setCorrespondingElement(&*targetIterator); |
362 ++targetIterator; | 362 ++targetIterator; |
363 } | 363 } |
364 ASSERT(!(targetIterator != targetRange.end())); | 364 ASSERT(!(targetIterator != targetRange.end())); |
365 } | 365 } |
366 | 366 |
| 367 // We don't walk the target tree element-by-element, and clone each element, |
| 368 // but instead use cloneNode(deep=true). This is an optimization for the common |
| 369 // case where <use> doesn't contain disallowed elements (ie. <foreignObject>). |
| 370 // Though if there are disallowed elements in the subtree, we have to remove |
| 371 // them. For instance: <use> on <g> containing <foreignObject> (indirect |
| 372 // case). |
| 373 static inline void removeDisallowedElementsFromSubtree(SVGElement& subtree) |
| 374 { |
| 375 ASSERT(!subtree.inDocument()); |
| 376 Element* element = ElementTraversal::firstWithin(subtree); |
| 377 while (element) { |
| 378 if (isDisallowedElement(*element)) { |
| 379 Element* next = ElementTraversal::nextSkippingChildren(*element, &su
btree); |
| 380 // The subtree is not in document so this won't generate events that
could mutate the tree. |
| 381 element->parentNode()->removeChild(element); |
| 382 element = next; |
| 383 } else { |
| 384 element = ElementTraversal::next(*element, &subtree); |
| 385 } |
| 386 } |
| 387 } |
| 388 |
367 void SVGUseElement::buildShadowAndInstanceTree(SVGElement& target) | 389 void SVGUseElement::buildShadowAndInstanceTree(SVGElement& target) |
368 { | 390 { |
369 ASSERT(!m_targetElementInstance); | 391 ASSERT(!m_targetElementInstance); |
370 ASSERT(!m_needsShadowTreeRecreation); | 392 ASSERT(!m_needsShadowTreeRecreation); |
371 | 393 |
372 // <use> creates a "user agent" shadow root. Do not build the shadow/instanc
e tree for <use> | 394 // <use> creates a "user agent" shadow root. Do not build the shadow/instanc
e tree for <use> |
373 // elements living in a user agent shadow tree because they will get expande
d in a second | 395 // elements living in a user agent shadow tree because they will get expande
d in a second |
374 // pass -- see expandUseElementsInShadowTree(). | 396 // pass -- see expandUseElementsInShadowTree(). |
375 if (inUseShadowTree()) | 397 if (inUseShadowTree()) |
376 return; | 398 return; |
377 | 399 |
378 // Do not allow self-referencing. | 400 // Do not allow self-referencing. |
379 if (&target == this || isDisallowedElement(target)) | 401 if (&target == this || isDisallowedElement(target)) |
380 return; | 402 return; |
381 | 403 |
382 // Set up root SVG element in shadow tree. | 404 // Set up root SVG element in shadow tree. |
383 RefPtrWillBeRawPtr<Element> newChild = target.cloneElementWithoutChildren(); | 405 // Clone the target subtree into the shadow tree, not handling <use> and <sy
mbol> yet. |
384 m_targetElementInstance = toSVGElement(newChild.get()); | 406 RefPtrWillBeRawPtr<Element> instanceRoot = target.cloneElementWithChildren()
; |
| 407 ASSERT(instanceRoot->isSVGElement()); |
| 408 associateCorrespondingElements(target, toSVGElement(*instanceRoot)); |
| 409 removeDisallowedElementsFromSubtree(toSVGElement(*instanceRoot)); |
| 410 |
| 411 m_targetElementInstance = toSVGElement(instanceRoot.get()); |
385 ShadowRoot* shadowTreeRootElement = userAgentShadowRoot(); | 412 ShadowRoot* shadowTreeRootElement = userAgentShadowRoot(); |
386 shadowTreeRootElement->appendChild(newChild.release()); | 413 shadowTreeRootElement->appendChild(instanceRoot.release()); |
387 | |
388 // Clone the target subtree into the shadow tree, not handling <use> and <sy
mbol> yet. | |
389 | |
390 // SVG specification does not say a word about <use> & cycles. My view on th
is is: just ignore it! | |
391 // Non-appearing <use> content is easier to debug, then half-appearing conte
nt. | |
392 buildShadowTree(target, *m_targetElementInstance); | |
393 | 414 |
394 addReferencesToFirstDegreeNestedUseElements(target); | 415 addReferencesToFirstDegreeNestedUseElements(target); |
395 | 416 |
396 if (instanceTreeIsLoading()) { | 417 if (instanceTreeIsLoading()) { |
397 cloneNonMarkupEventListeners(); | 418 cloneNonMarkupEventListeners(); |
398 return; | 419 return; |
399 } | 420 } |
400 | 421 |
401 // Assure shadow tree building was successful. | 422 // Assure shadow tree building was successful. |
402 ASSERT(m_targetElementInstance); | 423 ASSERT(m_targetElementInstance); |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
489 return; | 510 return; |
490 // We only need to track first degree <use> dependencies. Indirect | 511 // We only need to track first degree <use> dependencies. Indirect |
491 // references are handled as the invalidation bubbles up the dependency | 512 // references are handled as the invalidation bubbles up the dependency |
492 // chain. | 513 // chain. |
493 SVGUseElement* useElement = | 514 SVGUseElement* useElement = |
494 isSVGUseElement(target) ? toSVGUseElement(&target) : Traversal<SVGUseEle
ment>::firstWithin(target); | 515 isSVGUseElement(target) ? toSVGUseElement(&target) : Traversal<SVGUseEle
ment>::firstWithin(target); |
495 for (; useElement; useElement = Traversal<SVGUseElement>::nextSkippingChildr
en(*useElement, &target)) | 516 for (; useElement; useElement = Traversal<SVGUseElement>::nextSkippingChildr
en(*useElement, &target)) |
496 addReferenceTo(useElement); | 517 addReferenceTo(useElement); |
497 } | 518 } |
498 | 519 |
499 void SVGUseElement::buildShadowTree(SVGElement& target, SVGElement& targetInstan
ce) | |
500 { | |
501 ASSERT(!isDisallowedElement(target)); | |
502 | |
503 targetInstance.setCorrespondingElement(&target); | |
504 | |
505 for (RefPtrWillBeRawPtr<Node> child = target.firstChild(); child; child = ch
ild->nextSibling()) { | |
506 // Skip any disallowed element. | |
507 if (isDisallowedElement(*child)) | |
508 continue; | |
509 | |
510 RefPtrWillBeRawPtr<Node> newChild = child->cloneNode(false); | |
511 targetInstance.appendChild(newChild.get()); | |
512 if (newChild->isSVGElement()) { | |
513 // Enter recursion, appending new instance tree nodes to the "instan
ce" object. | |
514 buildShadowTree(toSVGElement(*child), toSVGElement(*newChild)); | |
515 } | |
516 } | |
517 } | |
518 | |
519 void SVGUseElement::cloneNonMarkupEventListeners() | 520 void SVGUseElement::cloneNonMarkupEventListeners() |
520 { | 521 { |
521 for (SVGElement& element : Traversal<SVGElement>::descendantsOf(*userAgentSh
adowRoot())) { | 522 for (SVGElement& element : Traversal<SVGElement>::descendantsOf(*userAgentSh
adowRoot())) { |
522 if (EventTargetData* data = element.correspondingElement()->eventTargetD
ata()) | 523 if (EventTargetData* data = element.correspondingElement()->eventTargetD
ata()) |
523 data->eventListenerMap.copyEventListenersNotCreatedFromMarkupToTarge
t(&element); | 524 data->eventListenerMap.copyEventListenersNotCreatedFromMarkupToTarge
t(&element); |
524 } | 525 } |
525 } | 526 } |
526 | 527 |
527 bool SVGUseElement::hasCycleUseReferencing(const SVGUseElement& use, const Conta
inerNode& targetInstance, SVGElement*& newTarget) const | 528 bool SVGUseElement::hasCycleUseReferencing(const SVGUseElement& use, const Conta
inerNode& targetInstance, SVGElement*& newTarget) const |
528 { | 529 { |
(...skipping 14 matching lines...) Expand all Loading... |
543 while (instance && instance->isSVGElement()) { | 544 while (instance && instance->isSVGElement()) { |
544 SVGElement* element = toSVGElement(instance); | 545 SVGElement* element = toSVGElement(instance); |
545 if (element->hasID() && element->getIdAttribute() == targetId && element
->document() == newTarget->document()) | 546 if (element->hasID() && element->getIdAttribute() == targetId && element
->document() == newTarget->document()) |
546 return true; | 547 return true; |
547 | 548 |
548 instance = instance->parentNode(); | 549 instance = instance->parentNode(); |
549 } | 550 } |
550 return false; | 551 return false; |
551 } | 552 } |
552 | 553 |
553 // We don't walk the target tree element-by-element, and clone each element, | |
554 // but instead use cloneNode(deep=true). This is an optimization for the common | |
555 // case where <use> doesn't contain disallowed elements (ie. <foreignObject>). | |
556 // Though if there are disallowed elements in the subtree, we have to remove | |
557 // them. For instance: <use> on <g> containing <foreignObject> (indirect | |
558 // case). | |
559 static inline void removeDisallowedElementsFromSubtree(SVGElement& subtree) | |
560 { | |
561 ASSERT(!subtree.inDocument()); | |
562 Element* element = ElementTraversal::firstWithin(subtree); | |
563 while (element) { | |
564 if (isDisallowedElement(*element)) { | |
565 Element* next = ElementTraversal::nextSkippingChildren(*element, &su
btree); | |
566 // The subtree is not in document so this won't generate events that
could mutate the tree. | |
567 element->parentNode()->removeChild(element); | |
568 element = next; | |
569 } else { | |
570 element = ElementTraversal::next(*element, &subtree); | |
571 } | |
572 } | |
573 } | |
574 | |
575 static void moveChildrenToReplacementElement(ContainerNode& sourceRoot, Containe
rNode& destinationRoot) | 554 static void moveChildrenToReplacementElement(ContainerNode& sourceRoot, Containe
rNode& destinationRoot) |
576 { | 555 { |
577 for (RefPtrWillBeRawPtr<Node> child = sourceRoot.firstChild(); child; ) { | 556 for (RefPtrWillBeRawPtr<Node> child = sourceRoot.firstChild(); child; ) { |
578 RefPtrWillBeRawPtr<Node> nextChild = child->nextSibling(); | 557 RefPtrWillBeRawPtr<Node> nextChild = child->nextSibling(); |
579 destinationRoot.appendChild(child); | 558 destinationRoot.appendChild(child); |
580 child = nextChild.release(); | 559 child = nextChild.release(); |
581 } | 560 } |
582 } | 561 } |
583 | 562 |
584 // Spec: In the generated content, the 'use' will be replaced by 'g', where all | 563 // Spec: In the generated content, the 'use' will be replaced by 'g', where all |
(...skipping 206 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
791 | 770 |
792 if (m_resource) | 771 if (m_resource) |
793 m_resource->removeClient(this); | 772 m_resource->removeClient(this); |
794 | 773 |
795 m_resource = resource; | 774 m_resource = resource; |
796 if (m_resource) | 775 if (m_resource) |
797 m_resource->addClient(this); | 776 m_resource->addClient(this); |
798 } | 777 } |
799 | 778 |
800 } // namespace blink | 779 } // namespace blink |
OLD | NEW |