Chromium Code Reviews| 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(); |
|
hayato
2017/03/15 11:13:00
Since ShadowRoot is not an element, it would be be
| |
| 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 |