Changeset 179980 in webkit
- Timestamp:
- Feb 11, 2015 7:53:48 PM (9 years ago)
- Location:
- trunk
- Files:
-
- 2 added
- 10 deleted
- 18 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r179979 r179980 1 2015-02-11 Darin Adler <darin@apple.com> 2 3 SVGUseElement follow-up improvements 4 https://bugs.webkit.org/show_bug.cgi?id=141382 5 6 Reviewed by Antti Koivisto. 7 8 Modified some tests to be reference tests since the change in implementation slightly changed 9 the behavior, but not in a way that matters. Other similar updates. 10 11 * TestExpectations: Expect a progression in imported/mozilla/svg/dynamic-use-02.svg. 12 13 * platform/gtk/svg/custom/relative-sized-shadow-tree-content-with-symbol-expected.png: Removed. 14 * platform/gtk/svg/custom/relative-sized-shadow-tree-content-with-symbol-expected.txt: Removed. 15 * platform/gtk/svg/custom/use-property-synchronization-crash-expected.png: Removed. 16 * platform/ios-sim-deprecated/svg/custom/relative-sized-shadow-tree-content-with-symbol-expected.txt: Removed. 17 * platform/ios-simulator/svg/custom/relative-sized-shadow-tree-content-with-symbol-expected.txt: Removed. 18 * platform/mac-mountainlion/svg/custom/relative-sized-shadow-tree-content-with-symbol-expected.txt: Removed. 19 * platform/mac/svg/custom/relative-sized-shadow-tree-content-with-symbol-expected.png: Removed. 20 * platform/mac/svg/custom/relative-sized-shadow-tree-content-with-symbol-expected.txt: Removed. 21 * platform/mac/svg/custom/use-property-synchronization-crash-expected.png: Removed. 22 23 * svg/animations/use-animate-width-and-height-expected.txt: Updated to expect the new expression 24 name from the modified test. 25 * svg/animations/use-animate-width-and-height.html: THe state of the shadow root now depends on 26 layout, so force layout before inspecting it. 27 28 * svg/custom/relative-sized-shadow-tree-content-with-symbol-expected.xhtml: Added. 29 * svg/custom/relative-sized-shadow-tree-content-with-symbol.xhtml: Made this no longer be a 30 repaint test. Not sure why we are using those in so many cases. Also made it be a reference test. 31 32 * svg/custom/use-property-synchronization-crash-expected.svg: Added. 33 * svg/custom/use-property-synchronization-crash-expected.txt: Removed. 34 1 35 2015-02-11 Gyuyoung Kim <gyuyoung.kim@samsung.com> 2 36 -
trunk/LayoutTests/TestExpectations
r179955 r179980 400 400 webkit.org/b/139155 imported/mozilla/svg/dynamic-pattern-01.svg [ ImageOnlyFailure ] 401 401 webkit.org/b/139155 imported/mozilla/svg/dynamic-use-01.svg [ ImageOnlyFailure ] 402 webkit.org/b/139155 imported/mozilla/svg/dynamic-use-02.svg [ ImageOnlyFailure ]403 402 webkit.org/b/139155 imported/mozilla/svg/dynamic-use-03.svg [ ImageOnlyFailure ] 404 403 webkit.org/b/139155 imported/mozilla/svg/dynamic-use-07.svg [ ImageOnlyFailure ] -
trunk/LayoutTests/svg/animations/use-animate-width-and-height-expected.txt
r179069 r179980 10 10 PASS use.getAttribute('width') is '100' 11 11 PASS use.getAttribute('height') is '100' 12 PASS shadowRoot.firstChild.width.animVal.value is 10013 PASS shadowRoot.firstChild.height.animVal.value is 10012 PASS useElementTargetClone().width.animVal.value is 100 13 PASS useElementTargetClone().height.animVal.value is 100 14 14 PASS use.width.animVal.value is 105 15 15 PASS use.width.baseVal.value is 100 … … 18 18 FAIL use.getAttribute('width') should be 105. Was 100. 19 19 FAIL use.getAttribute('height') should be 105. Was 100. 20 PASS shadowRoot.firstChild.width.animVal.value is 10521 PASS shadowRoot.firstChild.height.animVal.value is 10520 PASS useElementTargetClone().width.animVal.value is 105 21 PASS useElementTargetClone().height.animVal.value is 105 22 22 PASS use.width.animVal.value is 115 23 23 PASS use.width.baseVal.value is 100 … … 26 26 FAIL use.getAttribute('width') should be 115. Was 100. 27 27 FAIL use.getAttribute('height') should be 115. Was 100. 28 PASS shadowRoot.firstChild.width.animVal.value is 11529 PASS shadowRoot.firstChild.height.animVal.value is 11528 PASS useElementTargetClone().width.animVal.value is 115 29 PASS useElementTargetClone().height.animVal.value is 115 30 30 PASS use.width.animVal.value is 125 31 31 PASS use.width.baseVal.value is 100 … … 34 34 FAIL use.getAttribute('width') should be 125. Was 100. 35 35 FAIL use.getAttribute('height') should be 125. Was 100. 36 PASS shadowRoot.firstChild.width.animVal.value is 12537 PASS shadowRoot.firstChild.height.animVal.value is 12536 PASS useElementTargetClone().width.animVal.value is 125 37 PASS useElementTargetClone().height.animVal.value is 125 38 38 PASS use.width.animVal.value is 135 39 39 PASS use.width.baseVal.value is 100 … … 42 42 FAIL use.getAttribute('width') should be 135. Was 100. 43 43 FAIL use.getAttribute('height') should be 135. Was 100. 44 PASS shadowRoot.firstChild.width.animVal.value is 13545 PASS shadowRoot.firstChild.height.animVal.value is 13544 PASS useElementTargetClone().width.animVal.value is 135 45 PASS useElementTargetClone().height.animVal.value is 135 46 46 PASS successfullyParsed is true 47 47 -
trunk/LayoutTests/svg/animations/use-animate-width-and-height.html
r179069 r179980 59 59 use.appendChild(animate2); 60 60 61 var shadowRoot = internals.shadowRoot(use); 61 function useElementTargetClone() 62 { 63 document.body.offsetWidth; 64 return internals.shadowRoot(use).firstChild; 65 } 62 66 63 67 function sample1() … … 70 74 shouldBe("use.getAttribute('width')", "'100'"); 71 75 shouldBe("use.getAttribute('height')", "'100'"); 72 shouldBe(" shadowRoot.firstChild.width.animVal.value", "100");73 shouldBe(" shadowRoot.firstChild.height.animVal.value", "100");76 shouldBe("useElementTargetClone().width.animVal.value", "100"); 77 shouldBe("useElementTargetClone().height.animVal.value", "100"); 74 78 } 75 79 … … 82 86 shouldBe("use.getAttribute('width')", "'105'"); 83 87 shouldBe("use.getAttribute('height')", "'105'"); 84 shouldBe(" shadowRoot.firstChild.width.animVal.value", "105");85 shouldBe(" shadowRoot.firstChild.height.animVal.value", "105");88 shouldBe("useElementTargetClone().width.animVal.value", "105"); 89 shouldBe("useElementTargetClone().height.animVal.value", "105"); 86 90 } 87 91 … … 94 98 shouldBe("use.getAttribute('width')", "'115'"); 95 99 shouldBe("use.getAttribute('height')", "'115'"); 96 shouldBe(" shadowRoot.firstChild.width.animVal.value", "115");97 shouldBe(" shadowRoot.firstChild.height.animVal.value", "115");100 shouldBe("useElementTargetClone().width.animVal.value", "115"); 101 shouldBe("useElementTargetClone().height.animVal.value", "115"); 98 102 } 99 103 … … 105 109 shouldBe("use.getAttribute('width')", "'125'"); 106 110 shouldBe("use.getAttribute('height')", "'125'"); 107 shouldBe(" shadowRoot.firstChild.width.animVal.value", "125");108 shouldBe(" shadowRoot.firstChild.height.animVal.value", "125");111 shouldBe("useElementTargetClone().width.animVal.value", "125"); 112 shouldBe("useElementTargetClone().height.animVal.value", "125"); 109 113 } 110 114 … … 117 121 shouldBe("use.getAttribute('width')", "'135'"); 118 122 shouldBe("use.getAttribute('height')", "'135'"); 119 shouldBe(" shadowRoot.firstChild.width.animVal.value", "135");120 shouldBe(" shadowRoot.firstChild.height.animVal.value", "135");123 shouldBe("useElementTargetClone().width.animVal.value", "135"); 124 shouldBe("useElementTargetClone().height.animVal.value", "135"); 121 125 } 122 126 -
trunk/LayoutTests/svg/custom/relative-sized-shadow-tree-content-with-symbol.xhtml
r168350 r179980 1 1 <html xmlns="http://www.w3.org/1999/xhtml"> 2 2 <head> 3 <script src="../../fast/repaint/resources/repaint.js"></script>4 3 </head> 5 <body onload="runRepaintTest()">4 <body> 6 5 <p>The svg area contained in the div element (red box), should fill out the whole area (two green rectangles, first: (0,0)-(50%,50%), second: (50%,50%)-(100%,100%)), especially after resizing the content box to a different size</p> 7 6 <div id="contentBox" style="width: 100px; height: 400px; border: 1px solid red;"> … … 17 16 </div> 18 17 <script> 19 function repaintTest() { 20 document.getElementById("contentBox").style.setProperty("width", "400px"); 21 } 18 document.getElementById("contentBox").style.setProperty("width", "400px"); 22 19 </script> 23 20 </body> -
trunk/Source/WebCore/ChangeLog
r179978 r179980 1 2015-02-11 Darin Adler <darin@apple.com> 2 3 SVGUseElement follow-up improvements 4 https://bugs.webkit.org/show_bug.cgi?id=141382 5 6 Reviewed by Antti Koivisto. 7 8 * loader/cache/CachedSVGDocumentClient.h: Removed unneeded forward declaration. 9 10 * page/EventHandler.cpp: Removed unneeded include of SVGUseElement.h. 11 * rendering/svg/RenderSVGViewportContainer.cpp: Ditto. 12 13 * svg/SVGDocumentExtensions.cpp: 14 (WebCore::SVGDocumentExtensions::clearTargetDependencies): Removed too-specific 15 check that assumed that SVG elements in shadow trees are always for <use> elements. 16 This amounted to an unneeded optimization that could be removed with no bad effect. 17 18 * svg/SVGElement.cpp: 19 (WebCore::SVGElement::correspondingElement): Removed the assertions so this could 20 be used more freely outside of cases where the shadow tree state is fully consistent. 21 It's fine to have this just be a mechanical getter; there's nothing super-tricky 22 here that needs to be caught by the assertion. 23 (WebCore::SVGElement::title): Removed unneeded special handling for titles inside 24 the shadow tree. 25 26 * svg/SVGGElement.cpp: 27 (WebCore::SVGGElement::create): Added an overload that doesn't require explicitly 28 passing in the tag name. 29 * svg/SVGGElement.h: Ditto. 30 * svg/SVGSVGElement.cpp: 31 (WebCore::SVGSVGElement::create): Ditto. 32 * svg/SVGSVGElement.h: Ditto. 33 34 * svg/SVGUseElement.cpp: Removed a lot of unneeded includes. 35 (WebCore::SVGUseElement::SVGUseElement): Removed code to initialize some booleans. 36 We do that in the class definition now. 37 (WebCore::SVGUseElement::create): Removed the code that calls the 38 ensureUserAgentShadowRoot function unconditionally. That's properly done when 39 needed; no need to do it here. 40 (WebCore::SVGUseElement::~SVGUseElement): Removed unneeded code to destroy the 41 shadow tree (that happens automatically) and simplified the code to stop loading 42 the external document. 43 (WebCore::SVGUseElement::isSupportedAttribute): Deleted. 44 (WebCore::SVGUseElement::parseAttribute): Simplified this. Removed assumptions 45 about the intersection of various sets of attributes, and also removed the 46 isSupportedAttribute function. This seems to serve no purpose here, or in any 47 other SVG element class. I plan to remove it everywhere over time. 48 (WebCore::isWellFormedDocument): Deleted. 49 (WebCore::SVGUseElement::insertedInto): Simplified code by removing all the 50 special cases during initial parsing, and did the invalidation here rather than 51 deferring it to didNotifySubtreeInsertions. Added a call to the new function, 52 updateExternalDocument, since that won't do anything when the element is not 53 in a document. 54 (WebCore::SVGUseElement::didNotifySubtreeInsertions): Deleted. 55 (WebCore::SVGUseElement::removedFrom): Added code to call clearShadowTree and 56 updateExternalDocument. Both are efficient when doing nothing, and both are 57 appropriate since the element is no longer in a document. 58 (WebCore::SVGUseElement::referencedDocument): Deleted. No longer needed. 59 (WebCore::SVGUseElement::externalDocument): Streamlined the logic here, removing 60 multiple unneeded checks. 61 (WebCore::SVGUseElement::transferSizeAttributesToTargetClone): Renamed since 62 "target clone" is clear enough within this class, without explicitly stating 63 "shadow tree". All the clones are in the shadow tree. 64 (WebCore::SVGUseElement::svgAttributeChanged): Removed unneeded code calling 65 isSupportedAttribute. Changed the code that detects changes in href to just 66 call updateExternalDocument (for the document URL) and invalidateShadowTree 67 (for the fragment). Also updated the transferSizeAttributesToTargetClone logic 68 to only trigger on width and height and updated names. 69 (WebCore::SVGUseElement::willAttachRenderers): Updated for the new name of 70 m_shouldRebuildShadowTree and added a call through to the base class. 71 (WebCore::createAllowedElementSet): Added. A more efficient way to implement 72 the initialization of the set for isDisallowedElement. 73 (WebCore::isDisallowedElement): Simplified this by using the function above, 74 and also overloaded for both SVGElement and Element for a tiny efficiency boost. 75 (WebCore::SVGUseElement::clearShadowTree): Renamed form clearResourceReferences. 76 This is a much more straightforward name. Also deleted the code that sets the 77 m_needsShadowTreeRecreation flag to false. That should be done by the build 78 function, not here. 79 (WebCore::SVGUseElement::buildPendingResource): Made this just invalidate the 80 shadow tree now instead of explicitly building it. 81 (WebCore::SVGUseElement::updateShadowTree): Moved the code to create a shadow 82 tree here from buildPendingResource. ALso changed the logic so that we 83 always blow away the old shadow tree. Moved the comment about rebuilding things 84 every time here. Updated the code to use the findTarget and cloneTarget functions, 85 eliminating the buildShadowTree function entirely. Moved the call to 86 transferSizeAttributesToShadowTreeTargetClone inside cloneTarget. Also updated 87 for the name change for m_shouldRebuildShadowTree. 88 (WebCore::SVGUseElement::targetClone): Renamed from shadowTreeTargetClone. 89 No need to emphasize "shadow tree" since that's where all clones are. 90 (WebCore::isDirectReference): Streamlined a bit using "using namespace". 91 (WebCore::SVGUseElement::toClipPath): Rewrote to use early return and updated 92 for name changes. Also used ASCIILiteral. 93 (WebCore::SVGUseElement::rendererClipChild): Changed local variable names. 94 (WebCore::removeDisallowedElementsFromSubtree): Wrote the iteration in a 95 slightly more idiomatic style. 96 (WebCore::SVGUseElement::findTarget): Added. This new function implements 97 the rule for finding a valid target for a use element. This replaces logic 98 that was duplicated in two different places and it also includes all the 99 rules that were formerly in the isValidTarget function. Also, this implements 100 a correct check for a cycle that handles cases the code in isValidTarget did not. 101 (WebCore::SVGUseElement::isValidTarget): Deleted. 102 (WebCore::SVGUseElement::cloneTarget): Added. Helper function used both when 103 cloning the target of the top level <use> elements and for other <use> elements 104 inside the shadow tree. 105 (WebCore::cloneDataAndChildren): Added. Helper function that allows both the 106 <use> and <symbol> element expanding functions to be shorter and share more code. 107 (WebCore::SVGUseElement::expandUseElementsInShadowTree): Removed unneeded checks 108 of cachedDocumentIsStillLoading. Used the new findTarget function, which handles 109 finding the target cross-document correctly. Removed the incorrect use of 110 referencedDocument when creating new elements and finding targets. Refactored 111 to use the new cloneDataAndChildren function and also moved the code that removes 112 the special attributes here, replacing the transferAttributesToShadowTreeReplacement 113 function. Made a few other simplifications. 114 (WebCore::SVGUseElement::expandSymbolElementsInShadowTree): Ditto, just like the 115 <use> changes only simpler. 116 (WebCore::SVGUseElement::transferEventListenersToShadowTree): Made this const. 117 Removed unneeded assertions. 118 (WebCore::SVGUseElement::invalidateShadowTree): Updated for name change. 119 (WebCore::SVGUseElement::invalidateDependentShadowTrees): Removed assertion. 120 (WebCore::SVGUseElement::transferAttributesToShadowTreeReplacement): Deleted. 121 (WebCore::SVGUseElement::selfHasRelativeLengths): Tweaked names. 122 (WebCore::SVGUseElement::notifyFinished): Removed the inDocument check, since 123 this function will only be called for elements that are in a document. 124 (WebCore::SVGUseElement::cachedDocumentIsStillLoading): Deleted. 125 (WebCore::SVGUseElement::finishParsingChildren): Removed the code that calls 126 buildPendingResource here. Shadow tree updating is driven solely by renderer 127 generation now. 128 (WebCore::SVGUseElement::updateExternalDocument): Replaced setCachedDocument 129 with this. This function knows how to load a different document if the URL 130 has changed, or leave it alone if not, and also stop the load if it should. 131 (WebCore::SVGUseElement::isValid): Moved this here from the header, since it's 132 always being called virtually. 133 (WebCore::SVGUseElement::haveLoadedRequiredResources): Ditto. 134 (WebCore::SVGUseElement::setHaveFiredLoadEvent): Ditto. 135 (WebCore::SVGUseElement::haveFiredLoadEvent): Ditto. 136 (WebCore::SVGUseElement::svgLoadEventTimer): Ditto. 137 138 * svg/SVGUseElement.h: Removed unneeded include. Moved the animated properties 139 to the top of the class because they are public DOM API and so are logical to 140 list first. I'd like to do that for other classes too over time. Changed to 141 derive privately from CachedSVGDocumentClient. Made the function 142 invalidateDependentShadowTrees private. Removed didNotifySubtreeInsertions, 143 isSupportedAttribute, clearResourceReferences, buildShadowTree, 144 transferAttributesToShadowTreeReplacement, isParserInserted, and 145 m_wasInsertedByParser. Added updateExternalDocument, cloneTarget, targetClone, 146 updateShadowTree, and clearShadowTree. Also did a couple other renames, 147 including renaming m_cachedDocument to m_externalDocument. 148 149 * svg/svgtags.in: Removed constructorNeedsCreatedByParser from the <use> 150 element since we don't have to handle constructing by the parser specially. 151 1 152 2015-02-11 Dhi Aurrahman <diorahman@rockybars.com> 2 153 -
trunk/Source/WebCore/loader/cache/CachedSVGDocumentClient.h
r163440 r179980 28 28 namespace WebCore { 29 29 30 class CachedSVGDocument;31 32 30 class CachedSVGDocumentClient : public CachedResourceClient { 33 31 public: -
trunk/Source/WebCore/page/EventHandler.cpp
r179810 r179980 82 82 #include "SVGDocument.h" 83 83 #include "SVGNames.h" 84 #include "SVGUseElement.h"85 84 #include "ScrollAnimator.h" 86 85 #include "ScrollLatchingState.h" -
trunk/Source/WebCore/rendering/svg/RenderSVGViewportContainer.cpp
r179810 r179980 28 28 #include "SVGNames.h" 29 29 #include "SVGSVGElement.h" 30 #include "SVGUseElement.h"31 30 32 31 namespace WebCore { -
trunk/Source/WebCore/svg/SVGDocumentExtensions.cpp
r179599 r179980 342 342 void SVGDocumentExtensions::clearTargetDependencies(SVGElement& referencedElement) 343 343 { 344 if (referencedElement.isInShadowTree()) {345 // The host element (e.g. <use>) of the shadow root will rebuild the shadow tree346 // and all its references.347 ASSERT(referencedElement.shadowRoot());348 ASSERT(m_rebuildElements.contains(referencedElement.shadowRoot()->hostElement()));349 return;350 }351 344 auto it = m_elementDependencies.find(&referencedElement); 352 345 if (it == m_elementDependencies.end()) -
trunk/Source/WebCore/svg/SVGElement.cpp
r179829 r179980 483 483 SVGElement* SVGElement::correspondingElement() const 484 484 { 485 ASSERT(!m_svgRareData || !m_svgRareData->correspondingElement() || correspondingUseElement());486 485 return m_svgRareData ? m_svgRareData->correspondingElement() : nullptr; 487 486 } … … 967 966 if (isOutermostSVGSVGElement() && document().topDocument().isSVGDocument()) 968 967 return String(); 969 970 // Walk up the tree, to find out whether we're inside a <use> shadow tree, to find the right title.971 if (isInShadowTree()) {972 Element* shadowHostElement = downcast<ShadowRoot>(treeScope().rootNode()).hostElement();973 // At this time, SVG nodes are not allowed in non-<use> shadow trees, so any shadow root we do974 // have should be a use. The assert and following test is here to catch future shadow DOM changes975 // that do enable SVG in a shadow tree.976 ASSERT(!shadowHostElement || shadowHostElement->hasTagName(SVGNames::useTag));977 if (shadowHostElement && shadowHostElement->hasTagName(SVGNames::useTag)) {978 SVGUseElement& useElement = downcast<SVGUseElement>(*shadowHostElement);979 980 // If the <use> title is not empty we found the title to use.981 String useTitle(useElement.title());982 if (!useTitle.isEmpty())983 return useTitle;984 }985 }986 987 // If we aren't an instance in a <use> or the <use> title was not found, then find the first988 // <title> child of this element.989 968 auto firstTitle = childrenOfType<SVGTitleElement>(*this).first(); 990 969 return firstTitle ? const_cast<SVGTitleElement*>(firstTitle)->innerText() : String(); -
trunk/Source/WebCore/svg/SVGGElement.cpp
r179810 r179980 48 48 { 49 49 return adoptRef(*new SVGGElement(tagName, document)); 50 } 51 52 Ref<SVGGElement> SVGGElement::create(Document& document) 53 { 54 return create(SVGNames::gTag, document); 50 55 } 51 56 -
trunk/Source/WebCore/svg/SVGGElement.h
r178048 r179980 32 32 public: 33 33 static Ref<SVGGElement> create(const QualifiedName&, Document&); 34 static Ref<SVGGElement> create(Document&); 34 35 35 36 private: -
trunk/Source/WebCore/svg/SVGSVGElement.cpp
r179810 r179980 100 100 } 101 101 102 Ref<SVGSVGElement> SVGSVGElement::create(Document& document) 103 { 104 return create(SVGNames::svgTag, document); 105 } 106 102 107 SVGSVGElement::~SVGSVGElement() 103 108 { -
trunk/Source/WebCore/svg/SVGSVGElement.h
r178048 r179980 46 46 public: 47 47 static Ref<SVGSVGElement> create(const QualifiedName&, Document&); 48 static Ref<SVGSVGElement> create(Document&); 48 49 49 50 using SVGGraphicsElement::ref; -
trunk/Source/WebCore/svg/SVGUseElement.cpp
r179810 r179980 28 28 29 29 #include "CachedResourceLoader.h" 30 #include "CachedResourceRequest.h"31 30 #include "CachedSVGDocument.h" 32 #include "Document.h"33 31 #include "ElementIterator.h" 34 32 #include "Event.h" 35 #include "EventListener.h"36 #include "HTMLNames.h"37 #include "NodeRenderStyle.h"38 #include "RegisteredEventListener.h"39 33 #include "RenderSVGResource.h" 40 34 #include "RenderSVGTransformableContainer.h" 41 35 #include "ShadowRoot.h" 42 #include "SVGElementRareData.h"43 36 #include "SVGGElement.h" 44 #include "SVGLengthContext.h"45 #include "SVGNames.h"46 #include "SVGSMILElement.h"47 37 #include "SVGSVGElement.h" 48 38 #include "SVGSymbolElement.h" 49 #include "StyleResolver.h"50 39 #include "XLinkNames.h" 51 #include "XMLDocumentParser.h"52 #include "XMLSerializer.h"53 #include <wtf/NeverDestroyed.h>54 40 55 41 namespace WebCore { 56 42 57 // Animated property definitions58 43 DEFINE_ANIMATED_LENGTH(SVGUseElement, SVGNames::xAttr, X, x) 59 44 DEFINE_ANIMATED_LENGTH(SVGUseElement, SVGNames::yAttr, Y, y) … … 73 58 END_REGISTER_ANIMATED_PROPERTIES 74 59 75 inline SVGUseElement::SVGUseElement(const QualifiedName& tagName, Document& document , bool wasInsertedByParser)60 inline SVGUseElement::SVGUseElement(const QualifiedName& tagName, Document& document) 76 61 : SVGGraphicsElement(tagName, document) 77 62 , m_x(LengthModeWidth) … … 79 64 , m_width(LengthModeWidth) 80 65 , m_height(LengthModeHeight) 81 , m_wasInsertedByParser(wasInsertedByParser)82 , m_haveFiredLoadEvent(false)83 , m_needsShadowTreeRecreation(false)84 66 , m_svgLoadEventTimer(*this, &SVGElement::svgLoadEventTimerFired) 85 67 { … … 89 71 } 90 72 91 Ref<SVGUseElement> SVGUseElement::create(const QualifiedName& tagName, Document& document, bool wasInsertedByParser) 92 { 93 // Always build a #shadow-root for SVGUseElement. 94 Ref<SVGUseElement> use = adoptRef(*new SVGUseElement(tagName, document, wasInsertedByParser)); 95 use->ensureUserAgentShadowRoot(); 96 return use; 73 Ref<SVGUseElement> SVGUseElement::create(const QualifiedName& tagName, Document& document) 74 { 75 return adoptRef(*new SVGUseElement(tagName, document)); 97 76 } 98 77 99 78 SVGUseElement::~SVGUseElement() 100 79 { 101 setCachedDocument(0); 102 103 clearResourceReferences(); 104 } 105 106 bool SVGUseElement::isSupportedAttribute(const QualifiedName& attrName) 107 { 108 static NeverDestroyed<HashSet<QualifiedName>> supportedAttributes; 109 if (supportedAttributes.get().isEmpty()) { 110 SVGLangSpace::addSupportedAttributes(supportedAttributes); 111 SVGExternalResourcesRequired::addSupportedAttributes(supportedAttributes); 112 SVGURIReference::addSupportedAttributes(supportedAttributes); 113 supportedAttributes.get().add(SVGNames::xAttr); 114 supportedAttributes.get().add(SVGNames::yAttr); 115 supportedAttributes.get().add(SVGNames::widthAttr); 116 supportedAttributes.get().add(SVGNames::heightAttr); 117 } 118 return supportedAttributes.get().contains<SVGAttributeHashTranslator>(attrName); 80 if (m_externalDocument) 81 m_externalDocument->removeClient(this); 119 82 } 120 83 … … 123 86 SVGParsingError parseError = NoError; 124 87 125 if (!isSupportedAttribute(name)) 126 SVGGraphicsElement::parseAttribute(name, value); 127 else if (name == SVGNames::xAttr) 88 if (name == SVGNames::xAttr) 128 89 setXBaseValue(SVGLength::construct(LengthModeWidth, value, parseError)); 129 90 else if (name == SVGNames::yAttr) … … 133 94 else if (name == SVGNames::heightAttr) 134 95 setHeightBaseValue(SVGLength::construct(LengthModeHeight, value, parseError, ForbidNegativeLengths)); 135 else if (SVGLangSpace::parseAttribute(name, value)136 || SVGExternalResourcesRequired::parseAttribute(name, value)137 || SVGURIReference::parseAttribute(name, value)) {138 } else139 ASSERT_NOT_REACHED();140 96 141 97 reportAttributeParsingError(parseError, name, value); 142 } 143 144 #if !ASSERT_DISABLED 145 static inline bool isWellFormedDocument(Document& document) 146 { 147 if (document.isSVGDocument() || document.isXHTMLDocument()) 148 return static_cast<XMLDocumentParser*>(document.parser())->wellFormed(); 149 return true; 150 } 151 #endif 98 99 SVGExternalResourcesRequired::parseAttribute(name, value); 100 SVGGraphicsElement::parseAttribute(name, value); 101 SVGLangSpace::parseAttribute(name, value); 102 SVGURIReference::parseAttribute(name, value); 103 } 152 104 153 105 Node::InsertionNotificationRequest SVGUseElement::insertedInto(ContainerNode& rootParent) 154 106 { 155 107 SVGGraphicsElement::insertedInto(rootParent); 156 if (!rootParent.inDocument()) 157 return InsertionDone; 158 ASSERT(!hasPendingResources() || !isWellFormedDocument(document())); 159 SVGExternalResourcesRequired::insertedIntoDocument(this); 160 if (!m_wasInsertedByParser) 161 return InsertionShouldCallDidNotifySubtreeInsertions; 108 if (inDocument()) { 109 SVGExternalResourcesRequired::insertedIntoDocument(this); 110 invalidateShadowTree(); 111 updateExternalDocument(); 112 } 162 113 return InsertionDone; 163 114 } 164 115 165 void SVGUseElement::didNotifySubtreeInsertions(ContainerNode*)166 {167 buildPendingResource();168 }169 170 116 void SVGUseElement::removedFrom(ContainerNode& rootParent) 171 117 { 172 118 SVGGraphicsElement::removedFrom(rootParent); 173 if (rootParent.inDocument()) 174 clearResourceReferences(); 175 } 176 177 Document* SVGUseElement::referencedDocument() const 178 { 179 if (!isExternalURIReference(href(), document())) 180 return &document(); 181 return externalDocument(); 182 } 183 184 Document* SVGUseElement::externalDocument() const 185 { 186 if (m_cachedDocument && m_cachedDocument->isLoaded()) { 187 // Gracefully handle error condition. 188 if (m_cachedDocument->errorOccurred()) 189 return 0; 190 ASSERT(m_cachedDocument->document()); 191 return m_cachedDocument->document(); 192 } 193 return 0; 194 } 195 196 void SVGUseElement::transferSizeAttributesToShadowTreeTargetClone(SVGElement& shadowElement) const 119 clearShadowTree(); 120 updateExternalDocument(); 121 } 122 123 inline Document* SVGUseElement::externalDocument() const 124 { 125 return m_externalDocument ? m_externalDocument->document() : nullptr; 126 } 127 128 void SVGUseElement::transferSizeAttributesToTargetClone(SVGElement& shadowElement) const 197 129 { 198 130 // FIXME: The check for valueInSpecifiedUnits being non-zero below is a workaround for the fact … … 216 148 void SVGUseElement::svgAttributeChanged(const QualifiedName& attrName) 217 149 { 218 if (!isSupportedAttribute(attrName)) {219 SVGGraphicsElement::svgAttributeChanged(attrName);220 return;221 }222 223 150 InstanceInvalidationGuard guard(*this); 224 151 225 152 if (attrName == SVGNames::xAttr || attrName == SVGNames::yAttr || attrName == SVGNames::widthAttr || attrName == SVGNames::heightAttr) { 226 153 updateRelativeLengthsInformation(); 227 if (SVGElement* shadowTreeTargetClone = this->shadowTreeTargetClone()) { 228 // FIXME: It's unnecessarily inefficient to do this work any time we change "x" or "y". 154 if (attrName == SVGNames::widthAttr || attrName == SVGNames::heightAttr) { 229 155 // FIXME: It's unnecessarily inefficient to update both width and height each time either is changed. 230 transferSizeAttributesToShadowTreeTargetClone(*shadowTreeTargetClone); 156 if (auto* targetClone = this->targetClone()) 157 transferSizeAttributesToTargetClone(*targetClone); 231 158 } 232 159 if (auto* renderer = this->renderer()) … … 239 166 240 167 if (SVGURIReference::isKnownAttribute(attrName)) { 241 bool isExternalReference = isExternalURIReference(href(), document()); 242 if (isExternalReference) { 243 URL url = document().completeURL(href()); 244 if (url.hasFragmentIdentifier()) { 245 CachedResourceRequest request(ResourceRequest(url.string())); 246 request.setInitiator(this); 247 setCachedDocument(document().cachedResourceLoader().requestSVGDocument(request)); 248 } 249 } else 250 setCachedDocument(0); 251 252 if (!m_wasInsertedByParser) 253 buildPendingResource(); 254 255 return; 256 } 257 258 if (SVGLangSpace::isKnownAttribute(attrName) 259 || SVGExternalResourcesRequired::isKnownAttribute(attrName)) { 168 updateExternalDocument(); 260 169 invalidateShadowTree(); 261 170 return; 262 171 } 263 172 264 ASSERT_NOT_REACHED(); 173 if (SVGLangSpace::isKnownAttribute(attrName) || SVGExternalResourcesRequired::isKnownAttribute(attrName)) { 174 invalidateShadowTree(); 175 return; 176 } 177 178 SVGGraphicsElement::svgAttributeChanged(attrName); 265 179 } 266 180 267 181 void SVGUseElement::willAttachRenderers() 268 182 { 269 if (m_needsShadowTreeRecreation) 270 buildPendingResource(); 271 } 272 273 static bool isDisallowedElement(const Element& element) 183 if (m_shadowTreeNeedsUpdate) 184 updateShadowTree(); 185 SVGGraphicsElement::willAttachRenderers(); 186 } 187 188 static HashSet<AtomicString> createAllowedElementSet() 274 189 { 275 190 // Spec: "Any 'svg', 'symbol', 'g', graphics element or other 'use' is potentially a template object that can be re-used … … 277 192 // "Graphics Element" is defined as 'circle', 'ellipse', 'image', 'line', 'path', 'polygon', 'polyline', 'rect', 'text' 278 193 // Excluded are anything that is used by reference or that only make sense to appear once in a document. 279 280 if (!element.isSVGElement())281 return true;282 283 static NeverDestroyed<HashSet<QualifiedName>> allowedElementTags;284 if (allowedElementTags.get().isEmpty()) { 285 allowedElementTags.get().add(SVGNames::aTag); 286 allowedElementTags.get().add(SVGNames::circleTag); 287 allowedElementTags.get().add(SVGNames::descTag); 288 allowedElementTags.get().add(SVGNames::ellipseTag);289 allowedElementTags.get().add(SVGNames::gTag);290 allowedElementTags.get().add(SVGNames::imageTag); 291 allowedElementTags.get().add(SVGNames::lineTag); 292 allowedElementTags.get().add(SVGNames::metadataTag); 293 allowedElementTags.get().add(SVGNames::pathTag); 294 allowedElementTags.get().add(SVGNames::polygonTag);295 allowedElementTags.get().add(SVGNames::polylineTag); 296 allowedElementTags.get().add(SVGNames::rectTag); 297 allowedElementTags.get().add(SVGNames::svgTag); 298 allowedElementTags.get().add(SVGNames::switchTag); 299 allowedElementTags.get().add(SVGNames::symbolTag);300 allowedElementTags.get().add(SVGNames::textTag);301 allowedElementTags.get().add(SVGNames::textPathTag); 302 allowedElementTags.get().add(SVGNames::titleTag); 303 allowedElementTags.get().add(SVGNames::trefTag); 304 allowedElementTags.get().add(SVGNames::tspanTag); 305 allowedElementTags.get().add(SVGNames::useTag);306 307 return !allowedElementTags.get().contains<SVGAttributeHashTranslator>(element.tagQName()); 308 } 309 310 void SVGUseElement::clearResourceReferences() 311 { 194 using namespace SVGNames; 195 HashSet<AtomicString> set; 196 for (auto& tag : { aTag, circleTag, descTag, ellipseTag, gTag, imageTag, lineTag, metadataTag, pathTag, polygonTag, polylineTag, rectTag, svgTag, switchTag, symbolTag, textTag, textPathTag, titleTag, trefTag, tspanTag, useTag }) 197 set.add(tag.localName()); 198 return set; 199 } 200 201 static inline bool isDisallowedElement(const SVGElement& element) 202 { 203 static NeverDestroyed<HashSet<AtomicString>> set = createAllowedElementSet(); 204 return !set.get().contains(element.localName()); 205 } 206 207 static inline bool isDisallowedElement(const Element& element) 208 { 209 return !element.isSVGElement() || isDisallowedElement(downcast<SVGElement>(element)); 210 } 211 212 void SVGUseElement::clearShadowTree() 213 { 214 if (auto* root = userAgentShadowRoot()) 215 root->removeChildren(); 216 } 217 218 void SVGUseElement::buildPendingResource() 219 { 220 invalidateShadowTree(); 221 } 222 223 void SVGUseElement::updateShadowTree() 224 { 225 m_shadowTreeNeedsUpdate = false; 226 312 227 // FIXME: It's expensive to re-clone the entire tree every time. We should find a more efficient way to handle this. 313 if (ShadowRoot* root = userAgentShadowRoot()) 314 root->removeChildren(); 315 m_needsShadowTreeRecreation = false; 316 } 317 318 void SVGUseElement::buildPendingResource() 319 { 320 if (isInShadowTree()) 321 return; 322 if (!referencedDocument()) 323 return; 324 clearResourceReferences(); 325 if (!inDocument()) 326 return; 327 328 String id; 329 Element* target = SVGURIReference::targetElementFromIRIString(href(), document(), &id, externalDocument()); 330 if (!isValidTarget(target)) { 331 if (externalDocument()) { 332 // We can't find the target in an external document, so just give up and don't try to do it again. 333 // We should not attempt to observe if an element with ID shows up in the external document later. 334 return; 335 } 336 referencedDocument()->accessSVGExtensions().addPendingResource(id, this); 337 return; 338 } 339 340 buildShadowTree(downcast<SVGElement>(*target)); 228 clearShadowTree(); 229 230 if (isInShadowTree() || !inDocument()) 231 return; 232 233 String targetID; 234 auto* target = findTarget(&targetID); 235 if (!target) { 236 document().accessSVGExtensions().addPendingResource(targetID, this); 237 return; 238 } 239 240 cloneTarget(ensureUserAgentShadowRoot(), *target); 341 241 expandUseElementsInShadowTree(); 342 242 expandSymbolElementsInShadowTree(); 343 transferSizeAttributesToShadowTreeTargetClone(*shadowTreeTargetClone());344 243 transferEventListenersToShadowTree(); 244 345 245 updateRelativeLengthsInformation(); 346 246 347 247 // When we invalidate the other shadow trees, it's important that we don't 348 248 // follow any cycles and invalidate ourselves. To avoid that, we temporarily 349 // set m_ needsShadowTreeRecreationto true so invalidateShadowTree will249 // set m_shadowTreeNeedsUpdate to true so invalidateShadowTree will 350 250 // quickly return and do nothing. 351 ASSERT(!m_ needsShadowTreeRecreation);352 m_ needsShadowTreeRecreation= true;251 ASSERT(!m_shadowTreeNeedsUpdate); 252 m_shadowTreeNeedsUpdate = true; 353 253 invalidateDependentShadowTrees(); 354 m_ needsShadowTreeRecreation= false;355 } 356 357 SVGElement* SVGUseElement:: shadowTreeTargetClone() const254 m_shadowTreeNeedsUpdate = false; 255 } 256 257 SVGElement* SVGUseElement::targetClone() const 358 258 { 359 259 auto* root = userAgentShadowRoot(); … … 370 270 static bool isDirectReference(const SVGElement& element) 371 271 { 372 return element.hasTagName(SVGNames::pathTag) 373 || element.hasTagName(SVGNames::rectTag) 374 || element.hasTagName(SVGNames::circleTag) 375 || element.hasTagName(SVGNames::ellipseTag) 376 || element.hasTagName(SVGNames::polygonTag) 377 || element.hasTagName(SVGNames::polylineTag) 378 || element.hasTagName(SVGNames::textTag); 272 using namespace SVGNames; 273 return element.hasTagName(circleTag) 274 || element.hasTagName(ellipseTag) 275 || element.hasTagName(pathTag) 276 || element.hasTagName(polygonTag) 277 || element.hasTagName(polylineTag) 278 || element.hasTagName(rectTag) 279 || element.hasTagName(textTag); 379 280 } 380 281 … … 383 284 ASSERT(path.isEmpty()); 384 285 385 SVGElement* element = shadowTreeTargetClone(); 386 if (is<SVGGraphicsElement>(element)) { 387 if (!isDirectReference(*element)) { 388 // Spec: Indirect references are an error (14.3.5) 389 document().accessSVGExtensions().reportError("Not allowed to use indirect reference in <clip-path>"); 390 } else { 391 downcast<SVGGraphicsElement>(*element).toClipPath(path); 392 // FIXME: Avoid manual resolution of x/y here. Its potentially harmful. 393 SVGLengthContext lengthContext(this); 394 path.translate(FloatSize(x().value(lengthContext), y().value(lengthContext))); 395 path.transform(animatedLocalTransform()); 396 } 397 } 286 auto* targetClone = this->targetClone(); 287 if (!is<SVGGraphicsElement>(targetClone)) 288 return; 289 290 if (!isDirectReference(*targetClone)) { 291 // Spec: Indirect references are an error (14.3.5) 292 document().accessSVGExtensions().reportError(ASCIILiteral("Not allowed to use indirect reference in <clip-path>")); 293 return; 294 } 295 296 downcast<SVGGraphicsElement>(*targetClone).toClipPath(path); 297 SVGLengthContext lengthContext(this); 298 // FIXME: Find a way to do this without manual resolution of x/y here. It's potentially incorrect. 299 path.translate(FloatSize(x().value(lengthContext), y().value(lengthContext))); 300 path.transform(animatedLocalTransform()); 398 301 } 399 302 400 303 RenderElement* SVGUseElement::rendererClipChild() const 401 304 { 402 auto* element = shadowTreeTargetClone();403 if (! element)305 auto* targetClone = this->targetClone(); 306 if (!targetClone) 404 307 return nullptr; 405 if (!isDirectReference(* element))308 if (!isDirectReference(*targetClone)) 406 309 return nullptr; 407 return element->renderer();310 return targetClone->renderer(); 408 311 } 409 312 … … 420 323 Vector<Element*> disallowedElements; 421 324 auto descendants = descendantsOfType<Element>(subtree); 422 auto end = descendants.end(); 423 for (auto it = descendants.begin(); it != end; ) { 325 for (auto it = descendants.begin(), end = descendants.end(); it != end; ) { 424 326 if (isDisallowedElement(*it)) { 425 327 disallowedElements.append(&*it); … … 429 331 ++it; 430 332 } 431 for ( Element* element : disallowedElements)333 for (auto* element : disallowedElements) 432 334 element->parentNode()->removeChild(element); 433 335 } … … 448 350 static void associateReplacementCloneWithOriginal(SVGElement& replacementClone, SVGElement& originalClone) 449 351 { 450 SVGElement* correspondingElement = originalClone.correspondingElement();352 auto* correspondingElement = originalClone.correspondingElement(); 451 353 ASSERT(correspondingElement); 452 354 originalClone.setCorrespondingElement(nullptr); … … 467 369 } 468 370 469 void SVGUseElement::buildShadowTree(SVGElement& target) 470 { 471 Ref<SVGElement> clonedTarget = static_pointer_cast<SVGElement>(target.cloneElementWithChildren(document())).releaseNonNull(); 472 associateClonesWithOriginals(clonedTarget.get(), target); 473 removeDisallowedElementsFromSubtree(clonedTarget.get()); 474 ensureUserAgentShadowRoot().appendChild(WTF::move(clonedTarget)); 475 } 476 477 bool SVGUseElement::isValidTarget(Element* target) const 478 { 479 if (!is<SVGElement>(target)) 480 return false; 481 if (!target->inDocument()) 482 return false; 483 SVGElement& castedTarget = downcast<SVGElement>(*target); 484 if (&castedTarget == this) 485 return false; 486 if (isDisallowedElement(castedTarget)) 487 return false; 488 // Reject any target that would create a cycle. 489 for (auto& ancestor : lineageOfType<SVGElement>(*this)) { 490 if (ancestor.correspondingElement() == &castedTarget) 491 return false; 492 } 493 return true; 494 } 495 496 void SVGUseElement::expandUseElementsInShadowTree() 497 { 498 // FIXME: Combine this with buildShadowTree. 499 500 if (cachedDocumentIsStillLoading()) 501 return; 502 371 SVGElement* SVGUseElement::findTarget(String* targetID) const 372 { 373 auto* correspondingElement = this->correspondingElement(); 374 auto& original = correspondingElement ? downcast<SVGUseElement>(*correspondingElement) : *this; 375 376 auto* targetCandidate = targetElementFromIRIString(original.href(), original.document(), targetID, original.externalDocument()); 377 if (targetID && !targetID->isNull()) { 378 // If the reference is external, don't return the target ID to the caller. 379 // The caller would use the target ID to wait for a pending resource on the wrong document. 380 // If we ever want the change that and let the caller to wait on the external document, 381 // we should change this function so it returns the appropriate document to go with the ID. 382 if (isExternalURIReference(original.href(), original.document())) 383 *targetID = String(); 384 } 385 if (!is<SVGElement>(targetCandidate)) 386 return nullptr; 387 auto& target = downcast<SVGElement>(*targetCandidate); 388 389 if (!target.inDocument() || isDisallowedElement(target)) 390 return nullptr; 391 392 // Reject any target that has already been cloned to create one of the ancestors of this element, 393 // already in the shadow tree. This is sufficient to prevent cycles. 394 if (correspondingElement) { 395 for (auto& ancestor : lineageOfType<SVGElement>(*this)) { 396 if (ancestor.correspondingElement() == &target) 397 return nullptr; 398 } 399 } 400 401 return ⌖ 402 } 403 404 void SVGUseElement::cloneTarget(ContainerNode& container, SVGElement& target) const 405 { 406 Ref<SVGElement> targetClone = static_pointer_cast<SVGElement>(target.cloneElementWithChildren(document())).releaseNonNull(); 407 associateClonesWithOriginals(targetClone.get(), target); 408 removeDisallowedElementsFromSubtree(targetClone.get()); 409 transferSizeAttributesToTargetClone(targetClone.get()); 410 container.appendChild(WTF::move(targetClone)); 411 } 412 413 static void cloneDataAndChildren(SVGElement& replacementClone, SVGElement& originalClone) 414 { 415 // This assertion checks that we don't call this with the arguments backwards. 416 // The replacement clone is new and so it's not installed in a parent yet. 417 ASSERT(!replacementClone.parentNode()); 418 419 replacementClone.cloneDataFromElement(originalClone); 420 originalClone.cloneChildNodes(&replacementClone); 421 associateReplacementClonesWithOriginals(replacementClone, originalClone); 422 removeDisallowedElementsFromSubtree(replacementClone); 423 } 424 425 void SVGUseElement::expandUseElementsInShadowTree() const 426 { 503 427 auto descendants = descendantsOfType<SVGUseElement>(*userAgentShadowRoot()); 504 auto end = descendants.end(); 505 for (auto it = descendants.begin(); it != end; ) { 506 Ref<SVGUseElement> original = *it; 428 for (auto it = descendants.begin(), end = descendants.end(); it != end; ) { 429 SVGUseElement& originalClone = *it; 507 430 it = end; // Efficiently quiets assertions due to the outstanding iterator. 508 431 509 if (original->cachedDocumentIsStillLoading()) 510 return; 432 auto* target = originalClone.findTarget(); 511 433 512 434 // Spec: In the generated content, the 'use' will be replaced by 'g', where all attributes from the 513 435 // 'use' element except for x, y, width, height and xlink:href are transferred to the generated 'g' element. 514 436 515 // FIXME: Is it right to use referencedDocument() here instead of just document()? 516 // Can a shadow tree within this document really contain elements that are in a 517 // different document? 518 ASSERT(referencedDocument()); 519 auto replacement = SVGGElement::create(SVGNames::gTag, *referencedDocument()); 520 original->transferAttributesToShadowTreeReplacement(replacement.get()); 521 original->cloneChildNodes(replacement.ptr()); 522 associateReplacementClonesWithOriginals(replacement.get(), original.get()); 523 524 RefPtr<SVGElement> clonedTarget; 525 Element* targetCandidate = SVGURIReference::targetElementFromIRIString(original->href(), *referencedDocument()); 526 if (original->isValidTarget(targetCandidate)) { 527 SVGElement& originalTarget = downcast<SVGElement>(*targetCandidate); 528 clonedTarget = static_pointer_cast<SVGElement>(originalTarget.cloneElementWithChildren(document())); 529 associateClonesWithOriginals(*clonedTarget, originalTarget); 530 replacement->appendChild(clonedTarget); 531 } 532 533 removeDisallowedElementsFromSubtree(replacement.get()); 534 535 // Replace <use> with the <g> element we created. 536 original->parentNode()->replaceChild(replacement.ptr(), original.ptr()); 537 538 // Call transferSizeAttributesToShadowTreeTargetClone after putting the cloned elements into the 539 // shadow tree so it can use SVGElement::correspondingElement without triggering an assertion. 540 if (clonedTarget) 541 original->transferSizeAttributesToShadowTreeTargetClone(*clonedTarget); 542 543 // Continue iterating from the <g> element since the <use> element was replaced. 544 it = descendants.from(replacement.get()); 545 } 546 } 547 548 void SVGUseElement::expandSymbolElementsInShadowTree() 437 auto replacementClone = SVGGElement::create(document()); 438 cloneDataAndChildren(replacementClone.get(), originalClone); 439 440 replacementClone->removeAttribute(SVGNames::xAttr); 441 replacementClone->removeAttribute(SVGNames::yAttr); 442 replacementClone->removeAttribute(SVGNames::widthAttr); 443 replacementClone->removeAttribute(SVGNames::heightAttr); 444 replacementClone->removeAttribute(XLinkNames::hrefAttr); 445 446 if (target) 447 originalClone.cloneTarget(replacementClone.get(), *target); 448 449 originalClone.parentNode()->replaceChild(replacementClone.ptr(), &originalClone); 450 451 // Resume iterating, starting just inside the replacement clone. 452 it = descendants.from(replacementClone.get()); 453 } 454 } 455 456 void SVGUseElement::expandSymbolElementsInShadowTree() const 549 457 { 550 458 auto descendants = descendantsOfType<SVGSymbolElement>(*userAgentShadowRoot()); 551 auto end = descendants.end(); 552 for (auto it = descendants.begin(); it != end; ) { 553 SVGSymbolElement& original = *it; 459 for (auto it = descendants.begin(), end = descendants.end(); it != end; ) { 460 SVGSymbolElement& originalClone = *it; 554 461 it = end; // Efficiently quiets assertions due to the outstanding iterator. 555 462 … … 561 468 // 'svg' element will use values of 100% for these attributes. 562 469 563 // FIXME: Is it right to use referencedDocument() here instead of just document()? 564 // Can a shadow tree within this document really contain elements that are in a 565 // different document? 566 ASSERT(referencedDocument()); 567 auto replacement = SVGSVGElement::create(SVGNames::svgTag, *referencedDocument()); 568 replacement->cloneDataFromElement(original); 569 original.cloneChildNodes(replacement.ptr()); 570 associateReplacementClonesWithOriginals(replacement.get(), original); 571 572 removeDisallowedElementsFromSubtree(replacement.get()); 573 574 // Replace <symbol> with the <svg> element we created. 575 original.parentNode()->replaceChild(replacement.ptr(), &original); 576 577 // Continue iterating from the <svg> element since the <symbol> element was replaced. 578 it = descendants.from(replacement.get()); 579 } 580 } 581 582 void SVGUseElement::transferEventListenersToShadowTree() 583 { 584 ASSERT(userAgentShadowRoot()); 470 auto replacementClone = SVGSVGElement::create(document()); 471 cloneDataAndChildren(replacementClone.get(), originalClone); 472 473 originalClone.parentNode()->replaceChild(replacementClone.ptr(), &originalClone); 474 475 // Resume iterating, starting just inside the replacement clone. 476 it = descendants.from(replacementClone.get()); 477 } 478 } 479 480 void SVGUseElement::transferEventListenersToShadowTree() const 481 { 585 482 for (auto& descendant : descendantsOfType<SVGElement>(*userAgentShadowRoot())) { 586 ASSERT(descendant.correspondingElement());587 483 if (EventTargetData* data = descendant.correspondingElement()->eventTargetData()) 588 484 data->eventListenerMap.copyEventListenersNotCreatedFromMarkupToTarget(&descendant); … … 592 488 void SVGUseElement::invalidateShadowTree() 593 489 { 594 if (m_ needsShadowTreeRecreation)595 return; 596 m_ needsShadowTreeRecreation= true;490 if (m_shadowTreeNeedsUpdate) 491 return; 492 m_shadowTreeNeedsUpdate = true; 597 493 setNeedsStyleRecalc(ReconstructRenderTree); 598 494 invalidateDependentShadowTrees(); … … 602 498 { 603 499 for (auto* instance : instances()) { 604 if (SVGUseElement* element = instance->correspondingUseElement()) { 605 ASSERT(element->inDocument()); 500 if (auto* element = instance->correspondingUseElement()) 606 501 element->invalidateShadowTree(); 607 } 608 } 609 } 610 611 void SVGUseElement::transferAttributesToShadowTreeReplacement(SVGGElement& replacement) const 612 { 613 replacement.cloneDataFromElement(*this); 614 615 replacement.removeAttribute(SVGNames::xAttr); 616 replacement.removeAttribute(SVGNames::yAttr); 617 replacement.removeAttribute(SVGNames::widthAttr); 618 replacement.removeAttribute(SVGNames::heightAttr); 619 replacement.removeAttribute(XLinkNames::hrefAttr); 502 } 620 503 } 621 504 … … 625 508 return true; 626 509 627 auto* target = shadowTreeTargetClone();628 return target && target->hasRelativeLengths();510 auto* targetClone = this->targetClone(); 511 return targetClone && targetClone->hasRelativeLengths(); 629 512 } 630 513 631 514 void SVGUseElement::notifyFinished(CachedResource* resource) 632 515 { 633 if (!inDocument())634 return;635 636 516 invalidateShadowTree(); 637 517 if (resource->errorOccurred()) … … 641 521 } 642 522 643 bool SVGUseElement::cachedDocumentIsStillLoading()644 {645 if (m_cachedDocument && m_cachedDocument->isLoading())646 return true;647 return false;648 }649 650 523 void SVGUseElement::finishParsingChildren() 651 524 { 652 525 SVGGraphicsElement::finishParsingChildren(); 653 526 SVGExternalResourcesRequired::finishParsingChildren(); 654 if (m_wasInsertedByParser) { 655 buildPendingResource(); 656 m_wasInsertedByParser = false; 657 } 658 } 659 660 void SVGUseElement::setCachedDocument(CachedResourceHandle<CachedSVGDocument> cachedDocument) 661 { 662 if (m_cachedDocument == cachedDocument) 663 return; 664 665 if (m_cachedDocument) 666 m_cachedDocument->removeClient(this); 667 668 m_cachedDocument = cachedDocument; 669 if (m_cachedDocument) { 670 // We don't need the SVG document to create a new frame because the new document belongs to the parent UseElement. 671 m_cachedDocument->setShouldCreateFrameForDocument(false); 672 m_cachedDocument->addClient(this); 673 } 674 } 675 676 } 527 } 528 529 void SVGUseElement::updateExternalDocument() 530 { 531 URL externalDocumentURL; 532 if (inDocument() && isExternalURIReference(href(), document())) { 533 externalDocumentURL = document().completeURL(href()); 534 if (!externalDocumentURL.hasFragmentIdentifier()) 535 externalDocumentURL = URL(); 536 } 537 538 if (externalDocumentURL == (m_externalDocument ? m_externalDocument->url() : URL())) 539 return; 540 541 if (m_externalDocument) 542 m_externalDocument->removeClient(this); 543 544 if (externalDocumentURL.isNull()) 545 m_externalDocument = nullptr; 546 else { 547 CachedResourceRequest request { ResourceRequest { externalDocumentURL } }; 548 request.setInitiator(this); 549 m_externalDocument = document().cachedResourceLoader().requestSVGDocument(request); 550 if (m_externalDocument) { 551 // FIXME: Is it really OK for us to set this to false for a document that might be shared by another client? 552 m_externalDocument->setShouldCreateFrameForDocument(false); // No frame needed, we just want the elements. 553 m_externalDocument->addClient(this); 554 } 555 } 556 557 invalidateShadowTree(); 558 } 559 560 bool SVGUseElement::isValid() const 561 { 562 return SVGTests::isValid(); 563 } 564 565 bool SVGUseElement::haveLoadedRequiredResources() 566 { 567 return SVGExternalResourcesRequired::haveLoadedRequiredResources(); 568 } 569 570 void SVGUseElement::setHaveFiredLoadEvent(bool haveFiredLoadEvent) 571 { 572 m_haveFiredLoadEvent = haveFiredLoadEvent; 573 } 574 575 bool SVGUseElement::haveFiredLoadEvent() const 576 { 577 return m_haveFiredLoadEvent; 578 } 579 580 Timer* SVGUseElement::svgLoadEventTimer() 581 { 582 return &m_svgLoadEventTimer; 583 } 584 585 } -
trunk/Source/WebCore/svg/SVGUseElement.h
r179810 r179980 29 29 #include "SVGExternalResourcesRequired.h" 30 30 #include "SVGGraphicsElement.h" 31 #include "SVGNames.h"32 31 #include "SVGURIReference.h" 33 32 … … 37 36 class SVGGElement; 38 37 39 class SVGUseElement final : public SVGGraphicsElement, 40 public SVGExternalResourcesRequired, 41 public SVGURIReference, 42 public CachedSVGDocumentClient { 43 public: 44 static Ref<SVGUseElement> create(const QualifiedName&, Document&, bool wasInsertedByParser); 45 virtual ~SVGUseElement(); 46 47 void invalidateShadowTree(); 48 void invalidateDependentShadowTrees(); 49 50 RenderElement* rendererClipChild() const; 51 52 protected: 53 virtual void didNotifySubtreeInsertions(ContainerNode*) override; 54 55 private: 56 SVGUseElement(const QualifiedName&, Document&, bool wasInsertedByParser); 57 58 virtual bool isValid() const override { return SVGTests::isValid(); } 59 60 virtual InsertionNotificationRequest insertedInto(ContainerNode&) override; 61 virtual void removedFrom(ContainerNode&) override; 62 virtual void buildPendingResource() override; 63 64 bool isSupportedAttribute(const QualifiedName&); 65 virtual void parseAttribute(const QualifiedName&, const AtomicString&) override; 66 virtual void svgAttributeChanged(const QualifiedName&) override; 67 68 virtual void willAttachRenderers() override; 69 70 virtual RenderPtr<RenderElement> createElementRenderer(Ref<RenderStyle>&&) override; 71 virtual void toClipPath(Path&) override; 72 73 void clearResourceReferences(); 74 75 virtual bool haveLoadedRequiredResources() override { return SVGExternalResourcesRequired::haveLoadedRequiredResources(); } 76 77 virtual void finishParsingChildren() override; 78 virtual bool selfHasRelativeLengths() const override; 79 80 // Shadow tree handling. 81 void buildShadowTree(SVGElement& target); 82 void expandUseElementsInShadowTree(); 83 void expandSymbolElementsInShadowTree(); 84 SVGElement* shadowTreeTargetClone() const; 85 void transferEventListenersToShadowTree(); 86 void transferAttributesToShadowTreeReplacement(SVGGElement&) const; 87 void transferSizeAttributesToShadowTreeTargetClone(SVGElement&) const; 88 bool isValidTarget(Element*) const; 38 class SVGUseElement final : public SVGGraphicsElement, public SVGExternalResourcesRequired, public SVGURIReference, private CachedSVGDocumentClient { 89 39 90 40 BEGIN_DECLARE_ANIMATED_PROPERTIES(SVGUseElement) … … 97 47 END_DECLARE_ANIMATED_PROPERTIES 98 48 99 bool cachedDocumentIsStillLoading(); 49 public: 50 static Ref<SVGUseElement> create(const QualifiedName&, Document&); 51 virtual ~SVGUseElement(); 52 53 void invalidateShadowTree(); 54 55 RenderElement* rendererClipChild() const; 56 57 private: 58 SVGUseElement(const QualifiedName&, Document&); 59 60 virtual bool isValid() const override; 61 virtual InsertionNotificationRequest insertedInto(ContainerNode&) override; 62 virtual void removedFrom(ContainerNode&) override; 63 virtual void buildPendingResource() override; 64 virtual void parseAttribute(const QualifiedName&, const AtomicString&) override; 65 virtual void svgAttributeChanged(const QualifiedName&) override; 66 virtual void willAttachRenderers() override; 67 virtual RenderPtr<RenderElement> createElementRenderer(Ref<RenderStyle>&&) override; 68 virtual void toClipPath(Path&) override; 69 virtual bool haveLoadedRequiredResources() override; 70 virtual void finishParsingChildren() override; 71 virtual bool selfHasRelativeLengths() const override; 72 virtual void setHaveFiredLoadEvent(bool) override; 73 virtual bool haveFiredLoadEvent() const override; 74 virtual Timer* svgLoadEventTimer() override; 75 virtual void notifyFinished(CachedResource*) override; 76 100 77 Document* externalDocument() const; 101 virtual void notifyFinished(CachedResource*) override; 102 Document* referencedDocument() const; 103 void setCachedDocument(CachedResourceHandle<CachedSVGDocument>); 78 void updateExternalDocument(); 104 79 105 // SVGExternalResourcesRequired 106 virtual void setHaveFiredLoadEvent(bool haveFiredLoadEvent) override { m_haveFiredLoadEvent = haveFiredLoadEvent; } 107 virtual bool isParserInserted() const override { return m_wasInsertedByParser; } 108 virtual bool haveFiredLoadEvent() const override { return m_haveFiredLoadEvent; } 109 virtual Timer* svgLoadEventTimer() override { return &m_svgLoadEventTimer; } 80 SVGElement* findTarget(String* targetID = nullptr) const; 110 81 111 bool m_wasInsertedByParser; 112 bool m_haveFiredLoadEvent; 113 bool m_needsShadowTreeRecreation; 114 CachedResourceHandle<CachedSVGDocument> m_cachedDocument; 82 void cloneTarget(ContainerNode&, SVGElement& target) const; 83 SVGElement* targetClone() const; 84 85 void updateShadowTree(); 86 void expandUseElementsInShadowTree() const; 87 void expandSymbolElementsInShadowTree() const; 88 void transferEventListenersToShadowTree() const; 89 void transferSizeAttributesToTargetClone(SVGElement&) const; 90 91 void clearShadowTree(); 92 void invalidateDependentShadowTrees(); 93 94 bool m_haveFiredLoadEvent { false }; 95 bool m_shadowTreeNeedsUpdate { true }; 96 CachedResourceHandle<CachedSVGDocument> m_externalDocument; 115 97 Timer m_svgLoadEventTimer; 116 98 }; -
trunk/Source/WebCore/svg/svgtags.in
r174050 r179980 92 92 tref interfaceName=SVGTRefElement 93 93 tspan interfaceName=SVGTSpanElement 94 use constructorNeedsCreatedByParser94 use 95 95 view 96 96 #if ENABLE_SVG_FONTS
Note: See TracChangeset
for help on using the changeset viewer.