SVGUseElement follow-up improvements
authordarin@apple.com <darin@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 12 Feb 2015 03:53:48 +0000 (03:53 +0000)
committerdarin@apple.com <darin@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 12 Feb 2015 03:53:48 +0000 (03:53 +0000)
https://bugs.webkit.org/show_bug.cgi?id=141382

Reviewed by Antti Koivisto.

Source/WebCore:

* loader/cache/CachedSVGDocumentClient.h: Removed unneeded forward declaration.

* page/EventHandler.cpp: Removed unneeded include of SVGUseElement.h.
* rendering/svg/RenderSVGViewportContainer.cpp: Ditto.

* svg/SVGDocumentExtensions.cpp:
(WebCore::SVGDocumentExtensions::clearTargetDependencies): Removed too-specific
check that assumed that SVG elements in shadow trees are always for <use> elements.
This amounted to an unneeded optimization that could be removed with no bad effect.

* svg/SVGElement.cpp:
(WebCore::SVGElement::correspondingElement): Removed the assertions so this could
be used more freely outside of cases where the shadow tree state is fully consistent.
It's fine to have this just be a mechanical getter; there's nothing super-tricky
here that needs to be caught by the assertion.
(WebCore::SVGElement::title): Removed unneeded special handling for titles inside
the shadow tree.

* svg/SVGGElement.cpp:
(WebCore::SVGGElement::create): Added an overload that doesn't require explicitly
passing in the tag name.
* svg/SVGGElement.h: Ditto.
* svg/SVGSVGElement.cpp:
(WebCore::SVGSVGElement::create): Ditto.
* svg/SVGSVGElement.h: Ditto.

* svg/SVGUseElement.cpp: Removed a lot of unneeded includes.
(WebCore::SVGUseElement::SVGUseElement): Removed code to initialize some booleans.
We do that in the class definition now.
(WebCore::SVGUseElement::create): Removed the code that calls the
ensureUserAgentShadowRoot function unconditionally. That's properly done when
needed; no need to do it here.
(WebCore::SVGUseElement::~SVGUseElement): Removed unneeded code to destroy the
shadow tree (that happens automatically) and simplified the code to stop loading
the external document.
(WebCore::SVGUseElement::isSupportedAttribute): Deleted.
(WebCore::SVGUseElement::parseAttribute): Simplified this. Removed assumptions
about the intersection of various sets of attributes, and also removed the
isSupportedAttribute function. This seems to serve no purpose here, or in any
other SVG element class. I plan to remove it everywhere over time.
(WebCore::isWellFormedDocument): Deleted.
(WebCore::SVGUseElement::insertedInto): Simplified code by removing all the
special cases during initial parsing, and did the invalidation here rather than
deferring it to didNotifySubtreeInsertions. Added a call to the new function,
updateExternalDocument, since that won't do anything when the element is not
in a document.
(WebCore::SVGUseElement::didNotifySubtreeInsertions): Deleted.
(WebCore::SVGUseElement::removedFrom): Added code to call clearShadowTree and
updateExternalDocument. Both are efficient when doing nothing, and both are
appropriate since the element is no longer in a document.
(WebCore::SVGUseElement::referencedDocument): Deleted. No longer needed.
(WebCore::SVGUseElement::externalDocument): Streamlined the logic here, removing
multiple unneeded checks.
(WebCore::SVGUseElement::transferSizeAttributesToTargetClone): Renamed since
"target clone" is clear enough within this class, without explicitly stating
"shadow tree". All the clones are in the shadow tree.
(WebCore::SVGUseElement::svgAttributeChanged): Removed unneeded code calling
isSupportedAttribute. Changed the code that detects changes in href to just
call updateExternalDocument (for the document URL) and invalidateShadowTree
(for the fragment). Also updated the transferSizeAttributesToTargetClone logic
to only trigger on width and height and updated names.
(WebCore::SVGUseElement::willAttachRenderers): Updated for the new name of
m_shouldRebuildShadowTree and added a call through to the base class.
(WebCore::createAllowedElementSet): Added. A more efficient way to implement
the initialization of the set for isDisallowedElement.
(WebCore::isDisallowedElement): Simplified this by using the function above,
and also overloaded for both SVGElement and Element for a tiny efficiency boost.
(WebCore::SVGUseElement::clearShadowTree): Renamed form clearResourceReferences.
This is a much more straightforward name. Also deleted the code that sets the
m_needsShadowTreeRecreation flag to false. That should be done by the build
function, not here.
(WebCore::SVGUseElement::buildPendingResource): Made this just invalidate the
shadow tree now instead of explicitly building it.
(WebCore::SVGUseElement::updateShadowTree): Moved the code to create a shadow
tree here from buildPendingResource. ALso changed the logic so that we
always blow away the old shadow tree. Moved the comment about rebuilding things
every time here. Updated the code to use the findTarget and cloneTarget functions,
eliminating the buildShadowTree function entirely. Moved the call to
transferSizeAttributesToShadowTreeTargetClone inside cloneTarget. Also updated
for the name change for m_shouldRebuildShadowTree.
(WebCore::SVGUseElement::targetClone): Renamed from shadowTreeTargetClone.
No need to emphasize "shadow tree" since that's where all clones are.
(WebCore::isDirectReference): Streamlined a bit using "using namespace".
(WebCore::SVGUseElement::toClipPath): Rewrote to use early return and updated
for name changes. Also used ASCIILiteral.
(WebCore::SVGUseElement::rendererClipChild): Changed local variable names.
(WebCore::removeDisallowedElementsFromSubtree): Wrote the iteration in a
slightly more idiomatic style.
(WebCore::SVGUseElement::findTarget): Added. This new function implements
the rule for finding a valid target for a use element. This replaces logic
that was duplicated in two different places and it also includes all the
rules that were formerly in the isValidTarget function. Also, this implements
a correct check for a cycle that handles cases the code in isValidTarget did not.
(WebCore::SVGUseElement::isValidTarget): Deleted.
(WebCore::SVGUseElement::cloneTarget): Added. Helper function used both when
cloning the target of the top level <use> elements and for other <use> elements
inside the shadow tree.
(WebCore::cloneDataAndChildren): Added. Helper function that allows both the
<use> and <symbol> element expanding functions to be shorter and share more code.
(WebCore::SVGUseElement::expandUseElementsInShadowTree): Removed unneeded checks
of cachedDocumentIsStillLoading. Used the new findTarget function, which handles
finding the target cross-document correctly. Removed the incorrect use of
referencedDocument when creating new elements and finding targets. Refactored
to use the new cloneDataAndChildren function and also moved the code that removes
the special attributes here, replacing the transferAttributesToShadowTreeReplacement
function. Made a few other simplifications.
(WebCore::SVGUseElement::expandSymbolElementsInShadowTree): Ditto, just like the
<use> changes only simpler.
(WebCore::SVGUseElement::transferEventListenersToShadowTree): Made this const.
Removed unneeded assertions.
(WebCore::SVGUseElement::invalidateShadowTree): Updated for name change.
(WebCore::SVGUseElement::invalidateDependentShadowTrees): Removed assertion.
(WebCore::SVGUseElement::transferAttributesToShadowTreeReplacement): Deleted.
(WebCore::SVGUseElement::selfHasRelativeLengths): Tweaked names.
(WebCore::SVGUseElement::notifyFinished): Removed the inDocument check, since
this function will only be called for elements that are in a document.
(WebCore::SVGUseElement::cachedDocumentIsStillLoading): Deleted.
(WebCore::SVGUseElement::finishParsingChildren): Removed the code that calls
buildPendingResource here. Shadow tree updating is driven solely by renderer
generation now.
(WebCore::SVGUseElement::updateExternalDocument): Replaced setCachedDocument
with this. This function knows how to load a different document if the URL
has changed, or leave it alone if not, and also stop the load if it should.
(WebCore::SVGUseElement::isValid): Moved this here from the header, since it's
always being called virtually.
(WebCore::SVGUseElement::haveLoadedRequiredResources): Ditto.
(WebCore::SVGUseElement::setHaveFiredLoadEvent): Ditto.
(WebCore::SVGUseElement::haveFiredLoadEvent): Ditto.
(WebCore::SVGUseElement::svgLoadEventTimer): Ditto.

* svg/SVGUseElement.h: Removed unneeded include. Moved the animated properties
to the top of the class because they are public DOM API and so are logical to
list first. I'd like to do that for other classes too over time. Changed to
derive privately from CachedSVGDocumentClient. Made the function
invalidateDependentShadowTrees private. Removed didNotifySubtreeInsertions,
isSupportedAttribute, clearResourceReferences, buildShadowTree,
transferAttributesToShadowTreeReplacement, isParserInserted, and
m_wasInsertedByParser. Added updateExternalDocument, cloneTarget, targetClone,
updateShadowTree, and clearShadowTree. Also did a couple other renames,
including renaming m_cachedDocument to m_externalDocument.

* svg/svgtags.in: Removed constructorNeedsCreatedByParser from the <use>
element since we don't have to handle constructing by the parser specially.

LayoutTests:

Modified some tests to be reference tests since the change in implementation slightly changed
the behavior, but not in a way that matters. Other similar updates.

* TestExpectations: Expect a progression in imported/mozilla/svg/dynamic-use-02.svg.

* platform/gtk/svg/custom/relative-sized-shadow-tree-content-with-symbol-expected.png: Removed.
* platform/gtk/svg/custom/relative-sized-shadow-tree-content-with-symbol-expected.txt: Removed.
* platform/gtk/svg/custom/use-property-synchronization-crash-expected.png: Removed.
* platform/ios-sim-deprecated/svg/custom/relative-sized-shadow-tree-content-with-symbol-expected.txt: Removed.
* platform/ios-simulator/svg/custom/relative-sized-shadow-tree-content-with-symbol-expected.txt: Removed.
* platform/mac-mountainlion/svg/custom/relative-sized-shadow-tree-content-with-symbol-expected.txt: Removed.
* platform/mac/svg/custom/relative-sized-shadow-tree-content-with-symbol-expected.png: Removed.
* platform/mac/svg/custom/relative-sized-shadow-tree-content-with-symbol-expected.txt: Removed.
* platform/mac/svg/custom/use-property-synchronization-crash-expected.png: Removed.

* svg/animations/use-animate-width-and-height-expected.txt: Updated to expect the new expression
name from the modified test.
* svg/animations/use-animate-width-and-height.html: THe state of the shadow root now depends on
layout, so force layout before inspecting it.

* svg/custom/relative-sized-shadow-tree-content-with-symbol-expected.xhtml: Added.
* svg/custom/relative-sized-shadow-tree-content-with-symbol.xhtml: Made this no longer be a
repaint test. Not sure why we are using those in so many cases. Also made it be a reference test.

* svg/custom/use-property-synchronization-crash-expected.svg: Added.
* svg/custom/use-property-synchronization-crash-expected.txt: Removed.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@179980 268f45cc-cd09-0410-ab3c-d52691b4dbfc

30 files changed:
LayoutTests/ChangeLog
LayoutTests/TestExpectations
LayoutTests/platform/gtk/svg/custom/relative-sized-shadow-tree-content-with-symbol-expected.png [deleted file]
LayoutTests/platform/gtk/svg/custom/relative-sized-shadow-tree-content-with-symbol-expected.txt [deleted file]
LayoutTests/platform/gtk/svg/custom/use-property-synchronization-crash-expected.png [deleted file]
LayoutTests/platform/ios-sim-deprecated/svg/custom/relative-sized-shadow-tree-content-with-symbol-expected.txt [deleted file]
LayoutTests/platform/ios-simulator/svg/custom/relative-sized-shadow-tree-content-with-symbol-expected.txt [deleted file]
LayoutTests/platform/mac-mountainlion/svg/custom/relative-sized-shadow-tree-content-with-symbol-expected.txt [deleted file]
LayoutTests/platform/mac/svg/custom/relative-sized-shadow-tree-content-with-symbol-expected.png [deleted file]
LayoutTests/platform/mac/svg/custom/relative-sized-shadow-tree-content-with-symbol-expected.txt [deleted file]
LayoutTests/platform/mac/svg/custom/use-property-synchronization-crash-expected.png [deleted file]
LayoutTests/svg/animations/use-animate-width-and-height-expected.txt
LayoutTests/svg/animations/use-animate-width-and-height.html
LayoutTests/svg/custom/relative-sized-shadow-tree-content-with-symbol-expected.xhtml [new file with mode: 0644]
LayoutTests/svg/custom/relative-sized-shadow-tree-content-with-symbol.xhtml
LayoutTests/svg/custom/use-property-synchronization-crash-expected.svg [new file with mode: 0644]
LayoutTests/svg/custom/use-property-synchronization-crash-expected.txt [deleted file]
Source/WebCore/ChangeLog
Source/WebCore/loader/cache/CachedSVGDocumentClient.h
Source/WebCore/page/EventHandler.cpp
Source/WebCore/rendering/svg/RenderSVGViewportContainer.cpp
Source/WebCore/svg/SVGDocumentExtensions.cpp
Source/WebCore/svg/SVGElement.cpp
Source/WebCore/svg/SVGGElement.cpp
Source/WebCore/svg/SVGGElement.h
Source/WebCore/svg/SVGSVGElement.cpp
Source/WebCore/svg/SVGSVGElement.h
Source/WebCore/svg/SVGUseElement.cpp
Source/WebCore/svg/SVGUseElement.h
Source/WebCore/svg/svgtags.in

index f344a6758f98737874726d80de77e067dfc7019d..7d7e80e272209289d683713e2e692bd1cb7fe23a 100644 (file)
@@ -1,3 +1,37 @@
+2015-02-11  Darin Adler  <darin@apple.com>
+
+        SVGUseElement follow-up improvements
+        https://bugs.webkit.org/show_bug.cgi?id=141382
+
+        Reviewed by Antti Koivisto.
+
+        Modified some tests to be reference tests since the change in implementation slightly changed
+        the behavior, but not in a way that matters. Other similar updates.
+
+        * TestExpectations: Expect a progression in imported/mozilla/svg/dynamic-use-02.svg.
+
+        * platform/gtk/svg/custom/relative-sized-shadow-tree-content-with-symbol-expected.png: Removed.
+        * platform/gtk/svg/custom/relative-sized-shadow-tree-content-with-symbol-expected.txt: Removed.
+        * platform/gtk/svg/custom/use-property-synchronization-crash-expected.png: Removed.
+        * platform/ios-sim-deprecated/svg/custom/relative-sized-shadow-tree-content-with-symbol-expected.txt: Removed.
+        * platform/ios-simulator/svg/custom/relative-sized-shadow-tree-content-with-symbol-expected.txt: Removed.
+        * platform/mac-mountainlion/svg/custom/relative-sized-shadow-tree-content-with-symbol-expected.txt: Removed.
+        * platform/mac/svg/custom/relative-sized-shadow-tree-content-with-symbol-expected.png: Removed.
+        * platform/mac/svg/custom/relative-sized-shadow-tree-content-with-symbol-expected.txt: Removed.
+        * platform/mac/svg/custom/use-property-synchronization-crash-expected.png: Removed.
+
+        * svg/animations/use-animate-width-and-height-expected.txt: Updated to expect the new expression
+        name from the modified test.
+        * svg/animations/use-animate-width-and-height.html: THe state of the shadow root now depends on
+        layout, so force layout before inspecting it.
+
+        * svg/custom/relative-sized-shadow-tree-content-with-symbol-expected.xhtml: Added.
+        * svg/custom/relative-sized-shadow-tree-content-with-symbol.xhtml: Made this no longer be a
+        repaint test. Not sure why we are using those in so many cases. Also made it be a reference test.
+
+        * svg/custom/use-property-synchronization-crash-expected.svg: Added.
+        * svg/custom/use-property-synchronization-crash-expected.txt: Removed.
+
 2015-02-11  Gyuyoung Kim  <gyuyoung.kim@samsung.com>
 
         Unreviewed, EFL gardening. Mark multi-column failing tests to Failure.
index c5c80c1460e4565a203fbae8d7944819b24e9eef..330e2a13e294114639c56ba45e3f0ca9d82f55dc 100644 (file)
@@ -399,7 +399,6 @@ webkit.org/b/139155 imported/mozilla/svg/dynamic-textPath-02.svg [ ImageOnlyFail
 webkit.org/b/139155 imported/mozilla/svg/dynamic-textPath-03.svg [ ImageOnlyFailure ]
 webkit.org/b/139155 imported/mozilla/svg/dynamic-pattern-01.svg [ ImageOnlyFailure ]
 webkit.org/b/139155 imported/mozilla/svg/dynamic-use-01.svg [ ImageOnlyFailure ]
-webkit.org/b/139155 imported/mozilla/svg/dynamic-use-02.svg [ ImageOnlyFailure ]
 webkit.org/b/139155 imported/mozilla/svg/dynamic-use-03.svg [ ImageOnlyFailure ]
 webkit.org/b/139155 imported/mozilla/svg/dynamic-use-07.svg [ ImageOnlyFailure ]
 webkit.org/b/139183 imported/mozilla/svg/text/pseudo-first-letter.svg [ ImageOnlyFailure ]
diff --git a/LayoutTests/platform/gtk/svg/custom/relative-sized-shadow-tree-content-with-symbol-expected.png b/LayoutTests/platform/gtk/svg/custom/relative-sized-shadow-tree-content-with-symbol-expected.png
deleted file mode 100644 (file)
index fb40c07..0000000
Binary files a/LayoutTests/platform/gtk/svg/custom/relative-sized-shadow-tree-content-with-symbol-expected.png and /dev/null differ
diff --git a/LayoutTests/platform/gtk/svg/custom/relative-sized-shadow-tree-content-with-symbol-expected.txt b/LayoutTests/platform/gtk/svg/custom/relative-sized-shadow-tree-content-with-symbol-expected.txt
deleted file mode 100644 (file)
index 588c714..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-layer at (0,0) size 800x600
-  RenderView at (0,0) size 800x600
-layer at (0,0) size 800x476
-  RenderBlock {html} at (0,0) size 800x476
-    RenderBody {body} at (8,16) size 784x452
-      RenderBlock {p} at (0,0) size 784x34
-        RenderText {#text} at (0,0) size 729x34
-          text run at (0,0) width 729: "The svg area contained in the div element (red box), should fill out the whole area (two green rectangles, first: (0,0)-"
-          text run at (0,17) width 670: "(50%,50%), second: (50%,50%)-(100%,100%)), especially after resizing the content box to a different size"
-      RenderBlock {div} at (0,50) size 402x402 [border: (1px solid #FF0000)]
-        RenderSVGRoot {svg} at (9,67) size 400x400
-          RenderSVGHiddenContainer {defs} at (0,0) size 0x0
-            RenderSVGHiddenContainer {symbol} at (0,0) size 0x0
-              RenderSVGRect {rect} at (9,67) size 0x0 [fill={[type=SOLID] [color=#008000]}] [x=0.00] [y=0.00] [width=0.00] [height=0.00]
-              RenderSVGRect {rect} at (9,67) size 100x100 [fill={[type=SOLID] [color=#008000]}] [x=0.00] [y=0.00] [width=100.00] [height=100.00]
-          RenderSVGContainer {use} at (9,67) size 400x400
-            RenderSVGViewportContainer {svg} at (9,67) size 400x400
-              RenderSVGRect {rect} at (209,267) size 200x200 [fill={[type=SOLID] [color=#008000]}] [x=100.00] [y=100.00] [width=100.00] [height=100.00]
-              RenderSVGRect {rect} at (9,67) size 200x200 [fill={[type=SOLID] [color=#008000]}] [x=0.00] [y=0.00] [width=100.00] [height=100.00]
-        RenderText {#text} at (0,0) size 0x0
diff --git a/LayoutTests/platform/gtk/svg/custom/use-property-synchronization-crash-expected.png b/LayoutTests/platform/gtk/svg/custom/use-property-synchronization-crash-expected.png
deleted file mode 100644 (file)
index dc14b60..0000000
Binary files a/LayoutTests/platform/gtk/svg/custom/use-property-synchronization-crash-expected.png and /dev/null differ
diff --git a/LayoutTests/platform/ios-sim-deprecated/svg/custom/relative-sized-shadow-tree-content-with-symbol-expected.txt b/LayoutTests/platform/ios-sim-deprecated/svg/custom/relative-sized-shadow-tree-content-with-symbol-expected.txt
deleted file mode 100644 (file)
index e101b71..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-layer at (0,0) size 800x600
-  RenderView at (0,0) size 800x600
-layer at (0,0) size 800x482
-  RenderBlock {html} at (0,0) size 800x482
-    RenderBody {body} at (8,16) size 784x458
-      RenderBlock {p} at (0,0) size 784x40
-        RenderText {#text} at (0,0) size 746x39
-          text run at (0,0) width 746: "The svg area contained in the div element (red box), should fill out the whole area (two green rectangles, first: (0,0)-"
-          text run at (0,20) width 686: "(50%,50%), second: (50%,50%)-(100%,100%)), especially after resizing the content box to a different size"
-      RenderBlock {div} at (0,56) size 402x402 [border: (1px solid #FF0000)]
-        RenderSVGRoot {svg} at (9,73) size 400x400
-          RenderSVGHiddenContainer {defs} at (0,0) size 0x0
-            RenderSVGHiddenContainer {symbol} at (0,0) size 0x0
-              RenderSVGRect {rect} at (9,73) size 0x0 [fill={[type=SOLID] [color=#008000]}] [x=0.00] [y=0.00] [width=0.00] [height=0.00]
-              RenderSVGRect {rect} at (9,73) size 100x100 [fill={[type=SOLID] [color=#008000]}] [x=0.00] [y=0.00] [width=100.00] [height=100.00]
-          RenderSVGContainer {use} at (9,73) size 400x400
-            RenderSVGViewportContainer {svg} at (9,73) size 400x400
-              RenderSVGRect {rect} at (209,273) size 200x200 [fill={[type=SOLID] [color=#008000]}] [x=100.00] [y=100.00] [width=100.00] [height=100.00]
-              RenderSVGRect {rect} at (9,73) size 200x200 [fill={[type=SOLID] [color=#008000]}] [x=0.00] [y=0.00] [width=100.00] [height=100.00]
-        RenderText {#text} at (0,0) size 0x0
diff --git a/LayoutTests/platform/ios-simulator/svg/custom/relative-sized-shadow-tree-content-with-symbol-expected.txt b/LayoutTests/platform/ios-simulator/svg/custom/relative-sized-shadow-tree-content-with-symbol-expected.txt
deleted file mode 100644 (file)
index e101b71..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-layer at (0,0) size 800x600
-  RenderView at (0,0) size 800x600
-layer at (0,0) size 800x482
-  RenderBlock {html} at (0,0) size 800x482
-    RenderBody {body} at (8,16) size 784x458
-      RenderBlock {p} at (0,0) size 784x40
-        RenderText {#text} at (0,0) size 746x39
-          text run at (0,0) width 746: "The svg area contained in the div element (red box), should fill out the whole area (two green rectangles, first: (0,0)-"
-          text run at (0,20) width 686: "(50%,50%), second: (50%,50%)-(100%,100%)), especially after resizing the content box to a different size"
-      RenderBlock {div} at (0,56) size 402x402 [border: (1px solid #FF0000)]
-        RenderSVGRoot {svg} at (9,73) size 400x400
-          RenderSVGHiddenContainer {defs} at (0,0) size 0x0
-            RenderSVGHiddenContainer {symbol} at (0,0) size 0x0
-              RenderSVGRect {rect} at (9,73) size 0x0 [fill={[type=SOLID] [color=#008000]}] [x=0.00] [y=0.00] [width=0.00] [height=0.00]
-              RenderSVGRect {rect} at (9,73) size 100x100 [fill={[type=SOLID] [color=#008000]}] [x=0.00] [y=0.00] [width=100.00] [height=100.00]
-          RenderSVGContainer {use} at (9,73) size 400x400
-            RenderSVGViewportContainer {svg} at (9,73) size 400x400
-              RenderSVGRect {rect} at (209,273) size 200x200 [fill={[type=SOLID] [color=#008000]}] [x=100.00] [y=100.00] [width=100.00] [height=100.00]
-              RenderSVGRect {rect} at (9,73) size 200x200 [fill={[type=SOLID] [color=#008000]}] [x=0.00] [y=0.00] [width=100.00] [height=100.00]
-        RenderText {#text} at (0,0) size 0x0
diff --git a/LayoutTests/platform/mac-mountainlion/svg/custom/relative-sized-shadow-tree-content-with-symbol-expected.txt b/LayoutTests/platform/mac-mountainlion/svg/custom/relative-sized-shadow-tree-content-with-symbol-expected.txt
deleted file mode 100644 (file)
index 11a783c..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-layer at (0,0) size 800x600
-  RenderView at (0,0) size 800x600
-layer at (0,0) size 800x478
-  RenderBlock {html} at (0,0) size 800x478
-    RenderBody {body} at (8,16) size 784x454
-      RenderBlock {p} at (0,0) size 784x36
-        RenderText {#text} at (0,0) size 729x36
-          text run at (0,0) width 729: "The svg area contained in the div element (red box), should fill out the whole area (two green rectangles, first: (0,0)-"
-          text run at (0,18) width 670: "(50%,50%), second: (50%,50%)-(100%,100%)), especially after resizing the content box to a different size"
-      RenderBlock {div} at (0,52) size 402x402 [border: (1px solid #FF0000)]
-        RenderSVGRoot {svg} at (9,69) size 400x400
-          RenderSVGHiddenContainer {defs} at (0,0) size 0x0
-            RenderSVGHiddenContainer {symbol} at (0,0) size 0x0
-              RenderSVGRect {rect} at (9,69) size 0x0 [fill={[type=SOLID] [color=#008000]}] [x=0.00] [y=0.00] [width=0.00] [height=0.00]
-              RenderSVGRect {rect} at (9,69) size 100x100 [fill={[type=SOLID] [color=#008000]}] [x=0.00] [y=0.00] [width=100.00] [height=100.00]
-          RenderSVGContainer {use} at (9,69) size 400x400
-            RenderSVGViewportContainer {svg} at (9,69) size 400x400
-              RenderSVGRect {rect} at (209,269) size 200x200 [fill={[type=SOLID] [color=#008000]}] [x=100.00] [y=100.00] [width=100.00] [height=100.00]
-              RenderSVGRect {rect} at (9,69) size 200x200 [fill={[type=SOLID] [color=#008000]}] [x=0.00] [y=0.00] [width=100.00] [height=100.00]
-        RenderText {#text} at (0,0) size 0x0
diff --git a/LayoutTests/platform/mac/svg/custom/relative-sized-shadow-tree-content-with-symbol-expected.png b/LayoutTests/platform/mac/svg/custom/relative-sized-shadow-tree-content-with-symbol-expected.png
deleted file mode 100644 (file)
index b0e602d..0000000
Binary files a/LayoutTests/platform/mac/svg/custom/relative-sized-shadow-tree-content-with-symbol-expected.png and /dev/null differ
diff --git a/LayoutTests/platform/mac/svg/custom/relative-sized-shadow-tree-content-with-symbol-expected.txt b/LayoutTests/platform/mac/svg/custom/relative-sized-shadow-tree-content-with-symbol-expected.txt
deleted file mode 100644 (file)
index 3c48a75..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-layer at (0,0) size 800x600
-  RenderView at (0,0) size 800x600
-layer at (0,0) size 800x478
-  RenderBlock {html} at (0,0) size 800x478
-    RenderBody {body} at (8,16) size 784x454
-      RenderBlock {p} at (0,0) size 784x36
-        RenderText {#text} at (0,0) size 744x36
-          text run at (0,0) width 744: "The svg area contained in the div element (red box), should fill out the whole area (two green rectangles, first: (0,0)-"
-          text run at (0,18) width 686: "(50%,50%), second: (50%,50%)-(100%,100%)), especially after resizing the content box to a different size"
-      RenderBlock {div} at (0,52) size 402x402 [border: (1px solid #FF0000)]
-        RenderSVGRoot {svg} at (9,69) size 200x200
-          RenderSVGHiddenContainer {defs} at (0,0) size 0x0
-            RenderSVGHiddenContainer {symbol} at (0,0) size 0x0
-              RenderSVGRect {rect} at (9,69) size 0x0 [fill={[type=SOLID] [color=#008000]}] [x=0.00] [y=0.00] [width=0.00] [height=0.00]
-              RenderSVGRect {rect} at (9,69) size 100x100 [fill={[type=SOLID] [color=#008000]}] [x=0.00] [y=0.00] [width=100.00] [height=100.00]
-          RenderSVGContainer {use} at (9,69) size 200x200
-            RenderSVGViewportContainer {svg} at (9,69) size 200x200
-              RenderSVGRect {rect} at (109,169) size 100x100 [fill={[type=SOLID] [color=#008000]}] [x=100.00] [y=100.00] [width=100.00] [height=100.00]
-              RenderSVGRect {rect} at (9,69) size 100x100 [fill={[type=SOLID] [color=#008000]}] [x=0.00] [y=0.00] [width=100.00] [height=100.00]
-        RenderText {#text} at (0,0) size 0x0
diff --git a/LayoutTests/platform/mac/svg/custom/use-property-synchronization-crash-expected.png b/LayoutTests/platform/mac/svg/custom/use-property-synchronization-crash-expected.png
deleted file mode 100644 (file)
index decda76..0000000
Binary files a/LayoutTests/platform/mac/svg/custom/use-property-synchronization-crash-expected.png and /dev/null differ
index 2aa4254d12d061ca0602b6d8ded4c531c8abc3c4..04c63576ad4117a0eca67f29487298090bee64f3 100644 (file)
@@ -9,40 +9,40 @@ PASS use.height.animVal.value is 100
 PASS use.height.baseVal.value is 100
 PASS use.getAttribute('width') is '100'
 PASS use.getAttribute('height') is '100'
-PASS shadowRoot.firstChild.width.animVal.value is 100
-PASS shadowRoot.firstChild.height.animVal.value is 100
+PASS useElementTargetClone().width.animVal.value is 100
+PASS useElementTargetClone().height.animVal.value is 100
 PASS use.width.animVal.value is 105
 PASS use.width.baseVal.value is 100
 PASS use.height.animVal.value is 105
 PASS use.height.baseVal.value is 100
 FAIL use.getAttribute('width') should be 105. Was 100.
 FAIL use.getAttribute('height') should be 105. Was 100.
-PASS shadowRoot.firstChild.width.animVal.value is 105
-PASS shadowRoot.firstChild.height.animVal.value is 105
+PASS useElementTargetClone().width.animVal.value is 105
+PASS useElementTargetClone().height.animVal.value is 105
 PASS use.width.animVal.value is 115
 PASS use.width.baseVal.value is 100
 PASS use.height.animVal.value is 115
 PASS use.height.baseVal.value is 100
 FAIL use.getAttribute('width') should be 115. Was 100.
 FAIL use.getAttribute('height') should be 115. Was 100.
-PASS shadowRoot.firstChild.width.animVal.value is 115
-PASS shadowRoot.firstChild.height.animVal.value is 115
+PASS useElementTargetClone().width.animVal.value is 115
+PASS useElementTargetClone().height.animVal.value is 115
 PASS use.width.animVal.value is 125
 PASS use.width.baseVal.value is 100
 PASS use.height.animVal.value is 125
 PASS use.height.baseVal.value is 100
 FAIL use.getAttribute('width') should be 125. Was 100.
 FAIL use.getAttribute('height') should be 125. Was 100.
-PASS shadowRoot.firstChild.width.animVal.value is 125
-PASS shadowRoot.firstChild.height.animVal.value is 125
+PASS useElementTargetClone().width.animVal.value is 125
+PASS useElementTargetClone().height.animVal.value is 125
 PASS use.width.animVal.value is 135
 PASS use.width.baseVal.value is 100
 PASS use.height.animVal.value is 135
 PASS use.height.baseVal.value is 100
 FAIL use.getAttribute('width') should be 135. Was 100.
 FAIL use.getAttribute('height') should be 135. Was 100.
-PASS shadowRoot.firstChild.width.animVal.value is 135
-PASS shadowRoot.firstChild.height.animVal.value is 135
+PASS useElementTargetClone().width.animVal.value is 135
+PASS useElementTargetClone().height.animVal.value is 135
 PASS successfullyParsed is true
 
 TEST COMPLETE
index cdc0ad243c883b80b0556b61c36f7d9c9190730f..3926d4552d894cca0b8fe868ab29e92513342045 100644 (file)
@@ -58,7 +58,11 @@ animate2.setAttribute("from", "100");
 animate2.setAttribute("to", "200");
 use.appendChild(animate2);
 
-var shadowRoot = internals.shadowRoot(use);
+function useElementTargetClone()
+{
+    document.body.offsetWidth;
+    return internals.shadowRoot(use).firstChild;
+}
 
 function sample1()
 {
@@ -69,8 +73,8 @@ function sample1()
     shouldBe("use.height.baseVal.value", "100");
     shouldBe("use.getAttribute('width')", "'100'");
     shouldBe("use.getAttribute('height')", "'100'");
-    shouldBe("shadowRoot.firstChild.width.animVal.value", "100");
-    shouldBe("shadowRoot.firstChild.height.animVal.value", "100");
+    shouldBe("useElementTargetClone().width.animVal.value", "100");
+    shouldBe("useElementTargetClone().height.animVal.value", "100");
 }
 
 function sample2()
@@ -81,8 +85,8 @@ function sample2()
     shouldBe("use.height.baseVal.value", "100");
     shouldBe("use.getAttribute('width')", "'105'");
     shouldBe("use.getAttribute('height')", "'105'");
-    shouldBe("shadowRoot.firstChild.width.animVal.value", "105");
-    shouldBe("shadowRoot.firstChild.height.animVal.value", "105");
+    shouldBe("useElementTargetClone().width.animVal.value", "105");
+    shouldBe("useElementTargetClone().height.animVal.value", "105");
 }
 
 function sample3()
@@ -93,8 +97,8 @@ function sample3()
     shouldBe("use.height.baseVal.value", "100");
     shouldBe("use.getAttribute('width')", "'115'");
     shouldBe("use.getAttribute('height')", "'115'");
-    shouldBe("shadowRoot.firstChild.width.animVal.value", "115");
-    shouldBe("shadowRoot.firstChild.height.animVal.value", "115");
+    shouldBe("useElementTargetClone().width.animVal.value", "115");
+    shouldBe("useElementTargetClone().height.animVal.value", "115");
 }
 
 function sample4() {
@@ -104,8 +108,8 @@ function sample4() {
     shouldBe("use.height.baseVal.value", "100");
     shouldBe("use.getAttribute('width')", "'125'");
     shouldBe("use.getAttribute('height')", "'125'");
-    shouldBe("shadowRoot.firstChild.width.animVal.value", "125");
-    shouldBe("shadowRoot.firstChild.height.animVal.value", "125");
+    shouldBe("useElementTargetClone().width.animVal.value", "125");
+    shouldBe("useElementTargetClone().height.animVal.value", "125");
 }
 
 function sample5()
@@ -116,8 +120,8 @@ function sample5()
     shouldBe("use.height.baseVal.value", "100");
     shouldBe("use.getAttribute('width')", "'135'");
     shouldBe("use.getAttribute('height')", "'135'");
-    shouldBe("shadowRoot.firstChild.width.animVal.value", "135");
-    shouldBe("shadowRoot.firstChild.height.animVal.value", "135");
+    shouldBe("useElementTargetClone().width.animVal.value", "135");
+    shouldBe("useElementTargetClone().height.animVal.value", "135");
 }
 
 function executeTest()
diff --git a/LayoutTests/svg/custom/relative-sized-shadow-tree-content-with-symbol-expected.xhtml b/LayoutTests/svg/custom/relative-sized-shadow-tree-content-with-symbol-expected.xhtml
new file mode 100644 (file)
index 0000000..61b8753
--- /dev/null
@@ -0,0 +1,11 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<body>
+    <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>
+    <div style="width: 400px; height: 400px; border: 1px solid red;">
+        <svg xmlns="http://www.w3.org/2000/svg" width="400" height="400">
+            <rect width="200" height="200" fill="green"/>
+            <rect x="200" y="200" width="200" height="200" fill="green"/>
+        </svg>
+    </div>
+</body>
+</html>
index 604e7eb818b073cf0b684d98a1a87996cfb376b8..d422d6117ab56cee068ada851f2598d8f0b1c5df 100644 (file)
@@ -1,8 +1,7 @@
 <html xmlns="http://www.w3.org/1999/xhtml">
 <head>
-<script src="../../fast/repaint/resources/repaint.js"></script>
 </head>
-<body onload="runRepaintTest()">
+<body>
     <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>
     <div id="contentBox" style="width: 100px; height: 400px; border: 1px solid red;">
         <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="100%" height="100%">
@@ -16,9 +15,7 @@
         </svg>
     </div>
     <script>
-        function repaintTest() {
-            document.getElementById("contentBox").style.setProperty("width", "400px");
-        }
+        document.getElementById("contentBox").style.setProperty("width", "400px");
     </script>
 </body>
 </html>
diff --git a/LayoutTests/svg/custom/use-property-synchronization-crash-expected.svg b/LayoutTests/svg/custom/use-property-synchronization-crash-expected.svg
new file mode 100644 (file)
index 0000000..ab65c7b
--- /dev/null
@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg">
+</svg>
+
diff --git a/LayoutTests/svg/custom/use-property-synchronization-crash-expected.txt b/LayoutTests/svg/custom/use-property-synchronization-crash-expected.txt
deleted file mode 100644 (file)
index f7e6e91..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-CONSOLE MESSAGE: line 5: Error: Problem parsing points="0"
-CONSOLE MESSAGE: line 7: Error: Problem parsing points="0"
-layer at (0,0) size 800x600
-  RenderView at (0,0) size 800x600
-layer at (0,0) size 800x600
-  RenderSVGRoot {svg} at (0,0) size 0x0
-    RenderSVGContainer {g} at (0,0) size 0x0
-      RenderSVGContainer {g} at (0,0) size 0x0
-        RenderSVGPath {polyline} at (0,0) size 0x0 [fill={[type=SOLID] [color=#000000]}] [points=""]
-      RenderSVGContainer {use} at (0,0) size 0x0
-        RenderSVGContainer {g} at (0,0) size 0x0
-          RenderSVGPath {polyline} at (0,0) size 0x0 [fill={[type=SOLID] [color=#000000]}] [points=""]
-    RenderSVGContainer {g} at (0,0) size 0x0
index 135b3ec94d6d28c2b8ed973c63505fd3cf59cb6d..53d20c65010ac2a994e85b4f97b6627a19393e7d 100644 (file)
@@ -1,3 +1,154 @@
+2015-02-11  Darin Adler  <darin@apple.com>
+
+        SVGUseElement follow-up improvements
+        https://bugs.webkit.org/show_bug.cgi?id=141382
+
+        Reviewed by Antti Koivisto.
+
+        * loader/cache/CachedSVGDocumentClient.h: Removed unneeded forward declaration.
+
+        * page/EventHandler.cpp: Removed unneeded include of SVGUseElement.h.
+        * rendering/svg/RenderSVGViewportContainer.cpp: Ditto.
+
+        * svg/SVGDocumentExtensions.cpp:
+        (WebCore::SVGDocumentExtensions::clearTargetDependencies): Removed too-specific
+        check that assumed that SVG elements in shadow trees are always for <use> elements.
+        This amounted to an unneeded optimization that could be removed with no bad effect.
+
+        * svg/SVGElement.cpp:
+        (WebCore::SVGElement::correspondingElement): Removed the assertions so this could
+        be used more freely outside of cases where the shadow tree state is fully consistent.
+        It's fine to have this just be a mechanical getter; there's nothing super-tricky
+        here that needs to be caught by the assertion.
+        (WebCore::SVGElement::title): Removed unneeded special handling for titles inside
+        the shadow tree.
+
+        * svg/SVGGElement.cpp:
+        (WebCore::SVGGElement::create): Added an overload that doesn't require explicitly
+        passing in the tag name.
+        * svg/SVGGElement.h: Ditto.
+        * svg/SVGSVGElement.cpp:
+        (WebCore::SVGSVGElement::create): Ditto.
+        * svg/SVGSVGElement.h: Ditto.
+
+        * svg/SVGUseElement.cpp: Removed a lot of unneeded includes.
+        (WebCore::SVGUseElement::SVGUseElement): Removed code to initialize some booleans.
+        We do that in the class definition now.
+        (WebCore::SVGUseElement::create): Removed the code that calls the
+        ensureUserAgentShadowRoot function unconditionally. That's properly done when
+        needed; no need to do it here.
+        (WebCore::SVGUseElement::~SVGUseElement): Removed unneeded code to destroy the
+        shadow tree (that happens automatically) and simplified the code to stop loading
+        the external document.
+        (WebCore::SVGUseElement::isSupportedAttribute): Deleted.
+        (WebCore::SVGUseElement::parseAttribute): Simplified this. Removed assumptions
+        about the intersection of various sets of attributes, and also removed the
+        isSupportedAttribute function. This seems to serve no purpose here, or in any
+        other SVG element class. I plan to remove it everywhere over time.
+        (WebCore::isWellFormedDocument): Deleted.
+        (WebCore::SVGUseElement::insertedInto): Simplified code by removing all the
+        special cases during initial parsing, and did the invalidation here rather than
+        deferring it to didNotifySubtreeInsertions. Added a call to the new function,
+        updateExternalDocument, since that won't do anything when the element is not
+        in a document.
+        (WebCore::SVGUseElement::didNotifySubtreeInsertions): Deleted.
+        (WebCore::SVGUseElement::removedFrom): Added code to call clearShadowTree and
+        updateExternalDocument. Both are efficient when doing nothing, and both are
+        appropriate since the element is no longer in a document.
+        (WebCore::SVGUseElement::referencedDocument): Deleted. No longer needed.
+        (WebCore::SVGUseElement::externalDocument): Streamlined the logic here, removing
+        multiple unneeded checks.
+        (WebCore::SVGUseElement::transferSizeAttributesToTargetClone): Renamed since
+        "target clone" is clear enough within this class, without explicitly stating
+        "shadow tree". All the clones are in the shadow tree.
+        (WebCore::SVGUseElement::svgAttributeChanged): Removed unneeded code calling
+        isSupportedAttribute. Changed the code that detects changes in href to just
+        call updateExternalDocument (for the document URL) and invalidateShadowTree
+        (for the fragment). Also updated the transferSizeAttributesToTargetClone logic
+        to only trigger on width and height and updated names.
+        (WebCore::SVGUseElement::willAttachRenderers): Updated for the new name of
+        m_shouldRebuildShadowTree and added a call through to the base class.
+        (WebCore::createAllowedElementSet): Added. A more efficient way to implement
+        the initialization of the set for isDisallowedElement.
+        (WebCore::isDisallowedElement): Simplified this by using the function above,
+        and also overloaded for both SVGElement and Element for a tiny efficiency boost.
+        (WebCore::SVGUseElement::clearShadowTree): Renamed form clearResourceReferences.
+        This is a much more straightforward name. Also deleted the code that sets the
+        m_needsShadowTreeRecreation flag to false. That should be done by the build
+        function, not here.
+        (WebCore::SVGUseElement::buildPendingResource): Made this just invalidate the
+        shadow tree now instead of explicitly building it.
+        (WebCore::SVGUseElement::updateShadowTree): Moved the code to create a shadow
+        tree here from buildPendingResource. ALso changed the logic so that we
+        always blow away the old shadow tree. Moved the comment about rebuilding things
+        every time here. Updated the code to use the findTarget and cloneTarget functions,
+        eliminating the buildShadowTree function entirely. Moved the call to
+        transferSizeAttributesToShadowTreeTargetClone inside cloneTarget. Also updated
+        for the name change for m_shouldRebuildShadowTree.
+        (WebCore::SVGUseElement::targetClone): Renamed from shadowTreeTargetClone.
+        No need to emphasize "shadow tree" since that's where all clones are.
+        (WebCore::isDirectReference): Streamlined a bit using "using namespace".
+        (WebCore::SVGUseElement::toClipPath): Rewrote to use early return and updated
+        for name changes. Also used ASCIILiteral.
+        (WebCore::SVGUseElement::rendererClipChild): Changed local variable names.
+        (WebCore::removeDisallowedElementsFromSubtree): Wrote the iteration in a
+        slightly more idiomatic style.
+        (WebCore::SVGUseElement::findTarget): Added. This new function implements
+        the rule for finding a valid target for a use element. This replaces logic
+        that was duplicated in two different places and it also includes all the
+        rules that were formerly in the isValidTarget function. Also, this implements
+        a correct check for a cycle that handles cases the code in isValidTarget did not.
+        (WebCore::SVGUseElement::isValidTarget): Deleted.
+        (WebCore::SVGUseElement::cloneTarget): Added. Helper function used both when
+        cloning the target of the top level <use> elements and for other <use> elements
+        inside the shadow tree.
+        (WebCore::cloneDataAndChildren): Added. Helper function that allows both the
+        <use> and <symbol> element expanding functions to be shorter and share more code.
+        (WebCore::SVGUseElement::expandUseElementsInShadowTree): Removed unneeded checks
+        of cachedDocumentIsStillLoading. Used the new findTarget function, which handles
+        finding the target cross-document correctly. Removed the incorrect use of
+        referencedDocument when creating new elements and finding targets. Refactored
+        to use the new cloneDataAndChildren function and also moved the code that removes
+        the special attributes here, replacing the transferAttributesToShadowTreeReplacement
+        function. Made a few other simplifications.
+        (WebCore::SVGUseElement::expandSymbolElementsInShadowTree): Ditto, just like the
+        <use> changes only simpler.
+        (WebCore::SVGUseElement::transferEventListenersToShadowTree): Made this const.
+        Removed unneeded assertions.
+        (WebCore::SVGUseElement::invalidateShadowTree): Updated for name change.
+        (WebCore::SVGUseElement::invalidateDependentShadowTrees): Removed assertion.
+        (WebCore::SVGUseElement::transferAttributesToShadowTreeReplacement): Deleted.
+        (WebCore::SVGUseElement::selfHasRelativeLengths): Tweaked names.
+        (WebCore::SVGUseElement::notifyFinished): Removed the inDocument check, since
+        this function will only be called for elements that are in a document.
+        (WebCore::SVGUseElement::cachedDocumentIsStillLoading): Deleted.
+        (WebCore::SVGUseElement::finishParsingChildren): Removed the code that calls
+        buildPendingResource here. Shadow tree updating is driven solely by renderer
+        generation now.
+        (WebCore::SVGUseElement::updateExternalDocument): Replaced setCachedDocument
+        with this. This function knows how to load a different document if the URL
+        has changed, or leave it alone if not, and also stop the load if it should.
+        (WebCore::SVGUseElement::isValid): Moved this here from the header, since it's
+        always being called virtually.
+        (WebCore::SVGUseElement::haveLoadedRequiredResources): Ditto.
+        (WebCore::SVGUseElement::setHaveFiredLoadEvent): Ditto.
+        (WebCore::SVGUseElement::haveFiredLoadEvent): Ditto.
+        (WebCore::SVGUseElement::svgLoadEventTimer): Ditto.
+
+        * svg/SVGUseElement.h: Removed unneeded include. Moved the animated properties
+        to the top of the class because they are public DOM API and so are logical to
+        list first. I'd like to do that for other classes too over time. Changed to
+        derive privately from CachedSVGDocumentClient. Made the function
+        invalidateDependentShadowTrees private. Removed didNotifySubtreeInsertions,
+        isSupportedAttribute, clearResourceReferences, buildShadowTree,
+        transferAttributesToShadowTreeReplacement, isParserInserted, and
+        m_wasInsertedByParser. Added updateExternalDocument, cloneTarget, targetClone,
+        updateShadowTree, and clearShadowTree. Also did a couple other renames,
+        including renaming m_cachedDocument to m_externalDocument.
+
+        * svg/svgtags.in: Removed constructorNeedsCreatedByParser from the <use>
+        element since we don't have to handle constructing by the parser specially.
+
 2015-02-11  Dhi Aurrahman  <diorahman@rockybars.com>
 
         CSS selector JIT compilation support for :lang()
index 9c5a1e2fd237685be1bb50293b8ddc0372434582..36aef29be7582a4bdcf80fad7f1d9cbeb0c4c6f7 100644 (file)
@@ -27,8 +27,6 @@
 
 namespace WebCore {
 
-class CachedSVGDocument;
-
 class CachedSVGDocumentClient : public CachedResourceClient {
 public:
     virtual ~CachedSVGDocumentClient() { }
index 835d62339c878ff086016541465ab69bb4c50d18..a218826400490ff48fca40f687ec12af694078c6 100644 (file)
@@ -81,7 +81,6 @@
 #include "RuntimeApplicationChecks.h"
 #include "SVGDocument.h"
 #include "SVGNames.h"
-#include "SVGUseElement.h"
 #include "ScrollAnimator.h"
 #include "ScrollLatchingState.h"
 #include "Scrollbar.h"
index 0f0e1daba42f59465c50e00ebc93349b56de2d14..02703d3df9606c8cbbafb9a5ed500586c22fd8d5 100644 (file)
@@ -27,7 +27,6 @@
 #include "RenderView.h"
 #include "SVGNames.h"
 #include "SVGSVGElement.h"
-#include "SVGUseElement.h"
 
 namespace WebCore {
 
index 36de377b27039ba9c01db9a527a9e2290bae2dc9..5afd73a8a8f8ef8692bc4c1aa9d0015cade9a9de 100644 (file)
@@ -341,13 +341,6 @@ void SVGDocumentExtensions::rebuildElements()
 
 void SVGDocumentExtensions::clearTargetDependencies(SVGElement& referencedElement)
 {
-    if (referencedElement.isInShadowTree()) {
-        // The host element (e.g. <use>) of the shadow root will rebuild the shadow tree
-        // and all its references.
-        ASSERT(referencedElement.shadowRoot());
-        ASSERT(m_rebuildElements.contains(referencedElement.shadowRoot()->hostElement()));
-        return;
-    }
     auto it = m_elementDependencies.find(&referencedElement);
     if (it == m_elementDependencies.end())
         return;
index 8dcb10ca94c87eb55b97598694a5aeca5c2d1650..dcd2a6970e7677acb3f70b655580cd8e80a90fa0 100644 (file)
@@ -482,7 +482,6 @@ void SVGElement::cursorImageValueRemoved()
 
 SVGElement* SVGElement::correspondingElement() const
 {
-    ASSERT(!m_svgRareData || !m_svgRareData->correspondingElement() || correspondingUseElement());
     return m_svgRareData ? m_svgRareData->correspondingElement() : nullptr;
 }
 
@@ -966,26 +965,6 @@ String SVGElement::title() const
     // the document, not a tooltip) so we instantly return.
     if (isOutermostSVGSVGElement() && document().topDocument().isSVGDocument())
         return String();
-
-    // Walk up the tree, to find out whether we're inside a <use> shadow tree, to find the right title.
-    if (isInShadowTree()) {
-        Element* shadowHostElement = downcast<ShadowRoot>(treeScope().rootNode()).hostElement();
-        // At this time, SVG nodes are not allowed in non-<use> shadow trees, so any shadow root we do
-        // have should be a use. The assert and following test is here to catch future shadow DOM changes
-        // that do enable SVG in a shadow tree.
-        ASSERT(!shadowHostElement || shadowHostElement->hasTagName(SVGNames::useTag));
-        if (shadowHostElement && shadowHostElement->hasTagName(SVGNames::useTag)) {
-            SVGUseElement& useElement = downcast<SVGUseElement>(*shadowHostElement);
-
-            // If the <use> title is not empty we found the title to use.
-            String useTitle(useElement.title());
-            if (!useTitle.isEmpty())
-                return useTitle;
-        }
-    }
-
-    // If we aren't an instance in a <use> or the <use> title was not found, then find the first
-    // <title> child of this element.
     auto firstTitle = childrenOfType<SVGTitleElement>(*this).first();
     return firstTitle ? const_cast<SVGTitleElement*>(firstTitle)->innerText() : String();
 }
index bf7f94bc2e765b7231db89fd5ecbff2008775d5e..a21f9282c614a6fb79a4ebf70eda9e2aaea3e3aa 100644 (file)
@@ -49,6 +49,11 @@ Ref<SVGGElement> SVGGElement::create(const QualifiedName& tagName, Document& doc
     return adoptRef(*new SVGGElement(tagName, document));
 }
 
+Ref<SVGGElement> SVGGElement::create(Document& document)
+{
+    return create(SVGNames::gTag, document);
+}
+
 bool SVGGElement::isSupportedAttribute(const QualifiedName& attrName)
 {
     static NeverDestroyed<HashSet<QualifiedName>> supportedAttributes;
index cc1fc55f696aa3a1604311967b1fbabbcd9f4296..35ce10af552d3396496014597567fb2206911de2 100644 (file)
@@ -31,6 +31,7 @@ class SVGGElement final : public SVGGraphicsElement,
                           public SVGExternalResourcesRequired {
 public:
     static Ref<SVGGElement> create(const QualifiedName&, Document&);
+    static Ref<SVGGElement> create(Document&);
 
 private:
     SVGGElement(const QualifiedName&, Document&);
index c8d38d9eb8aeae1b0e7687ce1e4d8c3bf4d8bb11..7bc8c4221c031960f1fe994707945a8cf2692e00 100644 (file)
@@ -99,6 +99,11 @@ Ref<SVGSVGElement> SVGSVGElement::create(const QualifiedName& tagName, Document&
     return adoptRef(*new SVGSVGElement(tagName, document));
 }
 
+Ref<SVGSVGElement> SVGSVGElement::create(Document& document)
+{
+    return create(SVGNames::svgTag, document);
+}
+
 SVGSVGElement::~SVGSVGElement()
 {
     if (m_viewSpec)
index 67c2e45d8b279385290b97fa41d35e9eb8447632..8f9aed7381618362850b81142b22e0b3efb05d9a 100644 (file)
@@ -45,6 +45,7 @@ class SVGSVGElement final : public SVGGraphicsElement,
                             public SVGZoomAndPan {
 public:
     static Ref<SVGSVGElement> create(const QualifiedName&, Document&);
+    static Ref<SVGSVGElement> create(Document&);
 
     using SVGGraphicsElement::ref;
     using SVGGraphicsElement::deref;
index 5f320b7b5c042e271fda1a2ee60ca7354bf748e4..21c3da69f0990e4bf93e13c163df54f36fa4542c 100644 (file)
 #include "SVGUseElement.h"
 
 #include "CachedResourceLoader.h"
-#include "CachedResourceRequest.h"
 #include "CachedSVGDocument.h"
-#include "Document.h"
 #include "ElementIterator.h"
 #include "Event.h"
-#include "EventListener.h"
-#include "HTMLNames.h"
-#include "NodeRenderStyle.h"
-#include "RegisteredEventListener.h"
 #include "RenderSVGResource.h"
 #include "RenderSVGTransformableContainer.h"
 #include "ShadowRoot.h"
-#include "SVGElementRareData.h"
 #include "SVGGElement.h"
-#include "SVGLengthContext.h"
-#include "SVGNames.h"
-#include "SVGSMILElement.h"
 #include "SVGSVGElement.h"
 #include "SVGSymbolElement.h"
-#include "StyleResolver.h"
 #include "XLinkNames.h"
-#include "XMLDocumentParser.h"
-#include "XMLSerializer.h"
-#include <wtf/NeverDestroyed.h>
 
 namespace WebCore {
 
-// Animated property definitions
 DEFINE_ANIMATED_LENGTH(SVGUseElement, SVGNames::xAttr, X, x)
 DEFINE_ANIMATED_LENGTH(SVGUseElement, SVGNames::yAttr, Y, y)
 DEFINE_ANIMATED_LENGTH(SVGUseElement, SVGNames::widthAttr, Width, width)
@@ -72,15 +57,12 @@ BEGIN_REGISTER_ANIMATED_PROPERTIES(SVGUseElement)
     REGISTER_PARENT_ANIMATED_PROPERTIES(SVGGraphicsElement)
 END_REGISTER_ANIMATED_PROPERTIES
 
-inline SVGUseElement::SVGUseElement(const QualifiedName& tagName, Document& document, bool wasInsertedByParser)
+inline SVGUseElement::SVGUseElement(const QualifiedName& tagName, Document& document)
     : SVGGraphicsElement(tagName, document)
     , m_x(LengthModeWidth)
     , m_y(LengthModeHeight)
     , m_width(LengthModeWidth)
     , m_height(LengthModeHeight)
-    , m_wasInsertedByParser(wasInsertedByParser)
-    , m_haveFiredLoadEvent(false)
-    , m_needsShadowTreeRecreation(false)
     , m_svgLoadEventTimer(*this, &SVGElement::svgLoadEventTimerFired)
 {
     ASSERT(hasCustomStyleResolveCallbacks());
@@ -88,43 +70,22 @@ inline SVGUseElement::SVGUseElement(const QualifiedName& tagName, Document& docu
     registerAnimatedPropertiesForSVGUseElement();
 }
 
-Ref<SVGUseElement> SVGUseElement::create(const QualifiedName& tagName, Document& document, bool wasInsertedByParser)
+Ref<SVGUseElement> SVGUseElement::create(const QualifiedName& tagName, Document& document)
 {
-    // Always build a #shadow-root for SVGUseElement.
-    Ref<SVGUseElement> use = adoptRef(*new SVGUseElement(tagName, document, wasInsertedByParser));
-    use->ensureUserAgentShadowRoot();
-    return use;
+    return adoptRef(*new SVGUseElement(tagName, document));
 }
 
 SVGUseElement::~SVGUseElement()
 {
-    setCachedDocument(0);
-
-    clearResourceReferences();
-}
-
-bool SVGUseElement::isSupportedAttribute(const QualifiedName& attrName)
-{
-    static NeverDestroyed<HashSet<QualifiedName>> supportedAttributes;
-    if (supportedAttributes.get().isEmpty()) {
-        SVGLangSpace::addSupportedAttributes(supportedAttributes);
-        SVGExternalResourcesRequired::addSupportedAttributes(supportedAttributes);
-        SVGURIReference::addSupportedAttributes(supportedAttributes);
-        supportedAttributes.get().add(SVGNames::xAttr);
-        supportedAttributes.get().add(SVGNames::yAttr);
-        supportedAttributes.get().add(SVGNames::widthAttr);
-        supportedAttributes.get().add(SVGNames::heightAttr);
-    }
-    return supportedAttributes.get().contains<SVGAttributeHashTranslator>(attrName);
+    if (m_externalDocument)
+        m_externalDocument->removeClient(this);
 }
 
 void SVGUseElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
 {
     SVGParsingError parseError = NoError;
 
-    if (!isSupportedAttribute(name))
-        SVGGraphicsElement::parseAttribute(name, value);
-    else if (name == SVGNames::xAttr)
+    if (name == SVGNames::xAttr)
         setXBaseValue(SVGLength::construct(LengthModeWidth, value, parseError));
     else if (name == SVGNames::yAttr)
         setYBaseValue(SVGLength::construct(LengthModeHeight, value, parseError));
@@ -132,68 +93,39 @@ void SVGUseElement::parseAttribute(const QualifiedName& name, const AtomicString
         setWidthBaseValue(SVGLength::construct(LengthModeWidth, value, parseError, ForbidNegativeLengths));
     else if (name == SVGNames::heightAttr)
         setHeightBaseValue(SVGLength::construct(LengthModeHeight, value, parseError, ForbidNegativeLengths));
-    else if (SVGLangSpace::parseAttribute(name, value)
-             || SVGExternalResourcesRequired::parseAttribute(name, value)
-             || SVGURIReference::parseAttribute(name, value)) {
-    } else
-        ASSERT_NOT_REACHED();
 
     reportAttributeParsingError(parseError, name, value);
-}
 
-#if !ASSERT_DISABLED
-static inline bool isWellFormedDocument(Document& document)
-{
-    if (document.isSVGDocument() || document.isXHTMLDocument())
-        return static_cast<XMLDocumentParser*>(document.parser())->wellFormed();
-    return true;
+    SVGExternalResourcesRequired::parseAttribute(name, value);
+    SVGGraphicsElement::parseAttribute(name, value);
+    SVGLangSpace::parseAttribute(name, value);
+    SVGURIReference::parseAttribute(name, value);
 }
-#endif
 
 Node::InsertionNotificationRequest SVGUseElement::insertedInto(ContainerNode& rootParent)
 {
     SVGGraphicsElement::insertedInto(rootParent);
-    if (!rootParent.inDocument())
-        return InsertionDone;
-    ASSERT(!hasPendingResources() || !isWellFormedDocument(document()));
-    SVGExternalResourcesRequired::insertedIntoDocument(this);
-    if (!m_wasInsertedByParser)
-        return InsertionShouldCallDidNotifySubtreeInsertions;
+    if (inDocument()) {
+        SVGExternalResourcesRequired::insertedIntoDocument(this);
+        invalidateShadowTree();
+        updateExternalDocument();
+    }
     return InsertionDone;
 }
 
-void SVGUseElement::didNotifySubtreeInsertions(ContainerNode*)
-{
-    buildPendingResource();
-}
-
 void SVGUseElement::removedFrom(ContainerNode& rootParent)
 {
     SVGGraphicsElement::removedFrom(rootParent);
-    if (rootParent.inDocument())
-        clearResourceReferences();
+    clearShadowTree();
+    updateExternalDocument();
 }
 
-Document* SVGUseElement::referencedDocument() const
+inline Document* SVGUseElement::externalDocument() const
 {
-    if (!isExternalURIReference(href(), document()))
-        return &document();
-    return externalDocument();
+    return m_externalDocument ? m_externalDocument->document() : nullptr;
 }
 
-Document* SVGUseElement::externalDocument() const
-{
-    if (m_cachedDocument && m_cachedDocument->isLoaded()) {
-        // Gracefully handle error condition.
-        if (m_cachedDocument->errorOccurred())
-            return 0;
-        ASSERT(m_cachedDocument->document());
-        return m_cachedDocument->document();
-    }
-    return 0;
-}
-
-void SVGUseElement::transferSizeAttributesToShadowTreeTargetClone(SVGElement& shadowElement) const
+void SVGUseElement::transferSizeAttributesToTargetClone(SVGElement& shadowElement) const
 {
     // FIXME: The check for valueInSpecifiedUnits being non-zero below is a workaround for the fact
     // that we currently have no good way to tell whether a particular animatable attribute is a value
@@ -215,19 +147,14 @@ void SVGUseElement::transferSizeAttributesToShadowTreeTargetClone(SVGElement& sh
 
 void SVGUseElement::svgAttributeChanged(const QualifiedName& attrName)
 {
-    if (!isSupportedAttribute(attrName)) {
-        SVGGraphicsElement::svgAttributeChanged(attrName);
-        return;
-    }
-
     InstanceInvalidationGuard guard(*this);
 
     if (attrName == SVGNames::xAttr || attrName == SVGNames::yAttr || attrName == SVGNames::widthAttr || attrName == SVGNames::heightAttr) {
         updateRelativeLengthsInformation();
-        if (SVGElement* shadowTreeTargetClone = this->shadowTreeTargetClone()) {
-            // FIXME: It's unnecessarily inefficient to do this work any time we change "x" or "y".
+        if (attrName == SVGNames::widthAttr || attrName == SVGNames::heightAttr) {
             // FIXME: It's unnecessarily inefficient to update both width and height each time either is changed.
-            transferSizeAttributesToShadowTreeTargetClone(*shadowTreeTargetClone);
+            if (auto* targetClone = this->targetClone())
+                transferSizeAttributesToTargetClone(*targetClone);
         }
         if (auto* renderer = this->renderer())
             RenderSVGResource::markForLayoutAndParentResourceInvalidation(*renderer);
@@ -238,123 +165,96 @@ void SVGUseElement::svgAttributeChanged(const QualifiedName& attrName)
         return;
 
     if (SVGURIReference::isKnownAttribute(attrName)) {
-        bool isExternalReference = isExternalURIReference(href(), document());
-        if (isExternalReference) {
-            URL url = document().completeURL(href());
-            if (url.hasFragmentIdentifier()) {
-                CachedResourceRequest request(ResourceRequest(url.string()));
-                request.setInitiator(this);
-                setCachedDocument(document().cachedResourceLoader().requestSVGDocument(request));
-            }
-        } else
-            setCachedDocument(0);
-
-        if (!m_wasInsertedByParser)
-            buildPendingResource();
-
+        updateExternalDocument();
+        invalidateShadowTree();
         return;
     }
 
-    if (SVGLangSpace::isKnownAttribute(attrName)
-        || SVGExternalResourcesRequired::isKnownAttribute(attrName)) {
+    if (SVGLangSpace::isKnownAttribute(attrName) || SVGExternalResourcesRequired::isKnownAttribute(attrName)) {
         invalidateShadowTree();
         return;
     }
 
-    ASSERT_NOT_REACHED();
+    SVGGraphicsElement::svgAttributeChanged(attrName);
 }
 
 void SVGUseElement::willAttachRenderers()
 {
-    if (m_needsShadowTreeRecreation)
-        buildPendingResource();
+    if (m_shadowTreeNeedsUpdate)
+        updateShadowTree();
+    SVGGraphicsElement::willAttachRenderers();
 }
 
-static bool isDisallowedElement(const Element& element)
+static HashSet<AtomicString> createAllowedElementSet()
 {
     // Spec: "Any 'svg', 'symbol', 'g', graphics element or other 'use' is potentially a template object that can be re-used
     // (i.e., "instanced") in the SVG document via a 'use' element."
     // "Graphics Element" is defined as 'circle', 'ellipse', 'image', 'line', 'path', 'polygon', 'polyline', 'rect', 'text'
     // Excluded are anything that is used by reference or that only make sense to appear once in a document.
+    using namespace SVGNames;
+    HashSet<AtomicString> set;
+    for (auto& tag : { aTag, circleTag, descTag, ellipseTag, gTag, imageTag, lineTag, metadataTag, pathTag, polygonTag, polylineTag, rectTag, svgTag, switchTag, symbolTag, textTag, textPathTag, titleTag, trefTag, tspanTag, useTag })
+        set.add(tag.localName());
+    return set;
+}
 
-    if (!element.isSVGElement())
-        return true;
+static inline bool isDisallowedElement(const SVGElement& element)
+{
+    static NeverDestroyed<HashSet<AtomicString>> set = createAllowedElementSet();
+    return !set.get().contains(element.localName());
+}
 
-    static NeverDestroyed<HashSet<QualifiedName>> allowedElementTags;
-    if (allowedElementTags.get().isEmpty()) {
-        allowedElementTags.get().add(SVGNames::aTag);
-        allowedElementTags.get().add(SVGNames::circleTag);
-        allowedElementTags.get().add(SVGNames::descTag);
-        allowedElementTags.get().add(SVGNames::ellipseTag);
-        allowedElementTags.get().add(SVGNames::gTag);
-        allowedElementTags.get().add(SVGNames::imageTag);
-        allowedElementTags.get().add(SVGNames::lineTag);
-        allowedElementTags.get().add(SVGNames::metadataTag);
-        allowedElementTags.get().add(SVGNames::pathTag);
-        allowedElementTags.get().add(SVGNames::polygonTag);
-        allowedElementTags.get().add(SVGNames::polylineTag);
-        allowedElementTags.get().add(SVGNames::rectTag);
-        allowedElementTags.get().add(SVGNames::svgTag);
-        allowedElementTags.get().add(SVGNames::switchTag);
-        allowedElementTags.get().add(SVGNames::symbolTag);
-        allowedElementTags.get().add(SVGNames::textTag);
-        allowedElementTags.get().add(SVGNames::textPathTag);
-        allowedElementTags.get().add(SVGNames::titleTag);
-        allowedElementTags.get().add(SVGNames::trefTag);
-        allowedElementTags.get().add(SVGNames::tspanTag);
-        allowedElementTags.get().add(SVGNames::useTag);
-    }
-    return !allowedElementTags.get().contains<SVGAttributeHashTranslator>(element.tagQName());
+static inline bool isDisallowedElement(const Element& element)
+{
+    return !element.isSVGElement() || isDisallowedElement(downcast<SVGElement>(element));
 }
 
-void SVGUseElement::clearResourceReferences()
+void SVGUseElement::clearShadowTree()
 {
-    // FIXME: It's expensive to re-clone the entire tree every time. We should find a more efficient way to handle this.
-    if (ShadowRoot* root = userAgentShadowRoot())
+    if (auto* root = userAgentShadowRoot())
         root->removeChildren();
-    m_needsShadowTreeRecreation = false;
 }
 
 void SVGUseElement::buildPendingResource()
 {
-    if (isInShadowTree())
-        return;
-    if (!referencedDocument())
-        return;
-    clearResourceReferences();
-    if (!inDocument())
+    invalidateShadowTree();
+}
+
+void SVGUseElement::updateShadowTree()
+{
+    m_shadowTreeNeedsUpdate = false;
+
+    // FIXME: It's expensive to re-clone the entire tree every time. We should find a more efficient way to handle this.
+    clearShadowTree();
+
+    if (isInShadowTree() || !inDocument())
         return;
 
-    String id;
-    Element* target = SVGURIReference::targetElementFromIRIString(href(), document(), &id, externalDocument());
-    if (!isValidTarget(target)) {
-        if (externalDocument()) {
-            // We can't find the target in an external document, so just give up and don't try to do it again.
-            // We should not attempt to observe if an element with ID shows up in the external document later.
-            return;
-        }
-        referencedDocument()->accessSVGExtensions().addPendingResource(id, this);
+    String targetID;
+    auto* target = findTarget(&targetID);
+    if (!target) {
+        document().accessSVGExtensions().addPendingResource(targetID, this);
         return;
     }
 
-    buildShadowTree(downcast<SVGElement>(*target));
+    cloneTarget(ensureUserAgentShadowRoot(), *target);
     expandUseElementsInShadowTree();
     expandSymbolElementsInShadowTree();
-    transferSizeAttributesToShadowTreeTargetClone(*shadowTreeTargetClone());
     transferEventListenersToShadowTree();
+
     updateRelativeLengthsInformation();
 
     // When we invalidate the other shadow trees, it's important that we don't
     // follow any cycles and invalidate ourselves. To avoid that, we temporarily
-    // set m_needsShadowTreeRecreation to true so invalidateShadowTree will
+    // set m_shadowTreeNeedsUpdate to true so invalidateShadowTree will
     // quickly return and do nothing.
-    ASSERT(!m_needsShadowTreeRecreation);
-    m_needsShadowTreeRecreation = true;
+    ASSERT(!m_shadowTreeNeedsUpdate);
+    m_shadowTreeNeedsUpdate = true;
     invalidateDependentShadowTrees();
-    m_needsShadowTreeRecreation = false;
+    m_shadowTreeNeedsUpdate = false;
 }
 
-SVGElement* SVGUseElement::shadowTreeTargetClone() const
+SVGElement* SVGUseElement::targetClone() const
 {
     auto* root = userAgentShadowRoot();
     if (!root)
@@ -369,42 +269,45 @@ RenderPtr<RenderElement> SVGUseElement::createElementRenderer(Ref<RenderStyle>&&
 
 static bool isDirectReference(const SVGElement& element)
 {
-    return element.hasTagName(SVGNames::pathTag)
-        || element.hasTagName(SVGNames::rectTag)
-        || element.hasTagName(SVGNames::circleTag)
-        || element.hasTagName(SVGNames::ellipseTag)
-        || element.hasTagName(SVGNames::polygonTag)
-        || element.hasTagName(SVGNames::polylineTag)
-        || element.hasTagName(SVGNames::textTag);
+    using namespace SVGNames;
+    return element.hasTagName(circleTag)
+        || element.hasTagName(ellipseTag)
+        || element.hasTagName(pathTag)
+        || element.hasTagName(polygonTag)
+        || element.hasTagName(polylineTag)
+        || element.hasTagName(rectTag)
+        || element.hasTagName(textTag);
 }
 
 void SVGUseElement::toClipPath(Path& path)
 {
     ASSERT(path.isEmpty());
 
-    SVGElement* element = shadowTreeTargetClone();
-    if (is<SVGGraphicsElement>(element)) {
-        if (!isDirectReference(*element)) {
-            // Spec: Indirect references are an error (14.3.5)
-            document().accessSVGExtensions().reportError("Not allowed to use indirect reference in <clip-path>");
-        } else {
-            downcast<SVGGraphicsElement>(*element).toClipPath(path);
-            // FIXME: Avoid manual resolution of x/y here. Its potentially harmful.
-            SVGLengthContext lengthContext(this);
-            path.translate(FloatSize(x().value(lengthContext), y().value(lengthContext)));
-            path.transform(animatedLocalTransform());
-        }
+    auto* targetClone = this->targetClone();
+    if (!is<SVGGraphicsElement>(targetClone))
+        return;
+
+    if (!isDirectReference(*targetClone)) {
+        // Spec: Indirect references are an error (14.3.5)
+        document().accessSVGExtensions().reportError(ASCIILiteral("Not allowed to use indirect reference in <clip-path>"));
+        return;
     }
+
+    downcast<SVGGraphicsElement>(*targetClone).toClipPath(path);
+    SVGLengthContext lengthContext(this);
+    // FIXME: Find a way to do this without manual resolution of x/y here. It's potentially incorrect.
+    path.translate(FloatSize(x().value(lengthContext), y().value(lengthContext)));
+    path.transform(animatedLocalTransform());
 }
 
 RenderElement* SVGUseElement::rendererClipChild() const
 {
-    auto* element = shadowTreeTargetClone();
-    if (!element)
+    auto* targetClone = this->targetClone();
+    if (!targetClone)
         return nullptr;
-    if (!isDirectReference(*element))
+    if (!isDirectReference(*targetClone))
         return nullptr;
-    return element->renderer();
+    return targetClone->renderer();
 }
 
 static void removeDisallowedElementsFromSubtree(SVGElement& subtree)
@@ -419,8 +322,7 @@ static void removeDisallowedElementsFromSubtree(SVGElement& subtree)
 
     Vector<Element*> disallowedElements;
     auto descendants = descendantsOfType<Element>(subtree);
-    auto end = descendants.end();
-    for (auto it = descendants.begin(); it != end; ) {
+    for (auto it = descendants.begin(), end = descendants.end(); it != end; ) {
         if (isDisallowedElement(*it)) {
             disallowedElements.append(&*it);
             it.traverseNextSkippingChildren();
@@ -428,7 +330,7 @@ static void removeDisallowedElementsFromSubtree(SVGElement& subtree)
         }
         ++it;
     }
-    for (Element* element : disallowedElements)
+    for (auto* element : disallowedElements)
         element->parentNode()->removeChild(element);
 }
 
@@ -447,7 +349,7 @@ static void associateClonesWithOriginals(SVGElement& clone, SVGElement& original
 
 static void associateReplacementCloneWithOriginal(SVGElement& replacementClone, SVGElement& originalClone)
 {
-    SVGElement* correspondingElement = originalClone.correspondingElement();
+    auto* correspondingElement = originalClone.correspondingElement();
     ASSERT(correspondingElement);
     originalClone.setCorrespondingElement(nullptr);
     replacementClone.setCorrespondingElement(correspondingElement);
@@ -466,91 +368,96 @@ static void associateReplacementClonesWithOriginals(SVGElement& replacementClone
         associateReplacementCloneWithOriginal(pair.first, pair.second);
 }
 
-void SVGUseElement::buildShadowTree(SVGElement& target)
+SVGElement* SVGUseElement::findTarget(String* targetID) const
 {
-    Ref<SVGElement> clonedTarget = static_pointer_cast<SVGElement>(target.cloneElementWithChildren(document())).releaseNonNull();
-    associateClonesWithOriginals(clonedTarget.get(), target);
-    removeDisallowedElementsFromSubtree(clonedTarget.get());
-    ensureUserAgentShadowRoot().appendChild(WTF::move(clonedTarget));
+    auto* correspondingElement = this->correspondingElement();
+    auto& original = correspondingElement ? downcast<SVGUseElement>(*correspondingElement) : *this;
+
+    auto* targetCandidate = targetElementFromIRIString(original.href(), original.document(), targetID, original.externalDocument());
+    if (targetID && !targetID->isNull()) {
+        // If the reference is external, don't return the target ID to the caller.
+        // The caller would use the target ID to wait for a pending resource on the wrong document.
+        // If we ever want the change that and let the caller to wait on the external document,
+        // we should change this function so it returns the appropriate document to go with the ID.
+        if (isExternalURIReference(original.href(), original.document()))
+            *targetID = String();
+    }
+    if (!is<SVGElement>(targetCandidate))
+        return nullptr;
+    auto& target = downcast<SVGElement>(*targetCandidate);
+
+    if (!target.inDocument() || isDisallowedElement(target))
+        return nullptr;
+
+    // Reject any target that has already been cloned to create one of the ancestors of this element,
+    // already in the shadow tree. This is sufficient to prevent cycles.
+    if (correspondingElement) {
+        for (auto& ancestor : lineageOfType<SVGElement>(*this)) {
+            if (ancestor.correspondingElement() == &target)
+                return nullptr;
+        }
+    }
+
+    return &target;
 }
 
-bool SVGUseElement::isValidTarget(Element* target) const
+void SVGUseElement::cloneTarget(ContainerNode& container, SVGElement& target) const
 {
-    if (!is<SVGElement>(target))
-        return false;
-    if (!target->inDocument())
-        return false;
-    SVGElement& castedTarget = downcast<SVGElement>(*target);
-    if (&castedTarget == this)
-        return false;
-    if (isDisallowedElement(castedTarget))
-        return false;
-    // Reject any target that would create a cycle.
-    for (auto& ancestor : lineageOfType<SVGElement>(*this)) {
-        if (ancestor.correspondingElement() == &castedTarget)
-            return false;
-    }
-    return true;
+    Ref<SVGElement> targetClone = static_pointer_cast<SVGElement>(target.cloneElementWithChildren(document())).releaseNonNull();
+    associateClonesWithOriginals(targetClone.get(), target);
+    removeDisallowedElementsFromSubtree(targetClone.get());
+    transferSizeAttributesToTargetClone(targetClone.get());
+    container.appendChild(WTF::move(targetClone));
 }
 
-void SVGUseElement::expandUseElementsInShadowTree()
+static void cloneDataAndChildren(SVGElement& replacementClone, SVGElement& originalClone)
 {
-    // FIXME: Combine this with buildShadowTree.
+    // This assertion checks that we don't call this with the arguments backwards.
+    // The replacement clone is new and so it's not installed in a parent yet.
+    ASSERT(!replacementClone.parentNode());
 
-    if (cachedDocumentIsStillLoading())
-        return;
+    replacementClone.cloneDataFromElement(originalClone);
+    originalClone.cloneChildNodes(&replacementClone);
+    associateReplacementClonesWithOriginals(replacementClone, originalClone);
+    removeDisallowedElementsFromSubtree(replacementClone);
+}
 
+void SVGUseElement::expandUseElementsInShadowTree() const
+{
     auto descendants = descendantsOfType<SVGUseElement>(*userAgentShadowRoot());
-    auto end = descendants.end();
-    for (auto it = descendants.begin(); it != end; ) {
-        Ref<SVGUseElement> original = *it;
+    for (auto it = descendants.begin(), end = descendants.end(); it != end; ) {
+        SVGUseElement& originalClone = *it;
         it = end; // Efficiently quiets assertions due to the outstanding iterator.
 
-        if (original->cachedDocumentIsStillLoading())
-            return;
+        auto* target = originalClone.findTarget();
 
         // Spec: In the generated content, the 'use' will be replaced by 'g', where all attributes from the
         // 'use' element except for x, y, width, height and xlink:href are transferred to the generated 'g' element.
 
-        // FIXME: Is it right to use referencedDocument() here instead of just document()?
-        // Can a shadow tree within this document really contain elements that are in a
-        // different document?
-        ASSERT(referencedDocument());
-        auto replacement = SVGGElement::create(SVGNames::gTag, *referencedDocument());
-        original->transferAttributesToShadowTreeReplacement(replacement.get());
-        original->cloneChildNodes(replacement.ptr());
-        associateReplacementClonesWithOriginals(replacement.get(), original.get());
-
-        RefPtr<SVGElement> clonedTarget;
-        Element* targetCandidate = SVGURIReference::targetElementFromIRIString(original->href(), *referencedDocument());
-        if (original->isValidTarget(targetCandidate)) {
-            SVGElement& originalTarget = downcast<SVGElement>(*targetCandidate);
-            clonedTarget = static_pointer_cast<SVGElement>(originalTarget.cloneElementWithChildren(document()));
-            associateClonesWithOriginals(*clonedTarget, originalTarget);
-            replacement->appendChild(clonedTarget);
-        }
+        auto replacementClone = SVGGElement::create(document());
+        cloneDataAndChildren(replacementClone.get(), originalClone);
 
-        removeDisallowedElementsFromSubtree(replacement.get());
+        replacementClone->removeAttribute(SVGNames::xAttr);
+        replacementClone->removeAttribute(SVGNames::yAttr);
+        replacementClone->removeAttribute(SVGNames::widthAttr);
+        replacementClone->removeAttribute(SVGNames::heightAttr);
+        replacementClone->removeAttribute(XLinkNames::hrefAttr);
 
-        // Replace <use> with the <g> element we created.
-        original->parentNode()->replaceChild(replacement.ptr(), original.ptr());
+        if (target)
+            originalClone.cloneTarget(replacementClone.get(), *target);
 
-        // Call transferSizeAttributesToShadowTreeTargetClone after putting the cloned elements into the
-        // shadow tree so it can use SVGElement::correspondingElement without triggering an assertion.
-        if (clonedTarget)
-            original->transferSizeAttributesToShadowTreeTargetClone(*clonedTarget);
+        originalClone.parentNode()->replaceChild(replacementClone.ptr(), &originalClone);
 
-        // Continue iterating from the <g> element since the <use> element was replaced.
-        it = descendants.from(replacement.get());
+        // Resume iterating, starting just inside the replacement clone.
+        it = descendants.from(replacementClone.get());
     }
 }
 
-void SVGUseElement::expandSymbolElementsInShadowTree()
+void SVGUseElement::expandSymbolElementsInShadowTree() const
 {
     auto descendants = descendantsOfType<SVGSymbolElement>(*userAgentShadowRoot());
-    auto end = descendants.end();
-    for (auto it = descendants.begin(); it != end; ) {
-        SVGSymbolElement& original = *it;
+    for (auto it = descendants.begin(), end = descendants.end(); it != end; ) {
+        SVGSymbolElement& originalClone = *it;
         it = end; // Efficiently quiets assertions due to the outstanding iterator.
 
         // Spec: The referenced 'symbol' and its contents are deep-cloned into the generated tree,
@@ -560,30 +467,19 @@ void SVGUseElement::expandSymbolElementsInShadowTree()
         // the generated 'svg'. If attributes width and/or height are not specified, the generated
         // 'svg' element will use values of 100% for these attributes.
 
-        // FIXME: Is it right to use referencedDocument() here instead of just document()?
-        // Can a shadow tree within this document really contain elements that are in a
-        // different document?
-        ASSERT(referencedDocument());
-        auto replacement = SVGSVGElement::create(SVGNames::svgTag, *referencedDocument());
-        replacement->cloneDataFromElement(original);
-        original.cloneChildNodes(replacement.ptr());
-        associateReplacementClonesWithOriginals(replacement.get(), original);
-
-        removeDisallowedElementsFromSubtree(replacement.get());
+        auto replacementClone = SVGSVGElement::create(document());
+        cloneDataAndChildren(replacementClone.get(), originalClone);
 
-        // Replace <symbol> with the <svg> element we created.
-        original.parentNode()->replaceChild(replacement.ptr(), &original);
+        originalClone.parentNode()->replaceChild(replacementClone.ptr(), &originalClone);
 
-        // Continue iterating from the <svg> element since the <symbol> element was replaced.
-        it = descendants.from(replacement.get());
+        // Resume iterating, starting just inside the replacement clone.
+        it = descendants.from(replacementClone.get());
     }
 }
 
-void SVGUseElement::transferEventListenersToShadowTree()
+void SVGUseElement::transferEventListenersToShadowTree() const
 {
-    ASSERT(userAgentShadowRoot());
     for (auto& descendant : descendantsOfType<SVGElement>(*userAgentShadowRoot())) {
-        ASSERT(descendant.correspondingElement());
         if (EventTargetData* data = descendant.correspondingElement()->eventTargetData())
             data->eventListenerMap.copyEventListenersNotCreatedFromMarkupToTarget(&descendant);
     }
@@ -591,9 +487,9 @@ void SVGUseElement::transferEventListenersToShadowTree()
 
 void SVGUseElement::invalidateShadowTree()
 {
-    if (m_needsShadowTreeRecreation)
+    if (m_shadowTreeNeedsUpdate)
         return;
-    m_needsShadowTreeRecreation = true;
+    m_shadowTreeNeedsUpdate = true;
     setNeedsStyleRecalc(ReconstructRenderTree);
     invalidateDependentShadowTrees();
 }
@@ -601,38 +497,22 @@ void SVGUseElement::invalidateShadowTree()
 void SVGUseElement::invalidateDependentShadowTrees()
 {
     for (auto* instance : instances()) {
-        if (SVGUseElement* element = instance->correspondingUseElement()) {
-            ASSERT(element->inDocument());
+        if (auto* element = instance->correspondingUseElement())
             element->invalidateShadowTree();
-        }
     }
 }
 
-void SVGUseElement::transferAttributesToShadowTreeReplacement(SVGGElement& replacement) const
-{
-    replacement.cloneDataFromElement(*this);
-
-    replacement.removeAttribute(SVGNames::xAttr);
-    replacement.removeAttribute(SVGNames::yAttr);
-    replacement.removeAttribute(SVGNames::widthAttr);
-    replacement.removeAttribute(SVGNames::heightAttr);
-    replacement.removeAttribute(XLinkNames::hrefAttr);
-}
-
 bool SVGUseElement::selfHasRelativeLengths() const
 {
     if (x().isRelative() || y().isRelative() || width().isRelative() || height().isRelative())
         return true;
 
-    auto* target = shadowTreeTargetClone();
-    return target && target->hasRelativeLengths();
+    auto* targetClone = this->targetClone();
+    return targetClone && targetClone->hasRelativeLengths();
 }
 
 void SVGUseElement::notifyFinished(CachedResource* resource)
 {
-    if (!inDocument())
-        return;
-
     invalidateShadowTree();
     if (resource->errorOccurred())
         dispatchEvent(Event::create(eventNames().errorEvent, false, false));
@@ -640,37 +520,66 @@ void SVGUseElement::notifyFinished(CachedResource* resource)
         SVGExternalResourcesRequired::dispatchLoadEvent(this);
 }
 
-bool SVGUseElement::cachedDocumentIsStillLoading()
-{
-    if (m_cachedDocument && m_cachedDocument->isLoading())
-        return true;
-    return false;
-}
-
 void SVGUseElement::finishParsingChildren()
 {
     SVGGraphicsElement::finishParsingChildren();
     SVGExternalResourcesRequired::finishParsingChildren();
-    if (m_wasInsertedByParser) {
-        buildPendingResource();
-        m_wasInsertedByParser = false;
-    }
 }
 
-void SVGUseElement::setCachedDocument(CachedResourceHandle<CachedSVGDocument> cachedDocument)
+void SVGUseElement::updateExternalDocument()
 {
-    if (m_cachedDocument == cachedDocument)
-        return;
+    URL externalDocumentURL;
+    if (inDocument() && isExternalURIReference(href(), document())) {
+        externalDocumentURL = document().completeURL(href());
+        if (!externalDocumentURL.hasFragmentIdentifier())
+            externalDocumentURL = URL();
+    }
 
-    if (m_cachedDocument)
-        m_cachedDocument->removeClient(this);
+    if (externalDocumentURL == (m_externalDocument ? m_externalDocument->url() : URL()))
+        return;
 
-    m_cachedDocument = cachedDocument;
-    if (m_cachedDocument) {
-        // We don't need the SVG document to create a new frame because the new document belongs to the parent UseElement.
-        m_cachedDocument->setShouldCreateFrameForDocument(false);
-        m_cachedDocument->addClient(this);
+    if (m_externalDocument)
+        m_externalDocument->removeClient(this);
+
+    if (externalDocumentURL.isNull())
+        m_externalDocument = nullptr;
+    else {
+        CachedResourceRequest request { ResourceRequest { externalDocumentURL } };
+        request.setInitiator(this);
+        m_externalDocument = document().cachedResourceLoader().requestSVGDocument(request);
+        if (m_externalDocument) {
+            // FIXME: Is it really OK for us to set this to false for a document that might be shared by another client?
+            m_externalDocument->setShouldCreateFrameForDocument(false); // No frame needed, we just want the elements.
+            m_externalDocument->addClient(this);
+        }
     }
+
+    invalidateShadowTree();
+}
+
+bool SVGUseElement::isValid() const
+{
+    return SVGTests::isValid();
+}
+
+bool SVGUseElement::haveLoadedRequiredResources()
+{
+    return SVGExternalResourcesRequired::haveLoadedRequiredResources();
+}
+
+void SVGUseElement::setHaveFiredLoadEvent(bool haveFiredLoadEvent)
+{
+    m_haveFiredLoadEvent = haveFiredLoadEvent;
+}
+
+bool SVGUseElement::haveFiredLoadEvent() const
+{
+    return m_haveFiredLoadEvent;
+}
+
+Timer* SVGUseElement::svgLoadEventTimer()
+{
+    return &m_svgLoadEventTimer;
 }
 
 }
index 383403a91559af0aa8b6babee025206ac782f9ad..4773923c58b1b2ecb37f1cc9eca58364d86456c2 100644 (file)
@@ -28,7 +28,6 @@
 #include "SVGAnimatedLength.h"
 #include "SVGExternalResourcesRequired.h"
 #include "SVGGraphicsElement.h"
-#include "SVGNames.h"
 #include "SVGURIReference.h"
 
 namespace WebCore {
@@ -36,82 +35,65 @@ namespace WebCore {
 class CachedSVGDocument;
 class SVGGElement;
 
-class SVGUseElement final : public SVGGraphicsElement,
-                            public SVGExternalResourcesRequired,
-                            public SVGURIReference,
-                            public CachedSVGDocumentClient {
+class SVGUseElement final : public SVGGraphicsElement, public SVGExternalResourcesRequired, public SVGURIReference, private CachedSVGDocumentClient {
+
+    BEGIN_DECLARE_ANIMATED_PROPERTIES(SVGUseElement)
+        DECLARE_ANIMATED_LENGTH(X, x)
+        DECLARE_ANIMATED_LENGTH(Y, y)
+        DECLARE_ANIMATED_LENGTH(Width, width)
+        DECLARE_ANIMATED_LENGTH(Height, height)
+        DECLARE_ANIMATED_STRING(Href, href)
+        DECLARE_ANIMATED_BOOLEAN(ExternalResourcesRequired, externalResourcesRequired)
+    END_DECLARE_ANIMATED_PROPERTIES
+
 public:
-    static Ref<SVGUseElement> create(const QualifiedName&, Document&, bool wasInsertedByParser);
+    static Ref<SVGUseElement> create(const QualifiedName&, Document&);
     virtual ~SVGUseElement();
 
     void invalidateShadowTree();
-    void invalidateDependentShadowTrees();
 
     RenderElement* rendererClipChild() const;
 
-protected:
-    virtual void didNotifySubtreeInsertions(ContainerNode*) override;
-
 private:
-    SVGUseElement(const QualifiedName&, Document&, bool wasInsertedByParser);
-
-    virtual bool isValid() const override { return SVGTests::isValid(); }
+    SVGUseElement(const QualifiedName&, Document&);
 
+    virtual bool isValid() const override;
     virtual InsertionNotificationRequest insertedInto(ContainerNode&) override;
     virtual void removedFrom(ContainerNode&) override;
     virtual void buildPendingResource() override;
-
-    bool isSupportedAttribute(const QualifiedName&);
     virtual void parseAttribute(const QualifiedName&, const AtomicString&) override;
     virtual void svgAttributeChanged(const QualifiedName&) override;
-
     virtual void willAttachRenderers() override;
-
     virtual RenderPtr<RenderElement> createElementRenderer(Ref<RenderStyle>&&) override;
     virtual void toClipPath(Path&) override;
+    virtual bool haveLoadedRequiredResources() override;
+    virtual void finishParsingChildren() override;
+    virtual bool selfHasRelativeLengths() const override;
+    virtual void setHaveFiredLoadEvent(bool) override;
+    virtual bool haveFiredLoadEvent() const override;
+    virtual Timer* svgLoadEventTimer() override;
+    virtual void notifyFinished(CachedResource*) override;
 
-    void clearResourceReferences();
+    Document* externalDocument() const;
+    void updateExternalDocument();
 
-    virtual bool haveLoadedRequiredResources() override { return SVGExternalResourcesRequired::haveLoadedRequiredResources(); }
+    SVGElement* findTarget(String* targetID = nullptr) const;
 
-    virtual void finishParsingChildren() override;
-    virtual bool selfHasRelativeLengths() const override;
+    void cloneTarget(ContainerNode&, SVGElement& target) const;
+    SVGElement* targetClone() const;
 
-    // Shadow tree handling.
-    void buildShadowTree(SVGElement& target);
-    void expandUseElementsInShadowTree();
-    void expandSymbolElementsInShadowTree();
-    SVGElement* shadowTreeTargetClone() const;
-    void transferEventListenersToShadowTree();
-    void transferAttributesToShadowTreeReplacement(SVGGElement&) const;
-    void transferSizeAttributesToShadowTreeTargetClone(SVGElement&) const;
-    bool isValidTarget(Element*) const;
+    void updateShadowTree();
+    void expandUseElementsInShadowTree() const;
+    void expandSymbolElementsInShadowTree() const;
+    void transferEventListenersToShadowTree() const;
+    void transferSizeAttributesToTargetClone(SVGElement&) const;
 
-    BEGIN_DECLARE_ANIMATED_PROPERTIES(SVGUseElement)
-        DECLARE_ANIMATED_LENGTH(X, x)
-        DECLARE_ANIMATED_LENGTH(Y, y)
-        DECLARE_ANIMATED_LENGTH(Width, width)
-        DECLARE_ANIMATED_LENGTH(Height, height)
-        DECLARE_ANIMATED_STRING(Href, href)
-        DECLARE_ANIMATED_BOOLEAN(ExternalResourcesRequired, externalResourcesRequired)
-    END_DECLARE_ANIMATED_PROPERTIES
+    void clearShadowTree();
+    void invalidateDependentShadowTrees();
 
-    bool cachedDocumentIsStillLoading();
-    Document* externalDocument() const;
-    virtual void notifyFinished(CachedResource*) override;
-    Document* referencedDocument() const;
-    void setCachedDocument(CachedResourceHandle<CachedSVGDocument>);
-
-    // SVGExternalResourcesRequired
-    virtual void setHaveFiredLoadEvent(bool haveFiredLoadEvent) override { m_haveFiredLoadEvent = haveFiredLoadEvent; }
-    virtual bool isParserInserted() const override { return m_wasInsertedByParser; }
-    virtual bool haveFiredLoadEvent() const override { return m_haveFiredLoadEvent; }
-    virtual Timer* svgLoadEventTimer() override { return &m_svgLoadEventTimer; }
-
-    bool m_wasInsertedByParser;
-    bool m_haveFiredLoadEvent;
-    bool m_needsShadowTreeRecreation;
-    CachedResourceHandle<CachedSVGDocument> m_cachedDocument;
+    bool m_haveFiredLoadEvent { false };
+    bool m_shadowTreeNeedsUpdate { true };
+    CachedResourceHandle<CachedSVGDocument> m_externalDocument;
     Timer m_svgLoadEventTimer;
 };
 
index efa5f5098980ce312f8846112346e7ece20f552e..6c3c04d86c07a30345159d26e377b3283e4d2218 100644 (file)
@@ -91,7 +91,7 @@ textPath
 title
 tref interfaceName=SVGTRefElement
 tspan interfaceName=SVGTSpanElement
-use constructorNeedsCreatedByParser
+use
 view
 #if ENABLE_SVG_FONTS
 vkern interfaceName=SVGVKernElement