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 235 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
246 } | 246 } |
247 | 247 |
248 invalidateShadowTree(); | 248 invalidateShadowTree(); |
249 | 249 |
250 return; | 250 return; |
251 } | 251 } |
252 | 252 |
253 SVGGraphicsElement::svgAttributeChanged(attrName); | 253 SVGGraphicsElement::svgAttributeChanged(attrName); |
254 } | 254 } |
255 | 255 |
256 static bool isDisallowedElement(const Node* node) | 256 static bool isDisallowedElement(const Node& node) |
257 { | 257 { |
258 // Spec: "Any 'svg', 'symbol', 'g', graphics element or other 'use' is poten
tially a template object that can be re-used | 258 // Spec: "Any 'svg', 'symbol', 'g', graphics element or other 'use' is poten
tially a template object that can be re-used |
259 // (i.e., "instanced") in the SVG document via a 'use' element." | 259 // (i.e., "instanced") in the SVG document via a 'use' element." |
260 // "Graphics Element" is defined as 'circle', 'ellipse', 'image', 'line', 'p
ath', 'polygon', 'polyline', 'rect', 'text' | 260 // "Graphics Element" is defined as 'circle', 'ellipse', 'image', 'line', 'p
ath', 'polygon', 'polyline', 'rect', 'text' |
261 // Excluded are anything that is used by reference or that only make sense t
o appear once in a document. | 261 // Excluded are anything that is used by reference or that only make sense t
o appear once in a document. |
262 // We must also allow the shadow roots of other use elements. | 262 // We must also allow the shadow roots of other use elements. |
263 if (node->isShadowRoot() || node->isTextNode()) | 263 if (node.isShadowRoot() || node.isTextNode()) |
264 return false; | 264 return false; |
265 | 265 |
266 if (!node->isSVGElement()) | 266 if (!node.isSVGElement()) |
267 return true; | 267 return true; |
268 | 268 |
269 const Element* element = toElement(node); | 269 const Element& element = toElement(node); |
270 | 270 |
271 DEFINE_STATIC_LOCAL(HashSet<QualifiedName>, allowedElementTags, ()); | 271 DEFINE_STATIC_LOCAL(HashSet<QualifiedName>, allowedElementTags, ()); |
272 if (allowedElementTags.isEmpty()) { | 272 if (allowedElementTags.isEmpty()) { |
273 allowedElementTags.add(SVGNames::aTag); | 273 allowedElementTags.add(SVGNames::aTag); |
274 allowedElementTags.add(SVGNames::circleTag); | 274 allowedElementTags.add(SVGNames::circleTag); |
275 allowedElementTags.add(SVGNames::descTag); | 275 allowedElementTags.add(SVGNames::descTag); |
276 allowedElementTags.add(SVGNames::ellipseTag); | 276 allowedElementTags.add(SVGNames::ellipseTag); |
277 allowedElementTags.add(SVGNames::gTag); | 277 allowedElementTags.add(SVGNames::gTag); |
278 allowedElementTags.add(SVGNames::imageTag); | 278 allowedElementTags.add(SVGNames::imageTag); |
279 allowedElementTags.add(SVGNames::lineTag); | 279 allowedElementTags.add(SVGNames::lineTag); |
280 allowedElementTags.add(SVGNames::metadataTag); | 280 allowedElementTags.add(SVGNames::metadataTag); |
281 allowedElementTags.add(SVGNames::pathTag); | 281 allowedElementTags.add(SVGNames::pathTag); |
282 allowedElementTags.add(SVGNames::polygonTag); | 282 allowedElementTags.add(SVGNames::polygonTag); |
283 allowedElementTags.add(SVGNames::polylineTag); | 283 allowedElementTags.add(SVGNames::polylineTag); |
284 allowedElementTags.add(SVGNames::rectTag); | 284 allowedElementTags.add(SVGNames::rectTag); |
285 allowedElementTags.add(SVGNames::svgTag); | 285 allowedElementTags.add(SVGNames::svgTag); |
286 allowedElementTags.add(SVGNames::switchTag); | 286 allowedElementTags.add(SVGNames::switchTag); |
287 allowedElementTags.add(SVGNames::symbolTag); | 287 allowedElementTags.add(SVGNames::symbolTag); |
288 allowedElementTags.add(SVGNames::textTag); | 288 allowedElementTags.add(SVGNames::textTag); |
289 allowedElementTags.add(SVGNames::textPathTag); | 289 allowedElementTags.add(SVGNames::textPathTag); |
290 allowedElementTags.add(SVGNames::titleTag); | 290 allowedElementTags.add(SVGNames::titleTag); |
291 allowedElementTags.add(SVGNames::tspanTag); | 291 allowedElementTags.add(SVGNames::tspanTag); |
292 allowedElementTags.add(SVGNames::useTag); | 292 allowedElementTags.add(SVGNames::useTag); |
293 } | 293 } |
294 return !allowedElementTags.contains<SVGAttributeHashTranslator>(element->tag
QName()); | 294 return !allowedElementTags.contains<SVGAttributeHashTranslator>(element.tagQ
Name()); |
295 } | |
296 | |
297 static bool subtreeContainsDisallowedElement(const Node* start) | |
298 { | |
299 if (isDisallowedElement(start)) | |
300 return true; | |
301 | |
302 for (const Node* cur = start->firstChild(); cur; cur = cur->nextSibling()) { | |
303 if (subtreeContainsDisallowedElement(cur)) | |
304 return true; | |
305 } | |
306 | |
307 return false; | |
308 } | 295 } |
309 | 296 |
310 void SVGUseElement::scheduleShadowTreeRecreation() | 297 void SVGUseElement::scheduleShadowTreeRecreation() |
311 { | 298 { |
312 if (inUseShadowTree()) | 299 if (inUseShadowTree()) |
313 return; | 300 return; |
314 m_needsShadowTreeRecreation = true; | 301 m_needsShadowTreeRecreation = true; |
315 document().scheduleUseShadowTreeUpdate(*this); | 302 document().scheduleUseShadowTreeUpdate(*this); |
316 } | 303 } |
317 | 304 |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
391 ASSERT(!m_needsShadowTreeRecreation); | 378 ASSERT(!m_needsShadowTreeRecreation); |
392 | 379 |
393 // <use> creates a "user agent" shadow root. Do not build the shadow/instanc
e tree for <use> | 380 // <use> creates a "user agent" shadow root. Do not build the shadow/instanc
e tree for <use> |
394 // elements living in a user agent shadow tree because they will get expande
d in a second | 381 // elements living in a user agent shadow tree because they will get expande
d in a second |
395 // pass -- see expandUseElementsInShadowTree(). | 382 // pass -- see expandUseElementsInShadowTree(). |
396 if (inUseShadowTree()) | 383 if (inUseShadowTree()) |
397 return; | 384 return; |
398 | 385 |
399 // Do not allow self-referencing. | 386 // Do not allow self-referencing. |
400 // 'target' may be null, if it's a non SVG namespaced element. | 387 // 'target' may be null, if it's a non SVG namespaced element. |
401 if (!target || target == this || isDisallowedElement(target)) | 388 if (!target || target == this || isDisallowedElement(*target)) |
402 return; | 389 return; |
403 | 390 |
404 // Set up root SVG element in shadow tree. | 391 // Set up root SVG element in shadow tree. |
405 RefPtrWillBeRawPtr<Element> newChild = target->cloneElementWithoutChildren()
; | 392 RefPtrWillBeRawPtr<Element> newChild = target->cloneElementWithoutChildren()
; |
406 m_targetElementInstance = toSVGElement(newChild.get()); | 393 m_targetElementInstance = toSVGElement(newChild.get()); |
407 ShadowRoot* shadowTreeRootElement = userAgentShadowRoot(); | 394 ShadowRoot* shadowTreeRootElement = userAgentShadowRoot(); |
408 shadowTreeRootElement->appendChild(newChild.release()); | 395 shadowTreeRootElement->appendChild(newChild.release()); |
409 | 396 |
410 // Clone the target subtree into the shadow tree, not handling <use> and <sy
mbol> yet. | 397 // Clone the target subtree into the shadow tree, not handling <use> and <sy
mbol> yet. |
411 | 398 |
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
499 return nullptr; | 486 return nullptr; |
500 } | 487 } |
501 | 488 |
502 return &toSVGGraphicsElement(element); | 489 return &toSVGGraphicsElement(element); |
503 } | 490 } |
504 | 491 |
505 void SVGUseElement::buildShadowTree(SVGElement* target, SVGElement* targetInstan
ce, bool foundUse) | 492 void SVGUseElement::buildShadowTree(SVGElement* target, SVGElement* targetInstan
ce, bool foundUse) |
506 { | 493 { |
507 ASSERT(target); | 494 ASSERT(target); |
508 ASSERT(targetInstance); | 495 ASSERT(targetInstance); |
509 ASSERT(!isDisallowedElement(target)); | 496 ASSERT(!isDisallowedElement(*target)); |
510 | 497 |
511 // Spec: If the referenced object is itself a 'use', or if there are 'use' s
ubelements within the referenced | 498 // Spec: If the referenced object is itself a 'use', or if there are 'use' s
ubelements within the referenced |
512 // object, the instance tree will contain recursive expansion of the indirec
t references to form a complete tree. | 499 // object, the instance tree will contain recursive expansion of the indirec
t references to form a complete tree. |
513 if (isSVGUseElement(*target)) { | 500 if (isSVGUseElement(*target)) { |
514 // We only need to track first degree <use> dependencies. Indirect refer
ences are handled | 501 // We only need to track first degree <use> dependencies. Indirect refer
ences are handled |
515 // as the invalidation bubbles up the dependency chain. | 502 // as the invalidation bubbles up the dependency chain. |
516 if (!foundUse && !isStructurallyExternal()) { | 503 if (!foundUse && !isStructurallyExternal()) { |
517 addReferenceTo(target); | 504 addReferenceTo(target); |
518 foundUse = true; | 505 foundUse = true; |
519 } | 506 } |
520 } | 507 } |
521 | 508 |
522 targetInstance->setCorrespondingElement(target); | 509 targetInstance->setCorrespondingElement(target); |
523 | 510 |
524 for (RefPtrWillBeRawPtr<Node> child = target->firstChild(); child; child = c
hild->nextSibling()) { | 511 for (RefPtrWillBeRawPtr<Node> child = target->firstChild(); child; child = c
hild->nextSibling()) { |
525 // Skip any disallowed element. | 512 // Skip any disallowed element. |
526 if (isDisallowedElement(child.get())) | 513 if (isDisallowedElement(*child)) |
527 continue; | 514 continue; |
528 | 515 |
529 RefPtrWillBeRawPtr<Node> newChild = child->cloneNode(false); | 516 RefPtrWillBeRawPtr<Node> newChild = child->cloneNode(false); |
530 targetInstance->appendChild(newChild.get()); | 517 targetInstance->appendChild(newChild.get()); |
531 if (newChild->isSVGElement()) { | 518 if (newChild->isSVGElement()) { |
532 // Enter recursion, appending new instance tree nodes to the "instan
ce" object. | 519 // Enter recursion, appending new instance tree nodes to the "instan
ce" object. |
533 buildShadowTree(toSVGElement(child), toSVGElement(newChild), foundUs
e); | 520 buildShadowTree(toSVGElement(child), toSVGElement(newChild), foundUs
e); |
534 } | 521 } |
535 } | 522 } |
536 } | 523 } |
(...skipping 26 matching lines...) Expand all Loading... |
563 while (instance && instance->isSVGElement()) { | 550 while (instance && instance->isSVGElement()) { |
564 SVGElement* element = toSVGElement(instance); | 551 SVGElement* element = toSVGElement(instance); |
565 if (element->hasID() && element->getIdAttribute() == targetId && element
->document() == newTarget->document()) | 552 if (element->hasID() && element->getIdAttribute() == targetId && element
->document() == newTarget->document()) |
566 return true; | 553 return true; |
567 | 554 |
568 instance = instance->parentNode(); | 555 instance = instance->parentNode(); |
569 } | 556 } |
570 return false; | 557 return false; |
571 } | 558 } |
572 | 559 |
573 static inline void removeDisallowedElementsFromSubtree(Element& subtree) | 560 // We don't walk the target tree element-by-element, and clone each element, |
| 561 // but instead use cloneNode(deep=true). This is an optimization for the common |
| 562 // case where <use> doesn't contain disallowed elements (ie. <foreignObject>). |
| 563 // Though if there are disallowed elements in the subtree, we have to remove |
| 564 // them. For instance: <use> on <g> containing <foreignObject> (indirect |
| 565 // case). |
| 566 static inline void removeDisallowedElementsFromSubtree(SVGElement& subtree) |
574 { | 567 { |
575 ASSERT(!subtree.inDocument()); | 568 ASSERT(!subtree.inDocument()); |
576 Element* element = ElementTraversal::firstWithin(subtree); | 569 Element* element = ElementTraversal::firstWithin(subtree); |
577 while (element) { | 570 while (element) { |
578 if (isDisallowedElement(element)) { | 571 if (isDisallowedElement(*element)) { |
579 Element* next = ElementTraversal::nextSkippingChildren(*element, &su
btree); | 572 Element* next = ElementTraversal::nextSkippingChildren(*element, &su
btree); |
580 // The subtree is not in document so this won't generate events that
could mutate the tree. | 573 // The subtree is not in document so this won't generate events that
could mutate the tree. |
581 element->parentNode()->removeChild(element); | 574 element->parentNode()->removeChild(element); |
582 element = next; | 575 element = next; |
583 } else { | 576 } else { |
584 element = ElementTraversal::next(*element, &subtree); | 577 element = ElementTraversal::next(*element, &subtree); |
585 } | 578 } |
586 } | 579 } |
587 } | 580 } |
588 | 581 |
(...skipping 26 matching lines...) Expand all Loading... |
615 // actual shadow tree (after the special case modification for svg/symbol) w
e have | 608 // actual shadow tree (after the special case modification for svg/symbol) w
e have |
616 // to walk it completely and expand all <use> elements. | 609 // to walk it completely and expand all <use> elements. |
617 ShadowRoot* shadowRoot = userAgentShadowRoot(); | 610 ShadowRoot* shadowRoot = userAgentShadowRoot(); |
618 for (RefPtrWillBeRawPtr<SVGUseElement> use = Traversal<SVGUseElement>::first
Within(*shadowRoot); use; ) { | 611 for (RefPtrWillBeRawPtr<SVGUseElement> use = Traversal<SVGUseElement>::first
Within(*shadowRoot); use; ) { |
619 ASSERT(!use->resourceIsStillLoading()); | 612 ASSERT(!use->resourceIsStillLoading()); |
620 | 613 |
621 SVGElement* target = 0; | 614 SVGElement* target = 0; |
622 if (hasCycleUseReferencing(toSVGUseElement(use->correspondingElement()),
use.get(), target)) | 615 if (hasCycleUseReferencing(toSVGUseElement(use->correspondingElement()),
use.get(), target)) |
623 return false; | 616 return false; |
624 | 617 |
625 if (target && isDisallowedElement(target)) | 618 if (target && isDisallowedElement(*target)) |
626 return false; | 619 return false; |
627 // Don't ASSERT(target) here, it may be "pending", too. | 620 // Don't ASSERT(target) here, it may be "pending", too. |
628 // Setup sub-shadow tree root node | 621 // Setup sub-shadow tree root node |
629 RefPtrWillBeRawPtr<SVGGElement> cloneParent = SVGGElement::create(refere
ncedScope()->document()); | 622 RefPtrWillBeRawPtr<SVGGElement> cloneParent = SVGGElement::create(refere
ncedScope()->document()); |
630 // Transfer all data (attributes, etc.) from <use> to the new <g> elemen
t. | 623 // Transfer all data (attributes, etc.) from <use> to the new <g> elemen
t. |
631 cloneParent->cloneDataFromElement(*use); | 624 cloneParent->cloneDataFromElement(*use); |
632 cloneParent->setCorrespondingElement(use->correspondingElement()); | 625 cloneParent->setCorrespondingElement(use->correspondingElement()); |
633 | 626 |
634 // Spec: In the generated content, the 'use' will be replaced by 'g', wh
ere all attributes from the | 627 // Spec: In the generated content, the 'use' will be replaced by 'g', wh
ere all attributes from the |
635 // 'use' element except for x, y, width, height and xlink:href are trans
ferred to the generated 'g' element. | 628 // 'use' element except for x, y, width, height and xlink:href are trans
ferred to the generated 'g' element. |
636 removeAttributesFromReplacementElement(*cloneParent); | 629 removeAttributesFromReplacementElement(*cloneParent); |
637 | 630 |
638 // Move already cloned elements to the new <g> element. | 631 // Move already cloned elements to the new <g> element. |
639 moveChildrenToReplacementElement(*use, *cloneParent); | 632 moveChildrenToReplacementElement(*use, *cloneParent); |
640 | 633 |
641 if (target) { | 634 if (target) { |
642 RefPtrWillBeRawPtr<Node> newChild = cloneNodeAndAssociate(*target); | 635 RefPtrWillBeRawPtr<Node> newChild = cloneNodeAndAssociate(*target); |
643 ASSERT(newChild->isSVGElement()); | 636 ASSERT(newChild->isSVGElement()); |
644 transferUseWidthAndHeightIfNeeded(*use, toSVGElement(newChild.get())
, *target); | 637 transferUseWidthAndHeightIfNeeded(*use, toSVGElement(newChild.get())
, *target); |
645 cloneParent->appendChild(newChild.release()); | 638 cloneParent->appendChild(newChild.release()); |
646 } | 639 } |
647 | 640 |
648 // We don't walk the target tree element-by-element, and clone each elem
ent, | 641 removeDisallowedElementsFromSubtree(*cloneParent); |
649 // but instead use cloneElementWithChildren(). This is an optimization f
or the common | |
650 // case where <use> doesn't contain disallowed elements (ie. <foreignObj
ect>). | |
651 // Though if there are disallowed elements in the subtree, we have to re
move them. | |
652 // For instance: <use> on <g> containing <foreignObject> (indirect case)
. | |
653 if (subtreeContainsDisallowedElement(cloneParent.get())) | |
654 removeDisallowedElementsFromSubtree(*cloneParent); | |
655 | 642 |
656 RefPtrWillBeRawPtr<SVGElement> replacingElement(cloneParent.get()); | 643 RefPtrWillBeRawPtr<SVGElement> replacingElement(cloneParent.get()); |
657 | 644 |
658 // Replace <use> with referenced content. | 645 // Replace <use> with referenced content. |
659 use->parentNode()->replaceChild(cloneParent.release(), use); | 646 use->parentNode()->replaceChild(cloneParent.release(), use); |
660 | 647 |
661 use = Traversal<SVGUseElement>::next(*replacingElement, shadowRoot); | 648 use = Traversal<SVGUseElement>::next(*replacingElement, shadowRoot); |
662 } | 649 } |
663 return true; | 650 return true; |
664 } | 651 } |
(...skipping 10 matching lines...) Expand all Loading... |
675 // 'svg' element will use values of 100% for these attributes. | 662 // 'svg' element will use values of 100% for these attributes. |
676 ASSERT(referencedScope()); | 663 ASSERT(referencedScope()); |
677 RefPtrWillBeRawPtr<SVGSVGElement> svgElement = SVGSVGElement::create(ref
erencedScope()->document()); | 664 RefPtrWillBeRawPtr<SVGSVGElement> svgElement = SVGSVGElement::create(ref
erencedScope()->document()); |
678 // Transfer all data (attributes, etc.) from <symbol> to the new <svg> e
lement. | 665 // Transfer all data (attributes, etc.) from <symbol> to the new <svg> e
lement. |
679 svgElement->cloneDataFromElement(*symbol); | 666 svgElement->cloneDataFromElement(*symbol); |
680 svgElement->setCorrespondingElement(symbol->correspondingElement()); | 667 svgElement->setCorrespondingElement(symbol->correspondingElement()); |
681 | 668 |
682 // Move already cloned elements to the new <svg> element. | 669 // Move already cloned elements to the new <svg> element. |
683 moveChildrenToReplacementElement(*symbol, *svgElement); | 670 moveChildrenToReplacementElement(*symbol, *svgElement); |
684 | 671 |
685 // We don't walk the target tree element-by-element, and clone each elem
ent, | 672 removeDisallowedElementsFromSubtree(*svgElement); |
686 // but instead use cloneNode(deep=true). This is an optimization for the
common | |
687 // case where <use> doesn't contain disallowed elements (ie. <foreignObj
ect>). | |
688 // Though if there are disallowed elements in the subtree, we have to re
move them. | |
689 // For instance: <use> on <g> containing <foreignObject> (indirect case)
. | |
690 if (subtreeContainsDisallowedElement(svgElement.get())) | |
691 removeDisallowedElementsFromSubtree(*svgElement); | |
692 | 673 |
693 RefPtrWillBeRawPtr<SVGElement> replacingElement(svgElement.get()); | 674 RefPtrWillBeRawPtr<SVGElement> replacingElement(svgElement.get()); |
694 | 675 |
695 // Replace <symbol> with <svg>. | 676 // Replace <symbol> with <svg>. |
696 symbol->parentNode()->replaceChild(svgElement.release(), symbol); | 677 symbol->parentNode()->replaceChild(svgElement.release(), symbol); |
697 | 678 |
698 symbol = Traversal<SVGSymbolElement>::next(*replacingElement, shadowRoot
); | 679 symbol = Traversal<SVGSymbolElement>::next(*replacingElement, shadowRoot
); |
699 } | 680 } |
700 } | 681 } |
701 | 682 |
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
815 | 796 |
816 if (m_resource) | 797 if (m_resource) |
817 m_resource->removeClient(this); | 798 m_resource->removeClient(this); |
818 | 799 |
819 m_resource = resource; | 800 m_resource = resource; |
820 if (m_resource) | 801 if (m_resource) |
821 m_resource->addClient(this); | 802 m_resource->addClient(this); |
822 } | 803 } |
823 | 804 |
824 } // namespace blink | 805 } // namespace blink |
OLD | NEW |