| 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 |