OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2004, 2005, 2006, 2007, 2008 Nikolas Zimmermann | 2 * Copyright (C) 2004, 2005, 2006, 2007, 2008 Nikolas Zimmermann |
3 * <zimmermann@kde.org> | 3 * <zimmermann@kde.org> |
4 * Copyright (C) 2004, 2005, 2006, 2007 Rob Buis <buis@kde.org> | 4 * Copyright (C) 2004, 2005, 2006, 2007 Rob Buis <buis@kde.org> |
5 * Copyright (C) Research In Motion Limited 2009-2010. All rights reserved. | 5 * Copyright (C) Research In Motion Limited 2009-2010. All rights reserved. |
6 * Copyright (C) 2011 Torch Mobile (Beijing) Co. Ltd. All rights reserved. | 6 * Copyright (C) 2011 Torch Mobile (Beijing) Co. Ltd. All rights reserved. |
7 * Copyright (C) 2012 University of Szeged | 7 * Copyright (C) 2012 University of Szeged |
8 * Copyright (C) 2012 Renata Hodovan <reni@webkit.org> | 8 * Copyright (C) 2012 Renata Hodovan <reni@webkit.org> |
9 * | 9 * |
10 * This library is free software; you can redistribute it and/or | 10 * This library is free software; you can redistribute it and/or |
(...skipping 14 matching lines...) Expand all Loading... |
25 | 25 |
26 #include "core/svg/SVGUseElement.h" | 26 #include "core/svg/SVGUseElement.h" |
27 | 27 |
28 #include "core/SVGNames.h" | 28 #include "core/SVGNames.h" |
29 #include "core/XLinkNames.h" | 29 #include "core/XLinkNames.h" |
30 #include "core/dom/Document.h" | 30 #include "core/dom/Document.h" |
31 #include "core/dom/ElementTraversal.h" | 31 #include "core/dom/ElementTraversal.h" |
32 #include "core/dom/IdTargetObserver.h" | 32 #include "core/dom/IdTargetObserver.h" |
33 #include "core/dom/StyleChangeReason.h" | 33 #include "core/dom/StyleChangeReason.h" |
34 #include "core/dom/TaskRunnerHelper.h" | 34 #include "core/dom/TaskRunnerHelper.h" |
| 35 #include "core/dom/shadow/ElementShadow.h" |
35 #include "core/dom/shadow/ShadowRoot.h" | 36 #include "core/dom/shadow/ShadowRoot.h" |
36 #include "core/events/Event.h" | 37 #include "core/events/Event.h" |
37 #include "core/layout/svg/LayoutSVGTransformableContainer.h" | 38 #include "core/layout/svg/LayoutSVGTransformableContainer.h" |
38 #include "core/svg/SVGGElement.h" | 39 #include "core/svg/SVGGElement.h" |
39 #include "core/svg/SVGLengthContext.h" | 40 #include "core/svg/SVGLengthContext.h" |
40 #include "core/svg/SVGSVGElement.h" | 41 #include "core/svg/SVGSVGElement.h" |
41 #include "core/svg/SVGSymbolElement.h" | 42 #include "core/svg/SVGSymbolElement.h" |
42 #include "core/svg/SVGTitleElement.h" | 43 #include "core/svg/SVGTitleElement.h" |
43 #include "core/xml/parser/XMLDocumentParser.h" | 44 #include "core/xml/parser/XMLDocumentParser.h" |
44 #include "platform/loader/fetch/FetchRequest.h" | 45 #include "platform/loader/fetch/FetchRequest.h" |
(...skipping 28 matching lines...) Expand all Loading... |
73 | 74 |
74 addToPropertyMap(m_x); | 75 addToPropertyMap(m_x); |
75 addToPropertyMap(m_y); | 76 addToPropertyMap(m_y); |
76 addToPropertyMap(m_width); | 77 addToPropertyMap(m_width); |
77 addToPropertyMap(m_height); | 78 addToPropertyMap(m_height); |
78 } | 79 } |
79 | 80 |
80 SVGUseElement* SVGUseElement::create(Document& document) { | 81 SVGUseElement* SVGUseElement::create(Document& document) { |
81 // Always build a user agent #shadow-root for SVGUseElement. | 82 // Always build a user agent #shadow-root for SVGUseElement. |
82 SVGUseElement* use = new SVGUseElement(document); | 83 SVGUseElement* use = new SVGUseElement(document); |
83 use->ensureUserAgentShadowRoot(); | 84 use->ensureShadow().addShadowRoot(*use, ShadowRootType::Closed); |
84 return use; | 85 return use; |
85 } | 86 } |
86 | 87 |
87 SVGUseElement::~SVGUseElement() {} | 88 SVGUseElement::~SVGUseElement() {} |
88 | 89 |
89 void SVGUseElement::dispose() { | 90 void SVGUseElement::dispose() { |
90 setDocumentResource(nullptr); | 91 setDocumentResource(nullptr); |
91 } | 92 } |
92 | 93 |
93 DEFINE_TRACE(SVGUseElement) { | 94 DEFINE_TRACE(SVGUseElement) { |
(...skipping 212 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
306 } | 307 } |
307 if (!resourceIsValid()) | 308 if (!resourceIsValid()) |
308 return nullptr; | 309 return nullptr; |
309 return m_resource->document()->getElementById(m_elementIdentifier); | 310 return m_resource->document()->getElementById(m_elementIdentifier); |
310 } | 311 } |
311 | 312 |
312 void SVGUseElement::buildPendingResource() { | 313 void SVGUseElement::buildPendingResource() { |
313 if (inUseShadowTree()) | 314 if (inUseShadowTree()) |
314 return; | 315 return; |
315 // FIXME: We should try to optimize this, to at least allow partial reclones. | 316 // FIXME: We should try to optimize this, to at least allow partial reclones. |
316 userAgentShadowRoot()->removeChildren(OmitSubtreeModifiedEvent); | 317 useShadowRoot().removeChildren(OmitSubtreeModifiedEvent); |
317 clearResourceReference(); | 318 clearResourceReference(); |
318 cancelShadowTreeRecreation(); | 319 cancelShadowTreeRecreation(); |
319 if (!isConnected()) | 320 if (!isConnected()) |
320 return; | 321 return; |
321 Element* target = resolveTargetElement(); | 322 Element* target = resolveTargetElement(); |
322 // TODO(fs): Why would the Element not be "connected" at this point? | 323 // TODO(fs): Why would the Element not be "connected" at this point? |
323 if (target && target->isConnected() && target->isSVGElement()) { | 324 if (target && target->isConnected() && target->isSVGElement()) { |
324 buildShadowAndInstanceTree(toSVGElement(*target)); | 325 buildShadowAndInstanceTree(toSVGElement(*target)); |
325 invalidateDependentShadowTrees(); | 326 invalidateDependentShadowTrees(); |
326 } | 327 } |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
413 targetRoot); | 414 targetRoot); |
414 associateCorrespondingElements(targetRoot, toSVGElement(*instanceRoot)); | 415 associateCorrespondingElements(targetRoot, toSVGElement(*instanceRoot)); |
415 removeDisallowedElementsFromSubtree(toSVGElement(*instanceRoot)); | 416 removeDisallowedElementsFromSubtree(toSVGElement(*instanceRoot)); |
416 return instanceRoot; | 417 return instanceRoot; |
417 } | 418 } |
418 | 419 |
419 void SVGUseElement::buildShadowAndInstanceTree(SVGElement& target) { | 420 void SVGUseElement::buildShadowAndInstanceTree(SVGElement& target) { |
420 DCHECK(!m_targetElementInstance); | 421 DCHECK(!m_targetElementInstance); |
421 DCHECK(!m_needsShadowTreeRecreation); | 422 DCHECK(!m_needsShadowTreeRecreation); |
422 | 423 |
423 // <use> creates a "user agent" shadow root. Do not build the shadow/instance | 424 // <use> creates a closed shadow root. Do not build the shadow/instance |
424 // tree for <use> elements living in a user agent shadow tree because they | 425 // tree for <use> elements living in a closed tree because they |
425 // will get expanded in a second pass -- see expandUseElementsInShadowTree(). | 426 // will get expanded in a second pass -- see expandUseElementsInShadowTree(). |
426 if (inUseShadowTree()) | 427 if (inUseShadowTree()) |
427 return; | 428 return; |
428 | 429 |
429 // Do not allow self-referencing. | 430 // Do not allow self-referencing. |
430 if (&target == this || isDisallowedElement(target)) | 431 if (&target == this || isDisallowedElement(target)) |
431 return; | 432 return; |
432 | 433 |
433 // Set up root SVG element in shadow tree. | 434 // Set up root SVG element in shadow tree. |
434 // Clone the target subtree into the shadow tree, not handling <use> and | 435 // Clone the target subtree into the shadow tree, not handling <use> and |
435 // <symbol> yet. | 436 // <symbol> yet. |
436 Element* instanceRoot = createInstanceTree(target); | 437 Element* instanceRoot = createInstanceTree(target); |
437 m_targetElementInstance = toSVGElement(instanceRoot); | 438 m_targetElementInstance = toSVGElement(instanceRoot); |
438 ShadowRoot* shadowTreeRootElement = userAgentShadowRoot(); | 439 ShadowRoot& shadowRoot = useShadowRoot(); |
439 shadowTreeRootElement->appendChild(instanceRoot); | 440 shadowRoot.appendChild(instanceRoot); |
440 | 441 |
441 addReferencesToFirstDegreeNestedUseElements(target); | 442 addReferencesToFirstDegreeNestedUseElements(target); |
442 | 443 |
443 if (instanceTreeIsLoading()) | 444 if (instanceTreeIsLoading()) |
444 return; | 445 return; |
445 | 446 |
446 // Assure shadow tree building was successful. | 447 // Assure shadow tree building was successful. |
447 DCHECK(m_targetElementInstance); | 448 DCHECK(m_targetElementInstance); |
448 DCHECK_EQ(m_targetElementInstance->correspondingUseElement(), this); | 449 DCHECK_EQ(m_targetElementInstance->correspondingUseElement(), this); |
449 DCHECK_EQ(m_targetElementInstance->correspondingElement(), &target); | 450 DCHECK_EQ(m_targetElementInstance->correspondingElement(), &target); |
450 | 451 |
451 // Expand all <use> elements in the shadow tree. | 452 // Expand all <use> elements in the shadow tree. |
452 // Expand means: replace the actual <use> element by what it references. | 453 // Expand means: replace the actual <use> element by what it references. |
453 if (!expandUseElementsInShadowTree()) { | 454 if (!expandUseElementsInShadowTree()) { |
454 shadowTreeRootElement->removeChildren(OmitSubtreeModifiedEvent); | 455 shadowRoot.removeChildren(OmitSubtreeModifiedEvent); |
455 clearResourceReference(); | 456 clearResourceReference(); |
456 return; | 457 return; |
457 } | 458 } |
458 | 459 |
459 // If the instance root was a <use>, it could have been replaced now, so | 460 // If the instance root was a <use>, it could have been replaced now, so |
460 // reset |m_targetElementInstance|. | 461 // reset |m_targetElementInstance|. |
461 m_targetElementInstance = | 462 m_targetElementInstance = toSVGElementOrDie(shadowRoot.firstChild()); |
462 toSVGElementOrDie(shadowTreeRootElement->firstChild()); | 463 DCHECK_EQ(m_targetElementInstance->parentNode(), shadowRoot); |
463 DCHECK_EQ(m_targetElementInstance->parentNode(), shadowTreeRootElement); | |
464 | 464 |
465 // Update relative length information. | 465 // Update relative length information. |
466 updateRelativeLengthsInformation(); | 466 updateRelativeLengthsInformation(); |
467 } | 467 } |
468 | 468 |
469 LayoutObject* SVGUseElement::createLayoutObject(const ComputedStyle&) { | 469 LayoutObject* SVGUseElement::createLayoutObject(const ComputedStyle&) { |
470 return new LayoutSVGTransformableContainer(this); | 470 return new LayoutSVGTransformableContainer(this); |
471 } | 471 } |
472 | 472 |
473 static bool isDirectReference(const SVGElement& element) { | 473 static bool isDirectReference(const SVGElement& element) { |
(...skipping 16 matching lines...) Expand all Loading... |
490 // FIXME: Avoid manual resolution of x/y here. Its potentially harmful. | 490 // FIXME: Avoid manual resolution of x/y here. Its potentially harmful. |
491 SVGLengthContext lengthContext(this); | 491 SVGLengthContext lengthContext(this); |
492 path.translate(FloatSize(m_x->currentValue()->value(lengthContext), | 492 path.translate(FloatSize(m_x->currentValue()->value(lengthContext), |
493 m_y->currentValue()->value(lengthContext))); | 493 m_y->currentValue()->value(lengthContext))); |
494 path.transform(calculateTransform(SVGElement::IncludeMotionTransform)); | 494 path.transform(calculateTransform(SVGElement::IncludeMotionTransform)); |
495 } | 495 } |
496 } | 496 } |
497 | 497 |
498 SVGGraphicsElement* SVGUseElement::visibleTargetGraphicsElementForClipping() | 498 SVGGraphicsElement* SVGUseElement::visibleTargetGraphicsElementForClipping() |
499 const { | 499 const { |
500 Node* n = userAgentShadowRoot()->firstChild(); | 500 Node* n = useShadowRoot().firstChild(); |
501 if (!n || !n->isSVGElement()) | 501 if (!n || !n->isSVGElement()) |
502 return nullptr; | 502 return nullptr; |
503 | 503 |
504 SVGElement& element = toSVGElement(*n); | 504 SVGElement& element = toSVGElement(*n); |
505 | 505 |
506 if (!element.isSVGGraphicsElement()) | 506 if (!element.isSVGGraphicsElement()) |
507 return nullptr; | 507 return nullptr; |
508 | 508 |
509 // Spec: "If a <use> element is a child of a clipPath element, it must | 509 // Spec: "If a <use> element is a child of a clipPath element, it must |
510 // directly reference <path>, <text> or basic shapes elements. Indirect | 510 // directly reference <path>, <text> or basic shapes elements. Indirect |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
578 } | 578 } |
579 | 579 |
580 bool SVGUseElement::expandUseElementsInShadowTree() { | 580 bool SVGUseElement::expandUseElementsInShadowTree() { |
581 // Why expand the <use> elements in the shadow tree here, and not just | 581 // Why expand the <use> elements in the shadow tree here, and not just |
582 // do this directly in buildShadowTree, if we encounter a <use> element? | 582 // do this directly in buildShadowTree, if we encounter a <use> element? |
583 // | 583 // |
584 // Short answer: Because we may miss to expand some elements. For example, if | 584 // Short answer: Because we may miss to expand some elements. For example, if |
585 // a <symbol> contains <use> tags, we'd miss them. So once we're done with | 585 // a <symbol> contains <use> tags, we'd miss them. So once we're done with |
586 // setting up the actual shadow tree (after the special case modification for | 586 // setting up the actual shadow tree (after the special case modification for |
587 // svg/symbol) we have to walk it completely and expand all <use> elements. | 587 // svg/symbol) we have to walk it completely and expand all <use> elements. |
588 ShadowRoot* shadowRoot = userAgentShadowRoot(); | 588 ShadowRoot& shadowRoot = useShadowRoot(); |
589 for (SVGUseElement* use = Traversal<SVGUseElement>::firstWithin(*shadowRoot); | 589 for (SVGUseElement* use = Traversal<SVGUseElement>::firstWithin(shadowRoot); |
590 use;) { | 590 use;) { |
591 DCHECK(!use->resourceIsStillLoading()); | 591 DCHECK(!use->resourceIsStillLoading()); |
592 | 592 |
593 SVGUseElement& originalUse = toSVGUseElement(*use->correspondingElement()); | 593 SVGUseElement& originalUse = toSVGUseElement(*use->correspondingElement()); |
594 SVGElement* target = nullptr; | 594 SVGElement* target = nullptr; |
595 if (hasCycleUseReferencing(originalUse, *use, target)) | 595 if (hasCycleUseReferencing(originalUse, *use, target)) |
596 return false; | 596 return false; |
597 | 597 |
598 if (target && isDisallowedElement(*target)) | 598 if (target && isDisallowedElement(*target)) |
599 return false; | 599 return false; |
(...skipping 10 matching lines...) Expand all Loading... |
610 moveChildrenToReplacementElement(*use, *cloneParent); | 610 moveChildrenToReplacementElement(*use, *cloneParent); |
611 | 611 |
612 if (target) | 612 if (target) |
613 cloneParent->appendChild(use->createInstanceTree(*target)); | 613 cloneParent->appendChild(use->createInstanceTree(*target)); |
614 | 614 |
615 SVGElement* replacingElement(cloneParent); | 615 SVGElement* replacingElement(cloneParent); |
616 | 616 |
617 // Replace <use> with referenced content. | 617 // Replace <use> with referenced content. |
618 use->parentNode()->replaceChild(cloneParent, use); | 618 use->parentNode()->replaceChild(cloneParent, use); |
619 | 619 |
620 use = Traversal<SVGUseElement>::next(*replacingElement, shadowRoot); | 620 use = Traversal<SVGUseElement>::next(*replacingElement, &shadowRoot); |
621 } | 621 } |
622 return true; | 622 return true; |
623 } | 623 } |
624 | 624 |
625 void SVGUseElement::invalidateShadowTree() { | 625 void SVGUseElement::invalidateShadowTree() { |
626 if (!inActiveDocument() || m_needsShadowTreeRecreation) | 626 if (!inActiveDocument() || m_needsShadowTreeRecreation) |
627 return; | 627 return; |
628 clearInstanceRoot(); | 628 clearInstanceRoot(); |
629 scheduleShadowTreeRecreation(); | 629 scheduleShadowTreeRecreation(); |
630 invalidateDependentShadowTrees(); | 630 invalidateDependentShadowTrees(); |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
711 return m_resource && m_resource->isLoading(); | 711 return m_resource && m_resource->isLoading(); |
712 } | 712 } |
713 | 713 |
714 bool SVGUseElement::resourceIsValid() const { | 714 bool SVGUseElement::resourceIsValid() const { |
715 return m_resource && m_resource->isLoaded() && !m_resource->errorOccurred() && | 715 return m_resource && m_resource->isLoaded() && !m_resource->errorOccurred() && |
716 m_resource->document(); | 716 m_resource->document(); |
717 } | 717 } |
718 | 718 |
719 bool SVGUseElement::instanceTreeIsLoading() const { | 719 bool SVGUseElement::instanceTreeIsLoading() const { |
720 for (const SVGUseElement& useElement : | 720 for (const SVGUseElement& useElement : |
721 Traversal<SVGUseElement>::descendantsOf(*userAgentShadowRoot())) { | 721 Traversal<SVGUseElement>::descendantsOf(useShadowRoot())) { |
722 if (useElement.resourceIsStillLoading()) | 722 if (useElement.resourceIsStillLoading()) |
723 return true; | 723 return true; |
724 } | 724 } |
725 return false; | 725 return false; |
726 } | 726 } |
727 | 727 |
728 void SVGUseElement::setDocumentResource(DocumentResource* resource) { | 728 void SVGUseElement::setDocumentResource(DocumentResource* resource) { |
729 if (m_resource == resource) | 729 if (m_resource == resource) |
730 return; | 730 return; |
731 | 731 |
732 if (m_resource) | 732 if (m_resource) |
733 m_resource->removeClient(this); | 733 m_resource->removeClient(this); |
734 | 734 |
735 m_resource = resource; | 735 m_resource = resource; |
736 if (m_resource) | 736 if (m_resource) |
737 m_resource->addClient(this); | 737 m_resource->addClient(this); |
738 } | 738 } |
739 | 739 |
740 } // namespace blink | 740 } // namespace blink |
OLD | NEW |