Changeset 53446 in webkit


Ignore:
Timestamp:
Jan 18, 2010 6:17:28 PM (14 years ago)
Author:
Nikolas Zimmermann
Message:

2010-01-18 Nikolas Zimmermann <nzimmermann@rim.com>

Reviewed by Dirk Schulze.

Rewrite SVG <use> support in a modern-fashion
https://bugs.webkit.org/show_bug.cgi?id=33776

Tests: svg/custom/relative-sized-deep-shadow-tree-content.xhtml

svg/custom/relative-sized-shadow-tree-content.xhtml

Fixes: svg/W3C-SVG-1.1/animate-elem-30-t.svg (animated circle sometimes takes wrong path)

Rewrite <use> support in less intrusive way. Try hard to avoid recloning where possible, and do it lazily.
Introduce RenderSVGShadowTreeRootContainer as special renderer for SVGUseElement, that now manages the
render tree, instead of SVGUseElement manually hacking around it's own renderer from the DOM side.

Instead of recloning the whole shadow tree for every attribute change (DOM setAttribute / SVG DOM changes / CSS changes / childrenChanged()...)
just notify the RenderSVGShadowTreeRootContainer that it's supposed to reclone the tree upon the next updateFromElement() call.

updateFromElement() is fired from SVGUseElement::attach() / recalcStyle(), as it's done for HTMLFormControlElement/HTMLMediaElement, thus
lazily recloning the shadow tree if necessary.

Animations for <use> elements was a real performance bottlenck as the tree got recloned on every attribute change. Reclones are _completly_
avoided for animations now - the SVGAnim*Element classes already updated the instances of an element manually, though that resulted in a reclone
nontheless, and thus killing performance. <use> elements can only be recloned through mutations of the elements that they reference to.
For example referencing a <rect> element from a <use> element and scripting the <rect> element (setAttribute, or child tree mutations etc.).
We reclone instead of trying to synchronize trees - as it's currenty implemented - because it's very hard to do it right.

Any DOM / SVG DOM / CSS change on the <use> element don't reclone the tree anymore, this is a huge speed benefit.
x/y attribute changes are correctly handled in the render tree now (by an additional local transformation), now percentual values work
as expected, and resize on window changes - affecting lots of testcases.

The <use> implementation is much safer now, not doing any mutations synchronously from svgAttributeChanged etc.
Remove hack to force garbage collection on SVGElementInstance destruction - can't reproduce it anymore.

  • Android.mk: Add new files to build.
  • GNUmakefile.am: Ditto.
  • WebCore.gypi: Ditto.
  • WebCore.pro: Ditto.
  • WebCore.vcproj/WebCore.vcproj: Ditto.
  • WebCore.xcodeproj/project.pbxproj: Ditto.
  • rendering/RenderSVGShadowTreeRootContainer.cpp: Added. This is the rendered now created by SVGUseElement. (WebCore::RenderSVGShadowTreeRootContainer::RenderSVGShadowTreeRootContainer): (WebCore::RenderSVGShadowTreeRootContainer::~RenderSVGShadowTreeRootContainer): (WebCore::RenderSVGShadowTreeRootContainer::updateStyle): Used form SVGUseElement to request style recalculations for the shadow tree renderers (WebCore::RenderSVGShadowTreeRootContainer::updateFromElement): Used from SVGUseElement attach/recalcStyle to eventually request shadow tree updates. (WebCore::RenderSVGShadowTreeRootContainer::styleDidChange): Used to propage style updates across shadow tree boundaries.
  • rendering/RenderSVGShadowTreeRootContainer.h: Added. (WebCore::RenderSVGShadowTreeRootContainer::markShadowTreeForRecreation): Marks the shadow tree for a reclone, next time updateFromElement is used.
  • rendering/RenderSVGTransformableContainer.cpp: (WebCore::RenderSVGTransformableContainer::calculateLocalTransform): Take containerTranslation() into account, supplied by RenderSVGSDhadowTreeContainer.
  • rendering/SVGShadowTreeElements.cpp: Added. This is the root element of the SVG shadow tree residing as (hidden) child of SVGUseElement (DOM wise). (WebCore::SVGShadowTreeContainerElement::SVGShadowTreeContainerElement): (WebCore::SVGShadowTreeContainerElement::~SVGShadowTreeContainerElement): (WebCore::SVGShadowTreeContainerElement::containerTranslation): Used from calculateLocalTransform() to take x/y translation into account for shadow tree container elements. (WebCore::SVGShadowTreeRootElement::SVGShadowTreeRootElement): (WebCore::SVGShadowTreeRootElement::~SVGShadowTreeRootElement): (WebCore::SVGShadowTreeRootElement::attachElement): Used by RenderSVGShadowTreeRootContainer, instead of attach(), as we're a shadow tree root node.
  • rendering/SVGShadowTreeElements.h: Added. This is the root element of each SVG shadow sub-tree (whenever a <use> element is expanded in the shadow tree). (WebCore::SVGShadowTreeContainerElement::isShadowTreeContainerElement): Return true here. (WebCore::SVGShadowTreeContainerElement::setContainerOffset): Used from SVGUseElement to propagate x/y translation values set on <use> elements in the shadow tree. (WebCore::SVGShadowTreeRootElement::isShadowNode): Identify us as shadow node. (WebCore::SVGShadowTreeRootElement::shadowParentNode): Ditto. Return actual shadow parent node (== corresponding use element).
  • svg/SVGElement.cpp: Shrink size of all SVG*Elements, by removing the m_shadowParent parent. SVGShadowTreeRootElement is the new base class for shadow tree. (WebCore::SVGElement::SVGElement): (WebCore::SVGElement::eventParentNode): Call virtual shadowParentNode() method, instead of accessing m_shadowParent.
  • svg/SVGElement.h: Remove isShadowNode() / shadowParentNode() / setShadowParentNode().
  • svg/SVGElementInstance.cpp: Remove the hack, calling garbage collection before destruction. Can't reproduce this anymore, let's see what the bots say. (WebCore::SVGElementInstance::SVGElementInstance): Remove now unnecessary m_needsUpdate flag. (WebCore::SVGElementInstance::invalidateAllInstancesOfElement): Don't invalidate if instance updates are blocked (see SVGStyledElement changes)
  • svg/SVGElementInstance.h: Remove m_needsUpdate, and forgetWrapper() method.
  • svg/SVGGElement.h: (WebCore::SVGGElement::isShadowTreeContainerElement): Add new virtual method here returning false by default, SVGShadowTreeContainerElement will override it.
  • svg/SVGStyledElement.cpp: Remove gElementsWithInstanceUpdatesBlocked HashSet tracking the state of instancesUpdatesBlocked() per SVGStyledElement - make it a member variable.
  • svg/SVGStyledElement.h: Add inline getter/setters around m_instanceUpdatesBlocked. (WebCore::SVGStyledElement::instanceUpdatesBlocked): (WebCore::SVGStyledElement::setInstanceUpdatesBlocked):
  • svg/SVGUseElement.cpp: Full rewrite of <use> support, a detailed discussion would blow the ChangeLog - see short version above. (WebCore::SVGUseElement::SVGUseElement): (WebCore::SVGUseElement::instanceRoot): (WebCore::SVGUseElement::insertedIntoDocument): (WebCore::SVGUseElement::removedFromDocument): (WebCore::SVGUseElement::svgAttributeChanged): (WebCore::updateContainerOffset): (WebCore::SVGUseElement::updateContainerOffsets): (WebCore::SVGUseElement::recalcStyle): (WebCore::dumpInstanceTree): (WebCore::SVGUseElement::buildPendingResource): (WebCore::SVGUseElement::buildShadowAndInstanceTree): (WebCore::SVGUseElement::createRenderer): (WebCore::updateFromElementCallback): (WebCore::SVGUseElement::attach): (WebCore::SVGUseElement::detach): (WebCore::SVGUseElement::toClipPath): (WebCore::SVGUseElement::buildInstanceTree): (WebCore::SVGUseElement::handleDeepUseReferencing): (WebCore::SVGUseElement::buildShadowTree): (WebCore::SVGUseElement::expandUseElementsInShadowTree): (WebCore::SVGUseElement::expandSymbolElementsInShadowTree): (WebCore::SVGUseElement::instanceForShadowTreeElement): (WebCore::SVGUseElement::invalidateShadowTree): (WebCore::SVGUseElement::transferUseAttributesToReplacedElement):
  • svg/SVGUseElement.h: (WebCore::SVGUseElement::isPendingResource):

2010-01-18 Nikolas Zimmermann <nzimmermann@rim.com>

Reviewed by Dirk Schulze.

Rewrite SVG <use> support in a modern-fashion
https://bugs.webkit.org/show_bug.cgi?id=33776

Update some test results, after rewriting <use> support.

  • platform/mac/svg/W3C-SVG-1.1/animate-elem-40-t-expected.txt:
  • platform/mac/svg/custom/relative-sized-deep-shadow-tree-content-expected.checksum: Added.
  • platform/mac/svg/custom/relative-sized-deep-shadow-tree-content-expected.png: Added.
  • platform/mac/svg/custom/relative-sized-deep-shadow-tree-content-expected.txt: Added.
  • platform/mac/svg/custom/relative-sized-shadow-tree-content-expected.checksum: Added.
  • platform/mac/svg/custom/relative-sized-shadow-tree-content-expected.png: Added.
  • platform/mac/svg/custom/relative-sized-shadow-tree-content-expected.txt: Added.
  • platform/mac/svg/custom/use-events-crash-expected.txt:
  • platform/mac/svg/custom/use-on-disallowed-foreign-object-1-expected.txt:
  • platform/mac/svg/custom/use-on-disallowed-foreign-object-3-expected.txt:
  • platform/mac/svg/custom/use-on-non-svg-namespaced-element-expected.txt:
  • platform/mac/svg/custom/use-recursion-1-expected.txt:
  • platform/mac/svg/custom/use-recursion-2-expected.txt:
  • platform/mac/svg/custom/use-recursion-3-expected.txt:
  • platform/mac/svg/custom/use-recursion-4-expected.txt:
  • platform/mac/svg/hixie/error/017-expected.txt:
  • platform/mac/svg/text/text-text-05-t-expected.checksum:
  • platform/mac/svg/text/text-text-05-t-expected.png:
  • svg/custom/relative-sized-deep-shadow-tree-content.xhtml: Added.
  • svg/custom/relative-sized-shadow-tree-content.xhtml: Added.
  • svg/text/text-text-05-t.svg: Remove possible race-condition, between selecting & dumping.
Location:
trunk
Files:
12 added
32 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r53445 r53446  
     12010-01-18  Nikolas Zimmermann  <nzimmermann@rim.com>
     2
     3        Reviewed by Dirk Schulze.
     4
     5        Rewrite SVG <use> support in a modern-fashion
     6        https://bugs.webkit.org/show_bug.cgi?id=33776
     7
     8        Update some test results, after rewriting <use> support.
     9
     10        * platform/mac/svg/W3C-SVG-1.1/animate-elem-40-t-expected.txt:
     11        * platform/mac/svg/custom/relative-sized-deep-shadow-tree-content-expected.checksum: Added.
     12        * platform/mac/svg/custom/relative-sized-deep-shadow-tree-content-expected.png: Added.
     13        * platform/mac/svg/custom/relative-sized-deep-shadow-tree-content-expected.txt: Added.
     14        * platform/mac/svg/custom/relative-sized-shadow-tree-content-expected.checksum: Added.
     15        * platform/mac/svg/custom/relative-sized-shadow-tree-content-expected.png: Added.
     16        * platform/mac/svg/custom/relative-sized-shadow-tree-content-expected.txt: Added.
     17        * platform/mac/svg/custom/use-events-crash-expected.txt:
     18        * platform/mac/svg/custom/use-on-disallowed-foreign-object-1-expected.txt:
     19        * platform/mac/svg/custom/use-on-disallowed-foreign-object-3-expected.txt:
     20        * platform/mac/svg/custom/use-on-non-svg-namespaced-element-expected.txt:
     21        * platform/mac/svg/custom/use-recursion-1-expected.txt:
     22        * platform/mac/svg/custom/use-recursion-2-expected.txt:
     23        * platform/mac/svg/custom/use-recursion-3-expected.txt:
     24        * platform/mac/svg/custom/use-recursion-4-expected.txt:
     25        * platform/mac/svg/hixie/error/017-expected.txt:
     26        * platform/mac/svg/text/text-text-05-t-expected.checksum:
     27        * platform/mac/svg/text/text-text-05-t-expected.png:
     28        * svg/custom/relative-sized-deep-shadow-tree-content.xhtml: Added.
     29        * svg/custom/relative-sized-shadow-tree-content.xhtml: Added.
     30        * svg/text/text-text-05-t.svg: Remove possible race-condition, between selecting & dumping.
     31
    1322010-01-18  Kent Tamura  <tkent@chromium.org>
    233
  • trunk/LayoutTests/platform/mac/svg/W3C-SVG-1.1/animate-elem-40-t-expected.txt

    r42840 r53446  
    1313            RenderSVGContainer {use} at (-18.50,-18.50) size 7x7
    1414              RenderSVGContainer {g} at (-18.50,-18.50) size 7x7 [transform={m=((1.00,0.00)(0.00,1.00)) t=(-15.00,-15.00)}]
    15                 RenderPath {rect} at (-18.50,-18.50) size 7x7 [stroke={[type=SOLID] [color=#FFB400]}] [fill={[type=SOLID] [color=#E6E6E6]}] [data="M-3.00,-3.00 L3.00,-3.00 L3.00,3.00 L-3.00,3.00 Z"]
     15                RenderPath {rect} at (-18.50,-18.50) size 7x7 [stroke={[type=SOLID] [color=#FFB400]}] [fill={[type=SOLID] [color=#FFB400]}] [data="M-3.00,-3.00 L3.00,-3.00 L3.00,3.00 L-3.00,3.00 Z"]
    1616            RenderSVGContainer {use} at (11.50,-18.50) size 7x7
    1717              RenderSVGContainer {g} at (11.50,-18.50) size 7x7 [transform={m=((1.00,0.00)(0.00,1.00)) t=(15.00,-15.00)}]
     
    113113            RenderSVGContainer {use} at (-18.50,-18.50) size 7x7
    114114              RenderSVGContainer {g} at (-18.50,-18.50) size 7x7 [transform={m=((1.00,0.00)(0.00,1.00)) t=(-15.00,-15.00)}]
    115                 RenderPath {rect} at (-18.50,-18.50) size 7x7 [stroke={[type=SOLID] [color=#FFB400]}] [fill={[type=SOLID] [color=#E6E6E6]}] [data="M-3.00,-3.00 L3.00,-3.00 L3.00,3.00 L-3.00,3.00 Z"]
     115                RenderPath {rect} at (-18.50,-18.50) size 7x7 [stroke={[type=SOLID] [color=#FFB400]}] [fill={[type=SOLID] [color=#FFB400]}] [data="M-3.00,-3.00 L3.00,-3.00 L3.00,3.00 L-3.00,3.00 Z"]
    116116            RenderSVGContainer {use} at (11.50,-18.50) size 7x7
    117117              RenderSVGContainer {g} at (11.50,-18.50) size 7x7 [transform={m=((1.00,0.00)(0.00,1.00)) t=(15.00,-15.00)}]
  • trunk/LayoutTests/platform/mac/svg/custom/use-events-crash-expected.txt

    r38794 r53446  
    2020          RenderSVGContainer {g} at (350,25) size 40x40
    2121            RenderPath {rect} at (350,25) size 40x40 [fill={[type=SOLID] [color=#00FF00]}] [data="M0.00,0.00 L40.00,0.00 L40.00,40.00 L0.00,40.00 Z"]
     22caret: position 0 of child 0 {#text} of child 1 {text} of child 1 {g} of child 3 {g} of child 3 {g} of child 1 {svg} of document
  • trunk/LayoutTests/platform/mac/svg/custom/use-on-disallowed-foreign-object-1-expected.txt

    r30635 r53446  
    88          text run at (0,0) width 244: "You should only see this string ONCE"
    99    RenderSVGContainer {use} at (250,-50) size 0x0 [transform={m=((0.71,0.71)(-0.71,0.71)) t=(250.00,-50.00)}]
    10       RenderSVGContainer {g} at (250,-35.86) size 0x0 [transform={m=((1.00,0.00)(0.00,1.00)) t=(10.00,10.00)}]
     10      RenderSVGContainer {g} at (250,-50) size 0x0
  • trunk/LayoutTests/platform/mac/svg/custom/use-on-disallowed-foreign-object-3-expected.txt

    r30635 r53446  
    88          text run at (0,0) width 244: "You should only see this string ONCE"
    99    RenderSVGContainer {use} at (250,-50) size 0x0 [transform={m=((0.71,0.71)(-0.71,0.71)) t=(250.00,-50.00)}]
    10       RenderSVGContainer {g} at (250,-35.86) size 0x0 [transform={m=((1.00,0.00)(0.00,1.00)) t=(10.00,10.00)}]
     10      RenderSVGContainer {g} at (250,-50) size 0x0
    1111    RenderSVGContainer {use} at (250,-50) size 0x0 [transform={m=((0.71,0.71)(-0.71,0.71)) t=(250.00,-50.00)}]
    1212      RenderSVGContainer {g} at (250,-35.86) size 0x0 [transform={m=((1.00,0.00)(0.00,1.00)) t=(10.00,10.00)}]
    13         RenderSVGContainer {g} at (452.13,115.56) size 0x0 [transform={m=((0.71,0.71)(-0.71,0.71)) t=(250.00,-35.86)}]
     13        RenderSVGContainer {g} at (462.13,119.71) size 0x0 [transform={m=((0.71,0.71)(-0.71,0.71)) t=(260.00,-40.00)}]
  • trunk/LayoutTests/platform/mac/svg/custom/use-on-disallowed-foreign-object-4-expected.txt

    r30635 r53446  
    1515    RenderSVGContainer {use} at (250,-50) size 0x0 [transform={m=((0.71,0.71)(-0.71,0.71)) t=(250.00,-50.00)}]
    1616      RenderSVGContainer {g} at (250,-35.86) size 0x0 [transform={m=((1.00,0.00)(0.00,1.00)) t=(10.00,10.00)}]
    17         RenderSVGContainer {g} at (452.13,115.56) size 0x0 [transform={m=((0.71,0.71)(-0.71,0.71)) t=(250.00,-35.86)}]
    18           RenderSVGContainer {g} at (452.13,115.56) size 0x0
    19             RenderSVGContainer {g} at (452.13,115.56) size 0x0
     17        RenderSVGContainer {g} at (462.13,119.71) size 0x0 [transform={m=((0.71,0.71)(-0.71,0.71)) t=(260.00,-40.00)}]
     18          RenderSVGContainer {g} at (462.13,119.71) size 0x0
     19            RenderSVGContainer {g} at (462.13,119.71) size 0x0
  • trunk/LayoutTests/platform/mac/svg/custom/use-on-non-svg-namespaced-element-expected.txt

    r30635 r53446  
    88          text run at (0,0) width 244: "You should only see this string ONCE"
    99    RenderSVGContainer {use} at (250,-50) size 0x0 [transform={m=((0.71,0.71)(-0.71,0.71)) t=(250.00,-50.00)}]
     10      RenderSVGContainer {g} at (250,-50) size 0x0
  • trunk/LayoutTests/platform/mac/svg/custom/use-recursion-1-expected.txt

    r38794 r53446  
    77        RenderPath {rect} at (-2.50,-2.50) size 65x15 [stroke={[type=SOLID] [color=#000080] [stroke width=5.00]}] [fill={[type=SOLID] [color=#FF0000]}] [data="M0.00,0.00 L60.00,0.00 L60.00,10.00 L0.00,10.00 Z"]
    88        RenderSVGContainer {use} at (0,0) size 0x0
     9          RenderSVGContainer {g} at (0,0) size 0x0
    910    RenderSVGText {text} at (10,60) size 139x18 contains 1 chunk(s)
    1011      RenderSVGInlineText {#text} at (0,-14) size 139x18
    1112        chunk 1 text run 1 at (10.00,60.00) startOffset 0 endOffset 22 width 139.00: "This should not crash."
    1213    RenderSVGContainer {use} at (0,0) size 0x0
     14      RenderSVGContainer {g} at (0,0) size 0x0
  • trunk/LayoutTests/platform/mac/svg/custom/use-recursion-2-expected.txt

    r30635 r53446  
    77        chunk 1 text run 1 at (10.00,60.00) startOffset 0 endOffset 22 width 139.00: "This should not crash."
    88    RenderSVGContainer {use} at (0,0) size 0x0
     9      RenderSVGContainer {g} at (0,0) size 0x0
  • trunk/LayoutTests/platform/mac/svg/custom/use-recursion-3-expected.txt

    r38794 r53446  
    77        RenderPath {rect} at (-2.50,-2.50) size 65x15 [stroke={[type=SOLID] [color=#000080] [stroke width=5.00]}] [fill={[type=SOLID] [color=#FF0000]}] [data="M0.00,0.00 L60.00,0.00 L60.00,10.00 L0.00,10.00 Z"]
    88        RenderSVGContainer {use} at (0,0) size 0x0
     9          RenderSVGContainer {g} at (0,0) size 0x0
    910    RenderSVGText {text} at (10,60) size 139x18 contains 1 chunk(s)
    1011      RenderSVGInlineText {#text} at (0,-14) size 139x18
    1112        chunk 1 text run 1 at (10.00,60.00) startOffset 0 endOffset 22 width 139.00: "This should not crash."
    1213    RenderSVGContainer {use} at (0,0) size 0x0
     14      RenderSVGContainer {g} at (0,0) size 0x0
  • trunk/LayoutTests/platform/mac/svg/custom/use-recursion-4-expected.txt

    r38794 r53446  
    1111        RenderPath {rect} at (-2.50,-2.50) size 65x15 [stroke={[type=SOLID] [color=#000080] [stroke width=5.00]}] [fill={[type=SOLID] [color=#FF0000]}] [data="M0.00,0.00 L60.00,0.00 L60.00,10.00 L0.00,10.00 Z"]
    1212        RenderSVGContainer {use} at (0,0) size 0x0
     13          RenderSVGContainer {g} at (0,0) size 0x0
    1314    RenderSVGText {text} at (10,60) size 139x18 contains 1 chunk(s)
    1415      RenderSVGInlineText {#text} at (0,-14) size 139x18
    1516        chunk 1 text run 1 at (10.00,60.00) startOffset 0 endOffset 22 width 139.00: "This should not crash."
    1617    RenderSVGContainer {use} at (0,0) size 0x0
     18      RenderSVGContainer {g} at (0,0) size 0x0
  • trunk/LayoutTests/platform/mac/svg/hixie/error/017-expected.txt

    r38794 r53446  
    1818    RenderSVGContainer {g} at (0,0) size 0x0
    1919      RenderSVGContainer {use} at (0,0) size 0x0
     20        RenderSVGContainer {g} at (0,0) size 0x0
    2021    RenderSVGText {text} at (20,220) size 444x230 contains 1 chunk(s)
    2122      RenderSVGInlineText {#text} at (0,-180) size 444x230
  • trunk/LayoutTests/platform/mac/svg/text/text-text-05-t-expected.checksum

    r40949 r53446  
    1 0571a94f26afb9720655647261fc786c
     1db9ca27ce7850c95e06bb13bbcf32246
  • trunk/LayoutTests/svg/text/text-text-05-t.svg

    r28763 r53446  
    160160   
    161161<script>
    162 if (window.layoutTestController)
    163     window.layoutTestController.dumpSelectionRect();
    164 document.execCommand("SelectAll");
     162if (window.layoutTestController) {
     163    layoutTestController.waitUntilDone();
     164    layoutTestController.dumpSelectionRect();
     165}
     166
     167setTimeout(function() {
     168    document.execCommand("SelectAll");
     169    if (window.layoutTestController)
     170        layoutTestController.notifyDone();
     171}, 0);
    165172</script>
    166173</svg>
  • trunk/WebCore/Android.mk

    r52949 r53446  
    597597        rendering/RenderSVGModelObject.cpp \
    598598        rendering/RenderSVGRoot.cpp \
     599        rendering/RenderSVGShadowTreeRootContainer.cpp \
    599600        rendering/RenderSVGTSpan.cpp \
    600601        rendering/RenderSVGText.cpp \
     
    635636        rendering/SVGRenderSupport.cpp \
    636637        rendering/SVGRenderTreeAsText.cpp \
    637         rendering/SVGRootInlineBox.cpp
     638        rendering/SVGRootInlineBox.cpp \
     639        rendering/SVGShadowTreeElements.cpp
    638640endif
    639641
  • trunk/WebCore/ChangeLog

    r53445 r53446  
     12010-01-18  Nikolas Zimmermann  <nzimmermann@rim.com>
     2
     3        Reviewed by Dirk Schulze.
     4
     5        Rewrite SVG <use> support in a modern-fashion
     6        https://bugs.webkit.org/show_bug.cgi?id=33776
     7
     8        Tests: svg/custom/relative-sized-deep-shadow-tree-content.xhtml
     9               svg/custom/relative-sized-shadow-tree-content.xhtml
     10
     11        Fixes: svg/W3C-SVG-1.1/animate-elem-30-t.svg (animated circle sometimes takes wrong path)
     12
     13        Rewrite <use> support in less intrusive way. Try hard to avoid recloning where possible, and do it lazily.
     14        Introduce RenderSVGShadowTreeRootContainer as special renderer for SVGUseElement, that now manages the
     15        render tree, instead of SVGUseElement manually hacking around it's own renderer from the DOM side.
     16
     17        Instead of recloning the whole shadow tree for every attribute change (DOM setAttribute / SVG DOM changes / CSS changes / childrenChanged()...)
     18        just notify the RenderSVGShadowTreeRootContainer that it's supposed to reclone the tree upon the next updateFromElement() call.
     19
     20        updateFromElement() is fired from SVGUseElement::attach() / recalcStyle(), as it's done for HTMLFormControlElement/HTMLMediaElement, thus
     21        lazily recloning the shadow tree if necessary.
     22
     23        Animations for <use> elements was a real performance bottlenck as the tree got recloned on every attribute change. Reclones are _completly_
     24        avoided for animations now - the SVGAnim*Element classes already updated the instances of an element manually, though that resulted in a reclone
     25        nontheless, and thus killing performance. <use> elements can only be recloned through mutations of the elements that they reference to.
     26        For example referencing a <rect> element from a <use> element and scripting the <rect> element (setAttribute, or child tree mutations etc.).
     27        We reclone instead of trying to synchronize trees - as it's currenty implemented - because it's very hard to do it right.
     28
     29        Any DOM / SVG DOM / CSS change on the <use> element don't reclone the tree anymore, this is a huge speed benefit.
     30        x/y attribute changes are correctly handled in the render tree now (by an additional local transformation), now percentual values work
     31        as expected, and resize on window changes - affecting lots of testcases.
     32
     33        The <use> implementation is much safer now, not doing any mutations synchronously from svgAttributeChanged etc.
     34        Remove hack to force garbage collection on SVGElementInstance destruction - can't reproduce it anymore.
     35
     36        * Android.mk: Add new files to build.
     37        * GNUmakefile.am: Ditto.
     38        * WebCore.gypi: Ditto.
     39        * WebCore.pro: Ditto.
     40        * WebCore.vcproj/WebCore.vcproj: Ditto.
     41        * WebCore.xcodeproj/project.pbxproj: Ditto.
     42        * rendering/RenderSVGShadowTreeRootContainer.cpp: Added. This is the rendered now created by SVGUseElement.
     43        (WebCore::RenderSVGShadowTreeRootContainer::RenderSVGShadowTreeRootContainer):
     44        (WebCore::RenderSVGShadowTreeRootContainer::~RenderSVGShadowTreeRootContainer):
     45        (WebCore::RenderSVGShadowTreeRootContainer::updateStyle): Used form SVGUseElement to request style recalculations for the shadow tree renderers
     46        (WebCore::RenderSVGShadowTreeRootContainer::updateFromElement): Used from SVGUseElement attach/recalcStyle to eventually request shadow tree updates.
     47        (WebCore::RenderSVGShadowTreeRootContainer::styleDidChange): Used to propage style updates across shadow tree boundaries.
     48        * rendering/RenderSVGShadowTreeRootContainer.h: Added.
     49        (WebCore::RenderSVGShadowTreeRootContainer::markShadowTreeForRecreation): Marks the shadow tree for a reclone, next time updateFromElement is used.
     50        * rendering/RenderSVGTransformableContainer.cpp:
     51        (WebCore::RenderSVGTransformableContainer::calculateLocalTransform): Take containerTranslation() into account, supplied by RenderSVGSDhadowTreeContainer.
     52        * rendering/SVGShadowTreeElements.cpp: Added. This is the root element of the SVG shadow tree residing as (hidden) child of SVGUseElement (DOM wise).
     53        (WebCore::SVGShadowTreeContainerElement::SVGShadowTreeContainerElement):
     54        (WebCore::SVGShadowTreeContainerElement::~SVGShadowTreeContainerElement):
     55        (WebCore::SVGShadowTreeContainerElement::containerTranslation): Used from calculateLocalTransform() to take x/y translation into account for shadow tree container elements.
     56        (WebCore::SVGShadowTreeRootElement::SVGShadowTreeRootElement):
     57        (WebCore::SVGShadowTreeRootElement::~SVGShadowTreeRootElement):
     58        (WebCore::SVGShadowTreeRootElement::attachElement): Used by RenderSVGShadowTreeRootContainer, instead of attach(), as we're a shadow tree root node.
     59        * rendering/SVGShadowTreeElements.h: Added. This is the root element of each SVG shadow sub-tree (whenever a <use> element is expanded in the shadow tree).
     60        (WebCore::SVGShadowTreeContainerElement::isShadowTreeContainerElement): Return true here.
     61        (WebCore::SVGShadowTreeContainerElement::setContainerOffset): Used from SVGUseElement to propagate x/y translation values set on <use> elements in the shadow tree.
     62        (WebCore::SVGShadowTreeRootElement::isShadowNode): Identify us as shadow node.
     63        (WebCore::SVGShadowTreeRootElement::shadowParentNode): Ditto. Return actual shadow parent node (== corresponding use element).
     64        * svg/SVGElement.cpp: Shrink size of all SVG*Elements, by removing the m_shadowParent parent. SVGShadowTreeRootElement is the new base class for shadow tree.
     65        (WebCore::SVGElement::SVGElement):
     66        (WebCore::SVGElement::eventParentNode): Call virtual shadowParentNode() method, instead of accessing m_shadowParent.
     67        * svg/SVGElement.h: Remove isShadowNode() / shadowParentNode() / setShadowParentNode().
     68        * svg/SVGElementInstance.cpp: Remove the hack, calling garbage collection before destruction. Can't reproduce this anymore, let's see what the bots say.
     69        (WebCore::SVGElementInstance::SVGElementInstance): Remove now unnecessary m_needsUpdate flag.
     70        (WebCore::SVGElementInstance::invalidateAllInstancesOfElement): Don't invalidate if instance updates are blocked (see SVGStyledElement changes)
     71        * svg/SVGElementInstance.h: Remove m_needsUpdate, and forgetWrapper() method.
     72        * svg/SVGGElement.h:
     73        (WebCore::SVGGElement::isShadowTreeContainerElement): Add new virtual method here returning false by default, SVGShadowTreeContainerElement will override it.
     74        * svg/SVGStyledElement.cpp: Remove gElementsWithInstanceUpdatesBlocked HashSet tracking the state of instancesUpdatesBlocked() per SVGStyledElement - make it a member variable.
     75        * svg/SVGStyledElement.h: Add inline getter/setters around m_instanceUpdatesBlocked.
     76        (WebCore::SVGStyledElement::instanceUpdatesBlocked):
     77        (WebCore::SVGStyledElement::setInstanceUpdatesBlocked):
     78        * svg/SVGUseElement.cpp: Full rewrite of <use> support, a detailed discussion would blow the ChangeLog - see short version above.
     79        (WebCore::SVGUseElement::SVGUseElement):
     80        (WebCore::SVGUseElement::instanceRoot):
     81        (WebCore::SVGUseElement::insertedIntoDocument):
     82        (WebCore::SVGUseElement::removedFromDocument):
     83        (WebCore::SVGUseElement::svgAttributeChanged):
     84        (WebCore::updateContainerOffset):
     85        (WebCore::SVGUseElement::updateContainerOffsets):
     86        (WebCore::SVGUseElement::recalcStyle):
     87        (WebCore::dumpInstanceTree):
     88        (WebCore::SVGUseElement::buildPendingResource):
     89        (WebCore::SVGUseElement::buildShadowAndInstanceTree):
     90        (WebCore::SVGUseElement::createRenderer):
     91        (WebCore::updateFromElementCallback):
     92        (WebCore::SVGUseElement::attach):
     93        (WebCore::SVGUseElement::detach):
     94        (WebCore::SVGUseElement::toClipPath):
     95        (WebCore::SVGUseElement::buildInstanceTree):
     96        (WebCore::SVGUseElement::handleDeepUseReferencing):
     97        (WebCore::SVGUseElement::buildShadowTree):
     98        (WebCore::SVGUseElement::expandUseElementsInShadowTree):
     99        (WebCore::SVGUseElement::expandSymbolElementsInShadowTree):
     100        (WebCore::SVGUseElement::instanceForShadowTreeElement):
     101        (WebCore::SVGUseElement::invalidateShadowTree):
     102        (WebCore::SVGUseElement::transferUseAttributesToReplacedElement):
     103        * svg/SVGUseElement.h:
     104        (WebCore::SVGUseElement::isPendingResource):
     105
    11062010-01-18  Kent Tamura  <tkent@chromium.org>
    2107
  • trunk/WebCore/GNUmakefile.am

    r53443 r53446  
    29482948        WebCore/rendering/RenderSVGRoot.cpp \
    29492949        WebCore/rendering/RenderSVGRoot.h \
     2950        WebCore/rendering/RenderSVGShadowTreeRootContainer.cpp \
     2951        WebCore/rendering/RenderSVGShadowTreeRootContainer.h \
    29502952        WebCore/rendering/RenderSVGTSpan.cpp \
    29512953        WebCore/rendering/RenderSVGTSpan.h \
     
    29732975        WebCore/rendering/SVGRootInlineBox.cpp \
    29742976        WebCore/rendering/SVGRootInlineBox.h \
     2977        WebCore/rendering/SVGShadowTreeElements.cpp \
     2978        WebCore/rendering/SVGShadowTreeElements.h \
    29752979        WebCore/rendering/style/SVGRenderStyle.cpp \
    29762980        WebCore/rendering/style/SVGRenderStyle.h \
  • trunk/WebCore/WebCore.gypi

    r53406 r53446  
    30573057            'rendering/RenderSVGRoot.cpp',
    30583058            'rendering/RenderSVGRoot.h',
     3059            'rendering/RenderSVGShadowTreeRootContainer.cpp',
     3060            'rendering/RenderSVGShadowTreeRootContainer.h',
    30593061            'rendering/RenderSVGTSpan.cpp',
    30603062            'rendering/RenderSVGTSpan.h',
     
    31413143            'rendering/SVGRootInlineBox.cpp',
    31423144            'rendering/SVGRootInlineBox.h',
     3145            'rendering/SVGShadowTreeElements.cpp',
     3146            'rendering/SVGShadowTreeElements.h',
    31433147            'rendering/TableLayout.h',
    31443148            'rendering/TextControlInnerElements.cpp',
  • trunk/WebCore/WebCore.pro

    r53394 r53446  
    16351635    rendering/RenderSVGModelObject.h \
    16361636    rendering/RenderSVGRoot.h \
     1637    rendering/RenderSVGShadowTreeRootContainer.h \
    16371638    rendering/RenderSVGText.h \
    16381639    rendering/RenderSVGTextPath.h \
     
    16921693    rendering/SVGRenderTreeAsText.h \
    16931694    rendering/SVGRootInlineBox.h \
     1695    rendering/SVGShadowTreeElements.h \
    16941696    rendering/TextControlInnerElements.h \
    16951697    rendering/TransformState.h \
     
    25792581        rendering/RenderSVGModelObject.cpp \
    25802582        rendering/RenderSVGRoot.cpp \
     2583        rendering/RenderSVGShadowTreeRootContainer.cpp \
    25812584        rendering/RenderSVGText.cpp \
    25822585        rendering/RenderSVGTextPath.cpp \
     
    25892592        rendering/SVGMarkerLayoutInfo.cpp \
    25902593        rendering/SVGRenderSupport.cpp \
    2591         rendering/SVGRootInlineBox.cpp
     2594        rendering/SVGRootInlineBox.cpp \
     2595        rendering/SVGShadowTreeElements.cpp
    25922596}
    25932597
  • trunk/WebCore/WebCore.vcproj/WebCore.vcproj

    r53429 r53446  
    2746627466                        </File>
    2746727467                        <File
     27468                                RelativePath="..\rendering\RenderSVGShadowTreeRootContainer.cpp"
     27469                                >
     27470                        </File>
     27471                        <File
     27472                                RelativePath="..\rendering\RenderSVGShadowTreeRootContainer.h"
     27473                                >
     27474                        </File>
     27475                        <File
    2746827476                                RelativePath="..\rendering\RenderSVGText.cpp"
    2746927477                                >
     
    2779327801                        <File
    2779427802                                RelativePath="..\rendering\SVGRootInlineBox.h"
     27803                                >
     27804                        </File>
     27805                        <File
     27806                                RelativePath="..\rendering\SVGShadowTreeElements.cpp"
     27807                                >
     27808                        </File>
     27809                        <File
     27810                                RelativePath="..\rendering\SVGShadowTreeElements.h"
    2779527811                                >
    2779627812                        </File>
  • trunk/WebCore/WebCore.xcodeproj/project.pbxproj

    r53443 r53446  
    145145                08CD61BC0ED3929C002DDF51 /* WMLTaskElement.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 08CD61B80ED3929C002DDF51 /* WMLTaskElement.cpp */; };
    146146                08CD61BD0ED3929C002DDF51 /* WMLTaskElement.h in Headers */ = {isa = PBXBuildFile; fileRef = 08CD61B90ED3929C002DDF51 /* WMLTaskElement.h */; };
     147                08DAB9BA1103D9A5003E7ABA /* RenderSVGShadowTreeRootContainer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 08DAB9B81103D9A5003E7ABA /* RenderSVGShadowTreeRootContainer.cpp */; };
     148                08DAB9BB1103D9A5003E7ABA /* RenderSVGShadowTreeRootContainer.h in Headers */ = {isa = PBXBuildFile; fileRef = 08DAB9B91103D9A5003E7ABA /* RenderSVGShadowTreeRootContainer.h */; };
     149                08DAB9C21103D9C1003E7ABA /* SVGShadowTreeElements.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 08DAB9C01103D9C1003E7ABA /* SVGShadowTreeElements.cpp */; };
     150                08DAB9C31103D9C1003E7ABA /* SVGShadowTreeElements.h in Headers */ = {isa = PBXBuildFile; fileRef = 08DAB9C11103D9C1003E7ABA /* SVGShadowTreeElements.h */; };
    147151                08E192530EDE0C3A0087B780 /* WMLErrorHandling.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 08E192510EDE0C390087B780 /* WMLErrorHandling.cpp */; };
    148152                08E192540EDE0C3A0087B780 /* WMLErrorHandling.h in Headers */ = {isa = PBXBuildFile; fileRef = 08E192520EDE0C3A0087B780 /* WMLErrorHandling.h */; };
     
    53695373                08CD61B80ED3929C002DDF51 /* WMLTaskElement.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WMLTaskElement.cpp; sourceTree = "<group>"; };
    53705374                08CD61B90ED3929C002DDF51 /* WMLTaskElement.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WMLTaskElement.h; sourceTree = "<group>"; };
     5375                08DAB9B81103D9A5003E7ABA /* RenderSVGShadowTreeRootContainer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RenderSVGShadowTreeRootContainer.cpp; sourceTree = "<group>"; };
     5376                08DAB9B91103D9A5003E7ABA /* RenderSVGShadowTreeRootContainer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RenderSVGShadowTreeRootContainer.h; sourceTree = "<group>"; };
     5377                08DAB9C01103D9C1003E7ABA /* SVGShadowTreeElements.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SVGShadowTreeElements.cpp; sourceTree = "<group>"; };
     5378                08DAB9C11103D9C1003E7ABA /* SVGShadowTreeElements.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SVGShadowTreeElements.h; sourceTree = "<group>"; };
    53715379                08E192510EDE0C390087B780 /* WMLErrorHandling.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WMLErrorHandling.cpp; sourceTree = "<group>"; };
    53725380                08E192520EDE0C3A0087B780 /* WMLErrorHandling.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WMLErrorHandling.h; sourceTree = "<group>"; };
     
    1558215590                                AA31B5B20C1DFD1000AE7083 /* RenderSVGRoot.cpp */,
    1558315591                                AA31B5B30C1DFD1000AE7083 /* RenderSVGRoot.h */,
     15592                                08DAB9B81103D9A5003E7ABA /* RenderSVGShadowTreeRootContainer.cpp */,
     15593                                08DAB9B91103D9A5003E7ABA /* RenderSVGShadowTreeRootContainer.h */,
    1558415594                                853CA9D20AEEC5E9002372DC /* RenderSVGText.cpp */,
    1558515595                                853CA9D30AEEC5E9002372DC /* RenderSVGText.h */,
     
    1564515655                                853CA9E40AEEC608002372DC /* SVGRootInlineBox.cpp */,
    1564615656                                853CA9E50AEEC608002372DC /* SVGRootInlineBox.h */,
     15657                                08DAB9C01103D9C1003E7ABA /* SVGShadowTreeElements.cpp */,
     15658                                08DAB9C11103D9C1003E7ABA /* SVGShadowTreeElements.h */,
    1564715659                                A8CFF04C0A154F09000A4234 /* TableLayout.h */,
    1564815660                                AB014DE10E689A4300E10445 /* TextControlInnerElements.cpp */,
     
    1835618368                                6E4E91AF10F7FB3100A2779C /* WebGLContextAttributes.h in Headers */,
    1835718369                                6EE8A77310F803F3005A4A24 /* JSWebGLContextAttributes.h in Headers */,
     18370                                08DAB9BB1103D9A5003E7ABA /* RenderSVGShadowTreeRootContainer.h in Headers */,
     18371                                08DAB9C31103D9C1003E7ABA /* SVGShadowTreeElements.h in Headers */,
    1835818372                                E15A36D71104572000B7B639 /* XMLNSNames.h in Headers */,
    1835918373                                59A9E7B21104759400DFB4C1 /* JavaInstanceJSC.h in Headers */,
     
    2052120535                                6E4E91AE10F7FB3100A2779C /* WebGLContextAttributes.cpp in Sources */,
    2052220536                                6EE8A77210F803F3005A4A24 /* JSWebGLContextAttributes.cpp in Sources */,
     20537                                08DAB9BA1103D9A5003E7ABA /* RenderSVGShadowTreeRootContainer.cpp in Sources */,
     20538                                08DAB9C21103D9C1003E7ABA /* SVGShadowTreeElements.cpp in Sources */,
    2052320539                                E15A36D91104572700B7B639 /* XMLNSNames.cpp in Sources */,
    2052420540                                59A9E7B01104758800DFB4C1 /* JavaInstanceJSC.cpp in Sources */,
  • trunk/WebCore/rendering/RenderSVGTransformableContainer.cpp

    r53365 r53446  
    11/*
    2     Copyright (C) 2004, 2005 Nikolas Zimmermann <wildfox@kde.org>
     2    Copyright (C) 2004, 2005 Nikolas Zimmermann <zimmermann@kde.org>
    33                  2004, 2005, 2006 Rob Buis <buis@kde.org>
    44                  2009 Google, Inc.
     
    2121
    2222#include "config.h"
     23
    2324#if ENABLE(SVG)
    24 
    2525#include "RenderSVGTransformableContainer.h"
    2626
     27#include "SVGShadowTreeElements.h"
    2728#include "SVGStyledTransformableElement.h"
    28 #include "SVGTransformList.h"
    2929
    3030namespace WebCore {
     
    4848{
    4949    m_localTransform = static_cast<SVGStyledTransformableElement*>(node())->animatedLocalTransform();
     50    if (!node()->hasTagName(SVGNames::gTag) || !static_cast<SVGGElement*>(node())->isShadowTreeContainerElement())
     51        return;
     52
     53    FloatSize translation = static_cast<SVGShadowTreeContainerElement*>(node())->containerTranslation();
     54    if (translation.width() == 0 && translation.height() == 0)
     55        return;
     56
     57    m_localTransform.translateRight(translation.width(), translation.height());
    5058}
    5159
  • trunk/WebCore/svg/SVGElement.cpp

    r52312 r53446  
    5555SVGElement::SVGElement(const QualifiedName& tagName, Document* document)
    5656    : StyledElement(tagName, document, CreateElementZeroRefCount)
    57     , m_shadowParent(0)
    5857    , m_cursorElement(0)
    5958    , m_cursorImageValue(0)
     
    286285ContainerNode* SVGElement::eventParentNode()
    287286{
    288     return m_shadowParent ? m_shadowParent : StyledElement::eventParentNode();
     287    if (Node* shadowParent = shadowParentNode()) {
     288        ASSERT(shadowParent->isContainerNode());
     289        return static_cast<ContainerNode*>(shadowParent);
     290    }
     291    return StyledElement::eventParentNode();
    289292}
    290293
  • trunk/WebCore/svg/SVGElement.h

    r49745 r53446  
    6161        virtual bool isTextContent() const { return false; }
    6262
    63         void setShadowParentNode(ContainerNode* node) { m_shadowParent = node; }
    64 
    6563        // For SVGTests
    6664        virtual bool isValid() const { return true; }
     
    9694
    9795        virtual bool isSVGElement() const { return true; }
     96        virtual bool isSupported(StringImpl* feature, StringImpl* version) const;
    9897
    99         virtual bool isSupported(StringImpl* feature, StringImpl* version) const;
    100        
    101         virtual bool isShadowNode() const { return m_shadowParent; }
    102         virtual Node* shadowParentNode() { return m_shadowParent; }
    10398        virtual ContainerNode* eventParentNode();
    104 
    10599        virtual void buildPendingResource() { }
    106100
     
    110104        virtual bool haveLoadedRequiredResources();
    111105
    112         ContainerNode* m_shadowParent;
    113106        mutable SynchronizablePropertyController m_propertyController;
    114107
  • trunk/WebCore/svg/SVGElementInstance.cpp

    r48701 r53446  
    3434#include <wtf/RefCountedLeakCounter.h>
    3535
    36 #if USE(JSC)
    37 #include "GCController.h"
    38 #endif
    39 
    4036namespace WebCore {
    4137
     
    5248
    5349SVGElementInstance::SVGElementInstance(SVGUseElement* useElement, PassRefPtr<SVGElement> originalElement)
    54     : m_needsUpdate(false)
    55     , m_useElement(useElement)
     50    : m_useElement(useElement)
    5651    , m_element(originalElement)
    5752    , m_previousSibling(0)
     
    9489}
    9590
    96 void SVGElementInstance::forgetWrapper()
    97 {
    98 #if USE(JSC)
    99     // FIXME: This is fragile, as discussed with Sam. Need to find a better solution.
    100     // Think about the case where JS explicitely holds "var root = useElement.instanceRoot;".
    101     // We still have to recreate this wrapper somehow. The gc collection below, won't catch it.
    102 
    103     // If the use shadow tree has been rebuilt, just the JSSVGElementInstance objects
    104     // are still holding RefPtrs of SVGElementInstance objects, which prevent us to
    105     // be deleted (and the shadow tree is not destructed as well). Force JS GC.
    106     gcController().garbageCollectNow();
    107 #endif
    108 }
    109 
    11091void SVGElementInstance::appendChild(PassRefPtr<SVGElementInstance> child)
    11192{
     
    11596void SVGElementInstance::invalidateAllInstancesOfElement(SVGElement* element)
    11697{
    117     if (!element)
     98    if (!element || !element->isStyled())
     99        return;
     100
     101    if (static_cast<SVGStyledElement*>(element)->instanceUpdatesBlocked())
    118102        return;
    119103
     
    122106        return;
    123107
    124     // Find all use elements referencing the instances - ask them _once_ to rebuild.
     108    // Mark all use elements referencing 'element' for rebuilding
    125109    HashSet<SVGElementInstance*>::const_iterator it = set.begin();
    126110    const HashSet<SVGElementInstance*>::const_iterator end = set.end();
    127111
    128     for (; it != end; ++it)
    129         (*it)->setNeedsUpdate(true);
    130 }
    131 
    132 void SVGElementInstance::setNeedsUpdate(bool value)
    133 {
    134     m_needsUpdate = value;
    135 
    136     if (m_needsUpdate)
    137         correspondingUseElement()->setNeedsStyleRecalc();
     112    for (; it != end; ++it) {
     113        ASSERT((*it)->correspondingElement() == element);
     114        (*it)->correspondingUseElement()->invalidateShadowTree();
     115    }
    138116}
    139117
  • trunk/WebCore/svg/SVGElementInstance.h

    r48701 r53446  
    4646
    4747        virtual ~SVGElementInstance();
    48 
    49         bool needsUpdate() const { return m_needsUpdate; }
    50         void setNeedsUpdate(bool);
    5148
    5249        virtual ScriptExecutionContext* scriptExecutionContext() const;
     
    130127        void appendChild(PassRefPtr<SVGElementInstance> child);
    131128        void setShadowTreeElement(SVGElement*);
    132         void forgetWrapper();
    133129
    134130        template<class GenericNode, class GenericNodeContainer>
     
    154150        virtual EventTargetData* ensureEventTargetData();
    155151
    156         bool m_needsUpdate : 1;
    157 
    158152        SVGUseElement* m_useElement;
    159153        RefPtr<SVGElement> m_element;
  • trunk/WebCore/svg/SVGGElement.h

    r53229 r53446  
    3838        virtual ~SVGGElement();
    3939
     40        virtual bool isShadowTreeContainerElement() const { return false; }
    4041        virtual bool isValid() const { return SVGTests::isValid(); }
    4142
  • trunk/WebCore/svg/SVGStyledElement.cpp

    r52709 r53446  
    4848
    4949char SVGStyledElementIdentifier[] = "SVGStyledElement";
    50 static HashSet<const SVGStyledElement*>* gElementsWithInstanceUpdatesBlocked = 0;
    5150
    5251void mapAttributeToCSSProperty(HashMap<AtomicStringImpl*, int>* propertyNameToIdMap, const QualifiedName& attrName)
     
    6059    : SVGElement(tagName, doc)
    6160    , m_className(this, HTMLNames::classAttr)
     61    , m_instanceUpdatesBlocked(false)
    6262{
    6363}
     
    222222
    223223    if (document->parsing())
    224         return; 
     224        return;
    225225
    226226#if ENABLE(FILTERS)
     
    303303    SVGElement::detach();
    304304}
    305 
    306 void SVGStyledElement::setInstanceUpdatesBlocked(bool blockUpdates)
    307 {
    308     if (blockUpdates) {
    309         if (!gElementsWithInstanceUpdatesBlocked)
    310             gElementsWithInstanceUpdatesBlocked = new HashSet<const SVGStyledElement*>;
    311         gElementsWithInstanceUpdatesBlocked->add(this);
    312     } else {
    313         ASSERT(gElementsWithInstanceUpdatesBlocked);
    314         ASSERT(gElementsWithInstanceUpdatesBlocked->contains(this));
    315         gElementsWithInstanceUpdatesBlocked->remove(this);
    316     }
    317 }
    318305   
    319306}
  • trunk/WebCore/svg/SVGStyledElement.h

    r53229 r53446  
    5151        virtual bool rendererIsNeeded(RenderStyle*);
    5252        virtual SVGResource* canvasResource(const RenderObject*) { return 0; }
    53        
     53
    5454        virtual bool mapToEntry(const QualifiedName&, MappedAttributeEntry&) const;
    5555        virtual void parseMappedAttribute(MappedAttribute*);
    56 
    5756        virtual void svgAttributeChanged(const QualifiedName&);
    5857
     
    6665
    6766        virtual void detach();
    68                                  
    69         void setInstanceUpdatesBlocked(bool);
     67
     68        bool instanceUpdatesBlocked() const { return m_instanceUpdatesBlocked; }
     69        void setInstanceUpdatesBlocked(bool value) { m_instanceUpdatesBlocked = value; }
    7070
    7171    protected:
     
    7474    private:
    7575        ANIMATED_PROPERTY_DECLARATIONS(SVGStyledElement, SVGStyledElementIdentifier, HTMLNames::classAttrString, String, ClassName, className)
     76        bool m_instanceUpdatesBlocked;
    7677    };
    7778
  • trunk/WebCore/svg/SVGUseElement.cpp

    r53229 r53446  
    22    Copyright (C) 2004, 2005, 2006, 2007, 2008 Nikolas Zimmermann <zimmermann@kde.org>
    33                  2004, 2005, 2006, 2007 Rob Buis <buis@kde.org>
    4     Copyright (C) Research In Motion Limited 2009. All rights reserved.
     4    Copyright (C) Research In Motion Limited 2009-2010. All rights reserved.
    55
    66    This library is free software; you can redistribute it and/or
     
    3434#include "NodeRenderStyle.h"
    3535#include "RegisteredEventListener.h"
    36 #include "RenderSVGTransformableContainer.h"
     36#include "RenderSVGShadowTreeRootContainer.h"
    3737#include "SVGElementInstance.h"
    3838#include "SVGElementInstanceList.h"
     
    4040#include "SVGLength.h"
    4141#include "SVGPreserveAspectRatio.h"
     42#include "SVGShadowTreeElements.h"
    4243#include "SVGSMILElement.h"
    4344#include "SVGSVGElement.h"
     
    6667    , m_href(this, XLinkNames::hrefAttr)
    6768    , m_externalResourcesRequired(this, SVGNames::externalResourcesRequiredAttr, false)
     69    , m_isPendingResource(false)
     70    , m_needsShadowTreeRecreation(false)
    6871{
    6972}
     
    7578SVGElementInstance* SVGUseElement::instanceRoot() const
    7679{
     80    // If there is no element instance tree, force immediate SVGElementInstance tree
     81    // creation, as we can't wait for the lazy creation to happen if ie. JS wants to
     82    // access the instanceRoot object right after creating the element on-the-fly
     83    if (!m_targetElementInstance) {
     84        if (RenderSVGShadowTreeRootContainer* shadowRoot = static_cast<RenderSVGShadowTreeRootContainer*>(renderer())) {
     85            shadowRoot->markShadowTreeForRecreation();
     86            shadowRoot->updateFromElement();
     87        }
     88    }
     89
    7790    return m_targetElementInstance.get();
    7891}
     
    113126void SVGUseElement::insertedIntoDocument()
    114127{
     128    // This functions exists to assure assumptions made in the code regarding SVGElementInstance creation/destruction are satisfied.
    115129    SVGElement::insertedIntoDocument();
    116     buildPendingResource();
     130    ASSERT(!m_targetElementInstance);
     131    ASSERT(!m_isPendingResource);
    117132}
    118133
     
    120135{
    121136    m_targetElementInstance = 0;
    122     m_shadowTreeRootElement = 0;
    123137    SVGElement::removedFromDocument();
    124138}
     
    128142    SVGStyledTransformableElement::svgAttributeChanged(attrName);
    129143
    130     if (!attached())
    131         return;
    132 
    133     if (attrName == SVGNames::xAttr || attrName == SVGNames::yAttr ||
    134         attrName == SVGNames::widthAttr || attrName == SVGNames::heightAttr ||
    135         SVGTests::isKnownAttribute(attrName) ||
    136         SVGLangSpace::isKnownAttribute(attrName) ||
    137         SVGExternalResourcesRequired::isKnownAttribute(attrName) ||
    138         SVGURIReference::isKnownAttribute(attrName) ||
    139         SVGStyledTransformableElement::isKnownAttribute(attrName)) {
    140         buildPendingResource();
    141 
    142         if (m_shadowTreeRootElement)
    143             m_shadowTreeRootElement->setNeedsStyleRecalc();
    144     }
    145 }
    146 
    147 void SVGUseElement::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
    148 {
    149     SVGElement::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
    150 
    151     if (!attached())
    152         return;
    153 
    154     buildPendingResource();
    155 
    156     if (m_shadowTreeRootElement)
    157         m_shadowTreeRootElement->setNeedsStyleRecalc();
    158 }
    159  
    160 static bool shadowTreeContainsChangedNodes(SVGElementInstance* target)
    161 {
    162     if (!target)      // when use is referencing an non-existing element, there will be no Instance tree built
    163         return false;
    164 
    165     if (target->needsUpdate())
    166         return true;
    167 
    168     for (SVGElementInstance* instance = target->firstChild(); instance; instance = instance->nextSibling())
    169         if (shadowTreeContainsChangedNodes(instance))
    170             return true;
    171 
    172     return false;
     144    if (!renderer())
     145        return;
     146
     147    if (SVGURIReference::isKnownAttribute(attrName)) {
     148        if (m_isPendingResource) {
     149            document()->accessSVGExtensions()->removePendingResource(m_resourceId);
     150            m_resourceId = String();
     151            m_isPendingResource = false;
     152        }
     153
     154        invalidateShadowTree();
     155        return;
     156    }
     157
     158    if (attrName == SVGNames::xAttr || attrName == SVGNames::yAttr) {
     159        updateContainerOffsets();
     160        return;
     161    }
     162
     163    // Be very careful here, if svgAttributeChanged() has been called because a SVG CSS property changed, we do NOT want to reclone the tree!
     164    if (SVGStyledElement::isKnownAttribute(attrName)) {
     165        setNeedsStyleRecalc();
     166        return;
     167    }
     168
     169    // TODO: We should be able to remove the need for width/height to require a reclone, similar to the x/y logic.
     170    if (attrName == SVGNames::widthAttr
     171        || attrName == SVGNames::heightAttr
     172        || SVGTests::isKnownAttribute(attrName)
     173        || SVGLangSpace::isKnownAttribute(attrName)
     174        || SVGExternalResourcesRequired::isKnownAttribute(attrName)
     175        || SVGStyledTransformableElement::isKnownAttribute(attrName)) {
     176        invalidateShadowTree();
     177    }
     178}
     179
     180static void updateContainerOffset(SVGElementInstance* targetInstance)
     181{
     182    // Depth-first used to write the method in early exit style, no particular other reason.
     183    for (SVGElementInstance* instance = targetInstance->firstChild(); instance; instance = instance->nextSibling())
     184        updateContainerOffset(instance);
     185
     186    SVGElement* correspondingElement = targetInstance->correspondingElement();
     187    ASSERT(correspondingElement);
     188
     189    if (!correspondingElement->hasTagName(SVGNames::useTag))
     190        return;
     191
     192    SVGElement* shadowTreeElement = targetInstance->shadowTreeElement();
     193    ASSERT(shadowTreeElement);
     194    ASSERT(shadowTreeElement->hasTagName(SVGNames::gTag));
     195
     196    if (!static_cast<SVGGElement*>(shadowTreeElement)->isShadowTreeContainerElement())
     197        return;
     198
     199    // Spec: An additional transformation translate(x,y) is appended to the end
     200    // (i.e., right-side) of the transform attribute on the generated 'g', where x
     201    // and y represent the values of the x and y attributes on the 'use' element.
     202    SVGUseElement* useElement = static_cast<SVGUseElement*>(correspondingElement);
     203    SVGShadowTreeContainerElement* containerElement = static_cast<SVGShadowTreeContainerElement*>(shadowTreeElement);
     204    containerElement->setContainerOffset(useElement->x(), useElement->y());
     205}
     206
     207void SVGUseElement::updateContainerOffsets()
     208{
     209    if (!m_targetElementInstance)
     210        return;
     211
     212    // Update root container offset (not reachable through instance tree)
     213    SVGElement* shadowRoot = m_targetElementInstance->shadowTreeElement();
     214    ASSERT(shadowRoot);
     215
     216    Node* parentNode = shadowRoot->parentNode();
     217    ASSERT(parentNode);
     218    ASSERT(parentNode->isSVGElement());
     219    ASSERT(parentNode->hasTagName(SVGNames::gTag));
     220    ASSERT(static_cast<SVGGElement*>(parentNode)->isShadowTreeContainerElement());
     221
     222    SVGShadowTreeContainerElement* containerElement = static_cast<SVGShadowTreeContainerElement*>(parentNode);
     223    containerElement->setContainerOffset(x(), y());
     224
     225    // Update whole subtree, scanning for shadow container elements, marking a cloned use subtree
     226    updateContainerOffset(m_targetElementInstance.get());
     227
     228    if (renderer())
     229        renderer()->setNeedsLayout(true);
    173230}
    174231
    175232void SVGUseElement::recalcStyle(StyleChange change)
    176233{
    177     if (attached() && needsStyleRecalc() && shadowTreeContainsChangedNodes(m_targetElementInstance.get())) {
    178         buildPendingResource();
    179 
    180         if (m_shadowTreeRootElement)
    181             m_shadowTreeRootElement->setNeedsStyleRecalc();
    182     }
    183 
    184     SVGStyledElement::recalcStyle(change);
    185 
    186     // The shadow tree root element is NOT a direct child element of us.
    187     // So we have to take care it receives style updates, manually.
    188     if (!m_shadowTreeRootElement || !m_shadowTreeRootElement->attached())
    189         return;
    190 
    191     // Mimic Element::recalcStyle(). The main difference is that we don't call attach() on the
    192     // shadow tree root element, but call attachShadowTree() here. Calling attach() will crash
    193     // as the shadow tree root element has no (direct) parent node. Yes, shadow trees are tricky.
    194     if (change >= Inherit || m_shadowTreeRootElement->needsStyleRecalc()) {
    195         RefPtr<RenderStyle> newStyle = document()->styleSelector()->styleForElement(m_shadowTreeRootElement.get());
    196         StyleChange ch = Node::diff(m_shadowTreeRootElement->renderStyle(), newStyle.get());
    197         if (ch == Detach) {
    198             ASSERT(m_shadowTreeRootElement->attached());
    199             m_shadowTreeRootElement->detach();
    200             attachShadowTree();
    201 
    202             // attach recalulates the style for all children. No need to do it twice.
    203             m_shadowTreeRootElement->setNeedsStyleRecalc(NoStyleChange);
    204             m_shadowTreeRootElement->setChildNeedsStyleRecalc(false);
    205             return;
    206         }
    207     }
    208 
    209     // Only change==Detach needs special treatment, for anything else recalcStyle() works.
    210     m_shadowTreeRootElement->recalcStyle(change);
     234    // Eventually mark shadow root element needing style recalc
     235    if (needsStyleRecalc() && m_targetElementInstance) {
     236        if (SVGElement* shadowRoot = m_targetElementInstance->shadowTreeElement())
     237            shadowRoot->setNeedsStyleRecalc();
     238    }
     239
     240    SVGStyledTransformableElement::recalcStyle(change);
     241
     242    bool needsStyleUpdate = !m_needsShadowTreeRecreation;
     243    if (m_needsShadowTreeRecreation) {
     244        static_cast<RenderSVGShadowTreeRootContainer*>(renderer())->markShadowTreeForRecreation();
     245        m_needsShadowTreeRecreation = false;
     246    }
     247
     248    RenderSVGShadowTreeRootContainer* shadowRoot = static_cast<RenderSVGShadowTreeRootContainer*>(renderer());
     249    if (!shadowRoot)
     250        return;
     251
     252    shadowRoot->updateFromElement();
     253
     254    if (!needsStyleUpdate)
     255        return;
     256
     257    shadowRoot->updateStyle(change);
    211258}
    212259
     
    217264    ASSERT(element);
    218265
     266    SVGElement* shadowTreeElement = targetInstance->shadowTreeElement();
     267    ASSERT(shadowTreeElement);
     268
    219269    String elementId = element->getIDAttribute();
    220270    String elementNodeName = element->nodeName();
     271    String shadowTreeElementNodeName = shadowTreeElement->nodeName();
    221272    String parentNodeName = element->parentNode() ? element->parentNode()->nodeName() : "null";
    222273    String firstChildNodeName = element->firstChild() ? element->firstChild()->nodeName() : "null";
     
    225276        text += "  ";
    226277
    227     text += String::format("SVGElementInstance this=%p, (parentNode=%s, firstChild=%s, correspondingElement=%s (%p), shadowTreeElement=%p, id=%s)\n",
    228                            targetInstance, parentNodeName.latin1().data(), firstChildNodeName.latin1().data(), elementNodeName.latin1().data(),
    229                            element, targetInstance->shadowTreeElement(), elementId.latin1().data());
     278    text += String::format("SVGElementInstance this=%p, (parentNode=%s (%p), firstChild=%s (%p), correspondingElement=%s (%p), shadowTreeElement=%s (%p), id=%s)\n",
     279                           targetInstance, parentNodeName.latin1().data(), element->parentNode(), firstChildNodeName.latin1().data(), element->firstChild(),
     280                           elementNodeName.latin1().data(), element, shadowTreeElementNodeName.latin1().data(), shadowTreeElement, elementId.latin1().data());
    230281
    231282    for (unsigned int i = 0; i < depth; ++i)
     
    283334void SVGUseElement::buildPendingResource()
    284335{
     336    // If we're called the first time (during shadow tree root creation from RenderSVGShadowTreeRootContainer)
     337    // we either determine that our target is available or not - then we add ourselves to the pending resource list
     338    // Once the pending resource appears, it will call buildPendingResource(), so we're called a second time.
    285339    String id = SVGURIReference::getTarget(href());
    286340    Element* targetElement = document()->getElementById(id);
     341    ASSERT(!m_targetElementInstance);
    287342
    288343    if (!targetElement) {
    289         // TODO: We want to deregister as pending resource, if our href() changed!
    290         // TODO: Move to svgAttributeChanged, once we're fixing use & the new dynamic update concept.
     344        if (m_isPendingResource)
     345            return;
     346
     347        m_isPendingResource = true;
     348        m_resourceId = id;
    291349        document()->accessSVGExtensions()->addPendingResource(id, this);
    292350        return;
    293351    }
     352
     353    if (m_isPendingResource) {
     354        ASSERT(!m_targetElementInstance);
     355        m_isPendingResource = false;   
     356        invalidateShadowTree();
     357    }
     358}
     359
     360void SVGUseElement::buildShadowAndInstanceTree(SVGShadowTreeRootElement* shadowRoot)
     361{
     362    String id = SVGURIReference::getTarget(href());
     363    Element* targetElement = document()->getElementById(id);
     364    ASSERT(targetElement);
    294365
    295366    // Do not build the shadow/instance tree for <use> elements living in a shadow tree.
     
    307378        target = static_cast<SVGElement*>(targetElement);
    308379
    309     if (m_targetElementInstance) {
    310         m_targetElementInstance->forgetWrapper();
     380    if (m_targetElementInstance)
    311381        m_targetElementInstance = 0;
    312     }
    313382
    314383    // Do not allow self-referencing.
    315384    // 'target' may be null, if it's a non SVG namespaced element.
    316     if (!target || target == this) {
    317         m_shadowTreeRootElement = 0;
    318         return;
    319     }
     385    if (!target || target == this)
     386        return;
    320387
    321388    // Why a seperated instance/shadow tree? SVG demands it:
     
    339406    if (foundProblem) {
    340407        m_targetElementInstance = 0;
    341         m_shadowTreeRootElement = 0;
    342408        return;
    343409    }
     
    345411    // Assure instance tree building was successfull
    346412    ASSERT(m_targetElementInstance);
     413    ASSERT(!m_targetElementInstance->shadowTreeElement());
    347414    ASSERT(m_targetElementInstance->correspondingUseElement() == this);
    348 
    349     // Safe destruction, of the old shadow tree root element
    350     if (m_shadowTreeRootElement) {
    351         m_shadowTreeRootElement->detach();
    352         m_shadowTreeRootElement = 0;
    353     }
    354 
    355     // Setup shadow tree root node
    356     m_shadowTreeRootElement = new SVGGElement(SVGNames::gTag, document());
    357     m_shadowTreeRootElement->setInDocument();
    358     m_shadowTreeRootElement->setShadowParentNode(this);
    359 
    360     // Spec: An additional transformation translate(x,y) is appended to the end
    361     // (i.e., right-side) of the transform attribute on the generated 'g', where x
    362     // and y represent the values of the x and y attributes on the 'use' element.
    363     if (x().value(this) != 0.0 || y().value(this) != 0.0) {
    364         String transformString = String::format("translate(%f, %f)", x().value(this), y().value(this));
    365         m_shadowTreeRootElement->setAttribute(SVGNames::transformAttr, transformString);
    366     }
     415    ASSERT(m_targetElementInstance->correspondingElement() == target);
    367416
    368417    // Build shadow tree from instance tree
    369418    // This also handles the special cases: <use> on <symbol>, <use> on <svg>.
    370     buildShadowTree(target, m_targetElementInstance.get());
     419    buildShadowTree(shadowRoot, target, m_targetElementInstance.get());
    371420
    372421#if ENABLE(SVG) && ENABLE(SVG_USE)
    373422    // Expand all <use> elements in the shadow tree.
    374423    // Expand means: replace the actual <use> element by what it references.
    375     expandUseElementsInShadowTree(m_shadowTreeRootElement.get());
     424    expandUseElementsInShadowTree(shadowRoot, shadowRoot);
    376425
    377426    // Expand all <symbol> elements in the shadow tree.
    378427    // Expand means: replace the actual <symbol> element by the <svg> element.
    379     expandSymbolElementsInShadowTree(m_shadowTreeRootElement.get());
    380 
     428    expandSymbolElementsInShadowTree(shadowRoot, shadowRoot);
    381429#endif
    382430
    383431    // Now that the shadow tree is completly expanded, we can associate
    384432    // shadow tree elements <-> instances in the instance tree.
    385     associateInstancesWithShadowTreeElements(m_shadowTreeRootElement->firstChild(), m_targetElementInstance.get());
     433    associateInstancesWithShadowTreeElements(shadowRoot->firstChild(), m_targetElementInstance.get());
     434
     435    // If no shadow tree element is present, this means that the reference root
     436    // element was removed, as it is disallowed (ie. <use> on <foreignObject>)
     437    // Do NOT leave an inconsistent instance tree around, instead destruct it.
     438    if (!m_targetElementInstance->shadowTreeElement()) {
     439        shadowRoot->removeAllChildren();
     440        m_targetElementInstance = 0;
     441        return;
     442    }
     443
     444    // Consistency checks - this is assumed in updateContainerOffset().
     445    ASSERT(m_targetElementInstance->shadowTreeElement()->parentNode() == shadowRoot);
    386446
    387447    // Eventually dump instance tree
     
    400460    PassRefPtr<XMLSerializer> serializer = XMLSerializer::create();
    401461
    402     String markup = serializer->serializeToString(m_shadowTreeRootElement.get(), ec);
    403     ASSERT(ec == 0);
     462    String markup = serializer->serializeToString(shadowRoot, ec);
     463    ASSERT(!ec);
    404464
    405465    fprintf(stderr, "Dumping <use> shadow tree markup:\n%s\n", markup.latin1().data());
     
    409469    transferEventListenersToShadowTree(m_targetElementInstance.get());
    410470
    411     // The DOM side is setup properly. Now we have to attach the root shadow
    412     // tree element manually - using attach() won't work for "shadow nodes".
    413     attachShadowTree();
     471    // Update container translation offsets
     472    updateContainerOffsets();
    414473}
    415474
    416475RenderObject* SVGUseElement::createRenderer(RenderArena* arena, RenderStyle*)
    417476{
    418     return new (arena) RenderSVGTransformableContainer(this);
     477    return new (arena) RenderSVGShadowTreeRootContainer(this);
     478}
     479
     480static void updateFromElementCallback(Node* node)
     481{
     482    if (RenderObject* renderer = node->renderer())
     483        renderer->updateFromElement();
    419484}
    420485
     
    423488    SVGStyledTransformableElement::attach();
    424489
    425     // If we're a pending resource, this doesn't have any effect.
    426     attachShadowTree();
     490    if (renderer())
     491        queuePostAttachCallback(updateFromElementCallback, this);
    427492}
    428493
     
    430495{
    431496    SVGStyledTransformableElement::detach();
    432 
    433     if (m_shadowTreeRootElement)
    434         m_shadowTreeRootElement->detach();
     497    m_targetElementInstance = 0;
    435498}
    436499
     
    448511Path SVGUseElement::toClipPath() const
    449512{
    450     if (!m_shadowTreeRootElement)
    451         const_cast<SVGUseElement*>(this)->buildPendingResource();
    452 
    453     if (!m_shadowTreeRootElement)
     513    Node* n = m_targetElementInstance ? m_targetElementInstance->shadowTreeElement() : 0;
     514    if (!n)
    454515        return Path();
    455516
    456     Node* n = m_shadowTreeRootElement->firstChild();
    457517    if (n->isSVGElement() && static_cast<SVGElement*>(n)->isStyledTransformable()) {
    458518        if (!isDirectReference(n))
     
    488548
    489549        // Create SVGElementInstance object, for both container/non-container nodes.
    490         RefPtr<SVGElementInstance> instancePtr = SVGElementInstance::create(this, element);
    491         targetInstance->appendChild(instancePtr.get());
     550        RefPtr<SVGElementInstance> instance = SVGElementInstance::create(this, element);
     551        SVGElementInstance* instancePtr = instance.get();
     552        targetInstance->appendChild(instance.release());
    492553
    493554        // Enter recursion, appending new instance tree nodes to the "instance" object.
    494         buildInstanceTree(element, instancePtr.get(), foundProblem);
     555        buildInstanceTree(element, instancePtr, foundProblem);
    495556    }
    496557
     
    533594    // Create an instance object, even if we're dealing with a cycle
    534595    RefPtr<SVGElementInstance> newInstance = SVGElementInstance::create(this, target);
    535     targetInstance->appendChild(newInstance);
     596    SVGElementInstance* newInstancePtr = newInstance.get();
     597    targetInstance->appendChild(newInstance.release());
    536598
    537599    // Eventually enter recursion to build SVGElementInstance objects for the sub-tree children
    538     buildInstanceTree(target, newInstance.get(), foundProblem);
     600    buildInstanceTree(target, newInstancePtr, foundProblem);
    539601}
    540602
     
    567629}
    568630
    569 void SVGUseElement::buildShadowTree(SVGElement* target, SVGElementInstance* targetInstance)
     631void SVGUseElement::buildShadowTree(SVGShadowTreeRootElement* shadowRoot, SVGElement* target, SVGElementInstance* targetInstance)
    570632{
    571633    // For instance <use> on <foreignObject> (direct case).
     
    589651
    590652    ExceptionCode ec = 0;
    591     m_shadowTreeRootElement->appendChild(newChild.release(), ec);
    592     ASSERT(ec == 0);
     653    shadowRoot->appendChild(newChild.release(), ec);
     654    ASSERT(!ec);
    593655
    594656    // Handle use referencing <svg> special case
     
    598660
    599661#if ENABLE(SVG) && ENABLE(SVG_USE)
    600 void SVGUseElement::expandUseElementsInShadowTree(Node* element)
     662void SVGUseElement::expandUseElementsInShadowTree(SVGShadowTreeRootElement* shadowRoot, Node* element)
    601663{
    602664    // Why expand the <use> elements in the shadow tree here, and not just
     
    619681        if (target) {
    620682            // Setup sub-shadow tree root node
    621             RefPtr<SVGElement> cloneParent = new SVGGElement(SVGNames::gTag, document());
     683            RefPtr<SVGShadowTreeContainerElement> cloneParent = new SVGShadowTreeContainerElement(document());
    622684
    623685            // Spec: In the generated content, the 'use' will be replaced by 'g', where all attributes from the
     
    625687            transferUseAttributesToReplacedElement(use, cloneParent.get());
    626688
    627             // Spec: An additional transformation translate(x,y) is appended to the end
    628             // (i.e., right-side) of the transform attribute on the generated 'g', where x
    629             // and y represent the values of the x and y attributes on the 'use' element.
    630             if (use->x().value(this) != 0.0 || use->y().value(this) != 0.0) {
    631                 if (!cloneParent->hasAttribute(SVGNames::transformAttr)) {
    632                     String transformString = String::format("translate(%f, %f)", use->x().value(this), use->y().value(this));
    633                     cloneParent->setAttribute(SVGNames::transformAttr, transformString);
    634                 } else {
    635                     String transformString = String::format(" translate(%f, %f)", use->x().value(this), use->y().value(this));
    636                     const AtomicString& transformAttribute = cloneParent->getAttribute(SVGNames::transformAttr);
    637                     cloneParent->setAttribute(SVGNames::transformAttr, transformAttribute + transformString);
    638                 }
    639             }
    640 
    641689            ExceptionCode ec = 0;
    642  
     690
    643691            // For instance <use> on <foreignObject> (direct case).
    644692            if (isDisallowedElement(target)) {
     
    648696                ASSERT(use->parentNode());
    649697                use->parentNode()->replaceChild(cloneParent.release(), use, ec);
    650                 ASSERT(ec == 0);
     698                ASSERT(!ec);
    651699                return;
    652700            }
     
    668716
    669717            cloneParent->appendChild(newChild.release(), ec);
    670             ASSERT(ec == 0);
     718            ASSERT(!ec);
    671719
    672720            // Replace <use> with referenced content.
    673721            ASSERT(use->parentNode());
    674722            use->parentNode()->replaceChild(cloneParent.release(), use, ec);
    675             ASSERT(ec == 0);
     723            ASSERT(!ec);
    676724
    677725            // Handle use referencing <svg> special case
     
    680728
    681729            // Immediately stop here, and restart expanding.
    682             expandUseElementsInShadowTree(m_shadowTreeRootElement.get());
     730            expandUseElementsInShadowTree(shadowRoot, shadowRoot);
    683731            return;
    684732        }
     
    686734
    687735    for (RefPtr<Node> child = element->firstChild(); child; child = child->nextSibling())
    688         expandUseElementsInShadowTree(child.get());
    689 }
    690 
    691 void SVGUseElement::expandSymbolElementsInShadowTree(Node* element)
     736        expandUseElementsInShadowTree(shadowRoot, child.get());
     737}
     738
     739void SVGUseElement::expandSymbolElementsInShadowTree(SVGShadowTreeRootElement* shadowRoot, Node* element)
    692740{
    693741    if (element->hasTagName(SVGNames::symbolTag)) {
     
    716764            RefPtr<Node> newChild = child->cloneNode(true);
    717765            svgElement->appendChild(newChild.release(), ec);
    718             ASSERT(ec == 0);
     766            ASSERT(!ec);
    719767        }
    720768   
     
    730778        ASSERT(element->parentNode());
    731779        element->parentNode()->replaceChild(svgElement.release(), element, ec);
    732         ASSERT(ec == 0);
     780        ASSERT(!ec);
    733781
    734782        // Immediately stop here, and restart expanding.
    735         expandSymbolElementsInShadowTree(m_shadowTreeRootElement.get());
     783        expandSymbolElementsInShadowTree(shadowRoot, shadowRoot);
    736784        return;
    737785    }
    738786
    739787    for (RefPtr<Node> child = element->firstChild(); child; child = child->nextSibling())
    740         expandSymbolElementsInShadowTree(child.get());
     788        expandSymbolElementsInShadowTree(shadowRoot, child.get());
    741789}
    742790
    743791#endif
    744    
    745 void SVGUseElement::attachShadowTree()
    746 {
    747     if (!m_shadowTreeRootElement || m_shadowTreeRootElement->attached() || !document()->shouldCreateRenderers() || !attached() || !renderer())
    748         return;
    749 
    750     // Inspired by RenderTextControl::createSubtreeIfNeeded().
    751     if (renderer()->canHaveChildren() && childShouldCreateRenderer(m_shadowTreeRootElement.get())) {
    752         RefPtr<RenderStyle> style = m_shadowTreeRootElement->styleForRenderer();
    753 
    754         if (m_shadowTreeRootElement->rendererIsNeeded(style.get())) {
    755             m_shadowTreeRootElement->setRenderer(m_shadowTreeRootElement->createRenderer(document()->renderArena(), style.get()));
    756             if (RenderObject* shadowRenderer = m_shadowTreeRootElement->renderer()) {
    757                 shadowRenderer->setStyle(style.release());
    758                 renderer()->addChild(shadowRenderer, m_shadowTreeRootElement->nextRenderer());
    759                 m_shadowTreeRootElement->setAttached();
    760             }
    761         }
    762 
    763         // This will take care of attaching all shadow tree child nodes.
    764         for (Node* child = m_shadowTreeRootElement->firstChild(); child; child = child->nextSibling())
    765             child->attach();
    766     }
    767 }
    768  
     792
    769793void SVGUseElement::transferEventListenersToShadowTree(SVGElementInstance* target)
    770794{
     
    854878
    855879    for (SVGElementInstance* current = instance->firstChild(); current; current = current->nextSibling()) {
    856         SVGElementInstance* search = instanceForShadowTreeElement(element, current);
    857         if (search)
     880        if (SVGElementInstance* search = instanceForShadowTreeElement(element, current))
    858881            return search;
    859882    }
    860883
    861884    return 0;
     885}
     886
     887void SVGUseElement::invalidateShadowTree()
     888{
     889    m_needsShadowTreeRecreation = true;
     890    setNeedsStyleRecalc();
    862891}
    863892
     
    872901
    873902    to->removeAttribute(SVGNames::xAttr, ec);
    874     ASSERT(ec == 0);
     903    ASSERT(!ec);
    875904
    876905    to->removeAttribute(SVGNames::yAttr, ec);
    877     ASSERT(ec == 0);
     906    ASSERT(!ec);
    878907
    879908    to->removeAttribute(SVGNames::widthAttr, ec);
    880     ASSERT(ec == 0);
     909    ASSERT(!ec);
    881910
    882911    to->removeAttribute(SVGNames::heightAttr, ec);
    883     ASSERT(ec == 0);
     912    ASSERT(!ec);
    884913
    885914    to->removeAttribute(XLinkNames::hrefAttr, ec);
    886     ASSERT(ec == 0);
     915    ASSERT(!ec);
    887916}
    888917
  • trunk/WebCore/svg/SVGUseElement.h

    r53229 r53446  
    3333    class SVGElementInstance;
    3434    class SVGLength;
     35    class SVGShadowTreeRootElement;
    3536
    3637    class SVGUseElement : public SVGStyledTransformableElement,
     
    5354
    5455        virtual void parseMappedAttribute(MappedAttribute*);
    55         virtual void childrenChanged(bool changedByParser = false, Node* beforeChange = 0, Node* afterChange = 0, int childCountDelta = 0);
     56        virtual void svgAttributeChanged(const QualifiedName&);
    5657
    57         virtual void svgAttributeChanged(const QualifiedName&);
    5858        virtual void recalcStyle(StyleChange = NoChange);
    59 
    6059        virtual RenderObject* createRenderer(RenderArena*, RenderStyle*);
    6160        virtual void attach();
     
    6665        static void removeDisallowedElementsFromSubtree(Node* element);
    6766        SVGElementInstance* instanceForShadowTreeElement(Node* element) const;
     67        void invalidateShadowTree();
     68
     69    private:
     70        friend class RenderSVGShadowTreeRootContainer;
     71        bool isPendingResource() const { return m_isPendingResource; }
     72        void buildShadowAndInstanceTree(SVGShadowTreeRootElement*);
    6873
    6974    private:
     
    8994
    9095        // Shadow tree handling
    91         PassRefPtr<SVGSVGElement> buildShadowTreeForSymbolTag(SVGElement* target, SVGElementInstance* targetInstance);
    92         void alterShadowTreeForSVGTag(SVGElement* target);
    93 
    94         void buildShadowTree(SVGElement* target, SVGElementInstance* targetInstance);
     96        void alterShadowTreeForSVGTag(SVGElement*);
     97        void buildShadowTree(SVGShadowTreeRootElement*, SVGElement* target, SVGElementInstance* targetInstance);
    9598
    9699#if ENABLE(SVG) && ENABLE(SVG_USE)
    97         void expandUseElementsInShadowTree(Node* element);
    98         void expandSymbolElementsInShadowTree(Node* element);
     100        void expandUseElementsInShadowTree(SVGShadowTreeRootElement*, Node* element);
     101        void expandSymbolElementsInShadowTree(SVGShadowTreeRootElement*, Node* element);
    99102#endif
    100 
    101         void attachShadowTree();
    102103
    103104        // "Tree connector"
     
    107108        void transferUseAttributesToReplacedElement(SVGElement* from, SVGElement* to) const;
    108109        void transferEventListenersToShadowTree(SVGElementInstance* target);
     110        void updateContainerOffsets();
    109111
    110         RefPtr<SVGElement> m_shadowTreeRootElement;
     112        bool m_isPendingResource;
     113        bool m_needsShadowTreeRecreation;
     114        String m_resourceId;
    111115        RefPtr<SVGElementInstance> m_targetElementInstance;
    112116    };
Note: See TracChangeset for help on using the changeset viewer.