REGRESSION(r105057): Infinite loop inside SVGTextLayoutEngine::currentLogicalCharacte...
authorzimmermann@webkit.org <zimmermann@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 16 May 2012 07:21:07 +0000 (07:21 +0000)
committerzimmermann@webkit.org <zimmermann@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 16 May 2012 07:21:07 +0000 (07:21 +0000)
https://bugs.webkit.org/show_bug.cgi?id=83405

Reviewed by Darin Adler.

Source/WebCore:

Dynamically adding tspans carrying position information in the x/y/dx/dy/rotate lists is broken.
To avoid mistakes like this in future, simplify the calling code in RenderSVGInlineText and centralize
the management of all caches (text positioning element cache / metrics map / layout attributes) in
RenderSVGText. This avoids the hack in SVGRootInlineBox::computePerCharacterLayoutInformation() which
called textRoot->rebuildLayoutAttributes(), which was used to fix previous security issues with this code.
Instead correctly handle destruction of RenderSVGInlineText in RenderSVGText, keeping the m_layoutAttributes
synchronized with the current state of the render tree. Fixes highcharts problems.

Tests: svg/text/add-tspan-position-bug.html
       svg/text/highcharts-assertion.html
       svg/text/modify-tspan-position-bug.html

* rendering/svg/RenderSVGBlock.h:
(RenderSVGBlock):
* rendering/svg/RenderSVGInline.cpp:
(WebCore::RenderSVGInline::addChild):
(WebCore::RenderSVGInline::removeChild):
* rendering/svg/RenderSVGInline.h:
(RenderSVGInline):
* rendering/svg/RenderSVGInlineText.cpp:
(WebCore::RenderSVGInlineText::setTextInternal):
(WebCore::RenderSVGInlineText::styleDidChange):
* rendering/svg/RenderSVGInlineText.h:
* rendering/svg/RenderSVGText.cpp:
(WebCore::RenderSVGText::RenderSVGText):
(WebCore::RenderSVGText::~RenderSVGText):
(WebCore::collectLayoutAttributes):
(WebCore::RenderSVGText::subtreeChildWasAdded):
(WebCore::findPreviousAndNextAttributes):
(WebCore::checkLayoutAttributesConsistency):
(WebCore::RenderSVGText::willBeDestroyed):
(WebCore::RenderSVGText::subtreeChildWillBeRemoved):
(WebCore::RenderSVGText::subtreeChildWasRemoved):
(WebCore::RenderSVGText::subtreeStyleDidChange):
(WebCore::RenderSVGText::subtreeTextDidChange):
(WebCore::updateFontInAllDescendants):
(WebCore::RenderSVGText::layout):
(WebCore::RenderSVGText::addChild):
(WebCore::RenderSVGText::removeChild):
* rendering/svg/RenderSVGText.h:
(RenderSVGText):
* rendering/svg/SVGRenderSupport.cpp:
(WebCore::SVGRenderSupport::layoutChildren):
* rendering/svg/SVGRootInlineBox.cpp:
(WebCore::SVGRootInlineBox::computePerCharacterLayoutInformation):
* rendering/svg/SVGTextLayoutAttributesBuilder.cpp:
(WebCore::SVGTextLayoutAttributesBuilder::buildLayoutAttributesForTextRenderer):
(WebCore::SVGTextLayoutAttributesBuilder::buildLayoutAttributesForWholeTree):
(WebCore::SVGTextLayoutAttributesBuilder::rebuildMetricsForTextRenderer):
(WebCore::SVGTextLayoutAttributesBuilder::buildCharacterDataMap):
* rendering/svg/SVGTextLayoutAttributesBuilder.h:
(SVGTextLayoutAttributesBuilder):
(WebCore::SVGTextLayoutAttributesBuilder::numberOfTextPositioningElements):
* svg/SVGAElement.cpp:
* svg/SVGAElement.h:
(SVGAElement):
* svg/SVGTextContentElement.cpp:
* svg/SVGTextContentElement.h:
(SVGTextContentElement):

LayoutTests:

Add three new testcases covering the problem.

* svg/text/add-tspan-position-bug-expected.html: Added.
* svg/text/add-tspan-position-bug.html: Added.
* svg/text/highcharts-assertion-expected.txt: Added.
* svg/text/highcharts-assertion.html: Added.
* svg/text/modify-tspan-position-bug-expected.html: Added.
* svg/text/modify-tspan-position-bug.html: Added.

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

23 files changed:
LayoutTests/ChangeLog
LayoutTests/svg/text/add-tspan-position-bug-expected.html [new file with mode: 0644]
LayoutTests/svg/text/add-tspan-position-bug.html [new file with mode: 0644]
LayoutTests/svg/text/highcharts-assertion-expected.txt [new file with mode: 0644]
LayoutTests/svg/text/highcharts-assertion.html [new file with mode: 0644]
LayoutTests/svg/text/modify-tspan-position-bug-expected.html [new file with mode: 0644]
LayoutTests/svg/text/modify-tspan-position-bug.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/rendering/svg/RenderSVGBlock.h
Source/WebCore/rendering/svg/RenderSVGInline.cpp
Source/WebCore/rendering/svg/RenderSVGInline.h
Source/WebCore/rendering/svg/RenderSVGInlineText.cpp
Source/WebCore/rendering/svg/RenderSVGInlineText.h
Source/WebCore/rendering/svg/RenderSVGText.cpp
Source/WebCore/rendering/svg/RenderSVGText.h
Source/WebCore/rendering/svg/SVGRenderSupport.cpp
Source/WebCore/rendering/svg/SVGRootInlineBox.cpp
Source/WebCore/rendering/svg/SVGTextLayoutAttributesBuilder.cpp
Source/WebCore/rendering/svg/SVGTextLayoutAttributesBuilder.h
Source/WebCore/svg/SVGAElement.cpp
Source/WebCore/svg/SVGAElement.h
Source/WebCore/svg/SVGTextContentElement.cpp
Source/WebCore/svg/SVGTextContentElement.h

index 08f91c9..98357ee 100644 (file)
@@ -1,3 +1,19 @@
+2012-05-16  Nikolas Zimmermann  <nzimmermann@rim.com>
+
+        REGRESSION(r105057): Infinite loop inside SVGTextLayoutEngine::currentLogicalCharacterMetrics
+        https://bugs.webkit.org/show_bug.cgi?id=83405
+
+        Reviewed by Darin Adler.
+
+        Add three new testcases covering the problem.
+
+        * svg/text/add-tspan-position-bug-expected.html: Added.
+        * svg/text/add-tspan-position-bug.html: Added.
+        * svg/text/highcharts-assertion-expected.txt: Added.
+        * svg/text/highcharts-assertion.html: Added.
+        * svg/text/modify-tspan-position-bug-expected.html: Added.
+        * svg/text/modify-tspan-position-bug.html: Added.
+
 2012-05-15  Abhishek Arya  <inferno@chromium.org>
 
         Crash in Document::nodeChildrenWillBeRemoved.
diff --git a/LayoutTests/svg/text/add-tspan-position-bug-expected.html b/LayoutTests/svg/text/add-tspan-position-bug-expected.html
new file mode 100644 (file)
index 0000000..d1f889b
--- /dev/null
@@ -0,0 +1,8 @@
+<!DOCTYPE html>
+<html>
+<body>
+<svg>
+<text id="text" y="50"><tspan>Should be on</tspan><tspan dy="30">different lines</tspan></text>
+</svg>
+</body>
+</html>
diff --git a/LayoutTests/svg/text/add-tspan-position-bug.html b/LayoutTests/svg/text/add-tspan-position-bug.html
new file mode 100644 (file)
index 0000000..d33c57f
--- /dev/null
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<html>
+<body onload="loaded()">
+<svg>
+<title>This test used to be laid out on a single line, instead of multiple ones</title>
+<text id="text" y="50"></text>
+
+<script>
+var text = document.getElementsByTagName("text")[0];
+
+function addSpans() {
+    var tspan1 = document.createElementNS("http://www.w3.org/2000/svg", "tspan");
+    tspan1.appendChild(document.createTextNode("Should be on"));
+
+    var tspan2 = document.createElementNS("http://www.w3.org/2000/svg", "tspan");
+    tspan2.setAttribute("dy", "30");
+    tspan2.appendChild(document.createTextNode("different lines"));
+
+    text.appendChild(tspan1);
+    text.appendChild(tspan2);
+
+    if (window.layoutTestController)
+        layoutTestController.notifyDone();
+}
+
+if (window.layoutTestController)
+    layoutTestController.waitUntilDone();
+
+function loaded() {
+    // Bug is only trigger from another loop.
+    setTimeout(addSpans, 0);
+}
+</script>
+</svg>
+</body>
+</html>
diff --git a/LayoutTests/svg/text/highcharts-assertion-expected.txt b/LayoutTests/svg/text/highcharts-assertion-expected.txt
new file mode 100644 (file)
index 0000000..69cfc5a
--- /dev/null
@@ -0,0 +1,2 @@
+PASS
+
diff --git a/LayoutTests/svg/text/highcharts-assertion.html b/LayoutTests/svg/text/highcharts-assertion.html
new file mode 100644 (file)
index 0000000..3384e54
--- /dev/null
@@ -0,0 +1,14 @@
+<html>
+<head>
+    <title>This test passes if it doesn't crash</title>
+    <script>
+        if (window.layoutTestController)
+            layoutTestController.dumpAsText();
+    </script>
+</head>
+<body>
+<svg>
+    <text y="50"><tspan> </tspan><script>document.body.offsetTop;</script><tspan>PASS</tspan></text>
+</svg>
+</body>
+</html
diff --git a/LayoutTests/svg/text/modify-tspan-position-bug-expected.html b/LayoutTests/svg/text/modify-tspan-position-bug-expected.html
new file mode 100644 (file)
index 0000000..d1f889b
--- /dev/null
@@ -0,0 +1,8 @@
+<!DOCTYPE html>
+<html>
+<body>
+<svg>
+<text id="text" y="50"><tspan>Should be on</tspan><tspan dy="30">different lines</tspan></text>
+</svg>
+</body>
+</html>
diff --git a/LayoutTests/svg/text/modify-tspan-position-bug.html b/LayoutTests/svg/text/modify-tspan-position-bug.html
new file mode 100644 (file)
index 0000000..4ea9d07
--- /dev/null
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<html>
+<body onload="loaded()">
+<svg>
+<title>This test used to be laid out on a single line, instead of multiple ones</title>
+<text id="text" y="50"></text>
+
+<script>
+var text = document.getElementsByTagName("text")[0];
+
+function addSpans() {
+    var tspan1 = document.createElementNS("http://www.w3.org/2000/svg", "tspan");
+    tspan1.appendChild(document.createTextNode("Should be on"));
+
+    tspan2 = document.createElementNS("http://www.w3.org/2000/svg", "tspan");
+    tspan2.appendChild(document.createTextNode("different lines"));
+
+    text.appendChild(tspan1);
+    text.appendChild(tspan2);
+
+    // Bug is only trigger from another loop.
+    setTimeout(moveSpan, 0);
+}
+
+function moveSpan() {
+    tspan2.setAttribute("dy", "30");
+
+    if (window.layoutTestController)
+        layoutTestController.notifyDone();
+}
+
+if (window.layoutTestController)
+    layoutTestController.waitUntilDone();
+
+function loaded() {
+    // Bug is only trigger from another loop.
+    setTimeout(addSpans, 0);
+}
+</script>
+</svg>
+</body>
+</html>
index e64f9ef..c386286 100644 (file)
@@ -1,3 +1,70 @@
+2012-05-16  Nikolas Zimmermann  <nzimmermann@rim.com>
+
+        REGRESSION(r105057): Infinite loop inside SVGTextLayoutEngine::currentLogicalCharacterMetrics
+        https://bugs.webkit.org/show_bug.cgi?id=83405
+
+        Reviewed by Darin Adler.
+
+        Dynamically adding tspans carrying position information in the x/y/dx/dy/rotate lists is broken.
+        To avoid mistakes like this in future, simplify the calling code in RenderSVGInlineText and centralize
+        the management of all caches (text positioning element cache / metrics map / layout attributes) in
+        RenderSVGText. This avoids the hack in SVGRootInlineBox::computePerCharacterLayoutInformation() which
+        called textRoot->rebuildLayoutAttributes(), which was used to fix previous security issues with this code.
+        Instead correctly handle destruction of RenderSVGInlineText in RenderSVGText, keeping the m_layoutAttributes
+        synchronized with the current state of the render tree. Fixes highcharts problems.
+
+        Tests: svg/text/add-tspan-position-bug.html
+               svg/text/highcharts-assertion.html
+               svg/text/modify-tspan-position-bug.html
+
+        * rendering/svg/RenderSVGBlock.h:
+        (RenderSVGBlock):
+        * rendering/svg/RenderSVGInline.cpp:
+        (WebCore::RenderSVGInline::addChild):
+        (WebCore::RenderSVGInline::removeChild):
+        * rendering/svg/RenderSVGInline.h:
+        (RenderSVGInline):
+        * rendering/svg/RenderSVGInlineText.cpp:
+        (WebCore::RenderSVGInlineText::setTextInternal):
+        (WebCore::RenderSVGInlineText::styleDidChange):
+        * rendering/svg/RenderSVGInlineText.h:
+        * rendering/svg/RenderSVGText.cpp:
+        (WebCore::RenderSVGText::RenderSVGText):
+        (WebCore::RenderSVGText::~RenderSVGText):
+        (WebCore::collectLayoutAttributes):
+        (WebCore::RenderSVGText::subtreeChildWasAdded):
+        (WebCore::findPreviousAndNextAttributes):
+        (WebCore::checkLayoutAttributesConsistency):
+        (WebCore::RenderSVGText::willBeDestroyed):
+        (WebCore::RenderSVGText::subtreeChildWillBeRemoved):
+        (WebCore::RenderSVGText::subtreeChildWasRemoved):
+        (WebCore::RenderSVGText::subtreeStyleDidChange):
+        (WebCore::RenderSVGText::subtreeTextDidChange):
+        (WebCore::updateFontInAllDescendants):
+        (WebCore::RenderSVGText::layout):
+        (WebCore::RenderSVGText::addChild):
+        (WebCore::RenderSVGText::removeChild):
+        * rendering/svg/RenderSVGText.h:
+        (RenderSVGText):
+        * rendering/svg/SVGRenderSupport.cpp:
+        (WebCore::SVGRenderSupport::layoutChildren):
+        * rendering/svg/SVGRootInlineBox.cpp:
+        (WebCore::SVGRootInlineBox::computePerCharacterLayoutInformation):
+        * rendering/svg/SVGTextLayoutAttributesBuilder.cpp:
+        (WebCore::SVGTextLayoutAttributesBuilder::buildLayoutAttributesForTextRenderer):
+        (WebCore::SVGTextLayoutAttributesBuilder::buildLayoutAttributesForWholeTree):
+        (WebCore::SVGTextLayoutAttributesBuilder::rebuildMetricsForTextRenderer):
+        (WebCore::SVGTextLayoutAttributesBuilder::buildCharacterDataMap):
+        * rendering/svg/SVGTextLayoutAttributesBuilder.h:
+        (SVGTextLayoutAttributesBuilder):
+        (WebCore::SVGTextLayoutAttributesBuilder::numberOfTextPositioningElements):
+        * svg/SVGAElement.cpp:
+        * svg/SVGAElement.h:
+        (SVGAElement):
+        * svg/SVGTextContentElement.cpp:
+        * svg/SVGTextContentElement.h:
+        (SVGTextContentElement):
+
 2012-05-15  Abhishek Arya  <inferno@chromium.org>
 
         Crash in Document::nodeChildrenWillBeRemoved.
index ca000f5..9ef55a9 100644 (file)
@@ -34,13 +34,15 @@ public:
 
     virtual LayoutRect visualOverflowRect() const;
 
+protected:
+    virtual void willBeDestroyed() OVERRIDE;
+
 private:
     virtual void setStyle(PassRefPtr<RenderStyle>);
     virtual void updateBoxModelInfoFromStyle();
 
     virtual void absoluteRects(Vector<IntRect>&, const LayoutPoint& accumulatedOffset) const;
 
-    virtual void willBeDestroyed();
     virtual void styleWillChange(StyleDifference, const RenderStyle* newStyle);
     virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle);
     virtual void updateFromElement();
index ab8cc1a..77b4fe9 100644 (file)
@@ -124,7 +124,22 @@ void RenderSVGInline::addChild(RenderObject* child, RenderObject* beforeChild)
 {
     RenderInline::addChild(child, beforeChild);
     if (RenderSVGText* textRenderer = RenderSVGText::locateRenderSVGTextAncestor(this))
-        textRenderer->layoutAttributesChanged(child);
+        textRenderer->subtreeChildWasAdded(child);
+}
+
+void RenderSVGInline::removeChild(RenderObject* child)
+{
+    RenderSVGText* textRenderer = child->isSVGInlineText() ? RenderSVGText::locateRenderSVGTextAncestor(this) : 0;
+    if (!textRenderer) {
+        RenderInline::removeChild(child);
+        return;
+    }
+
+    RenderSVGInlineText* text = toRenderSVGInlineText(child);
+    Vector<SVGTextLayoutAttributes*, 2> affectedAttributes;
+    textRenderer->subtreeChildWillBeRemoved(text, affectedAttributes);
+    RenderInline::removeChild(child);
+    textRenderer->subtreeChildWasRemoved(affectedAttributes);
 }
 
 }
index 8aa4ab8..1720621 100644 (file)
@@ -57,7 +57,9 @@ private:
     virtual void styleWillChange(StyleDifference, const RenderStyle* newStyle);
     virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle);
     virtual void updateFromElement();
+
     virtual void addChild(RenderObject* child, RenderObject* beforeChild = 0);
+    virtual void removeChild(RenderObject*) OVERRIDE;
 };
 
 }
index 09d446b..eff7077 100644 (file)
@@ -72,37 +72,11 @@ RenderSVGInlineText::RenderSVGInlineText(Node* n, PassRefPtr<StringImpl> string)
 {
 }
 
-void RenderSVGInlineText::willBeDestroyed()
-{
-    RenderSVGText* textRenderer = RenderSVGText::locateRenderSVGTextAncestor(this);
-    if (!textRenderer) {
-        RenderText::willBeDestroyed();
-        return;
-    }
-
-    Vector<SVGTextLayoutAttributes*> affectedAttributes;
-    textRenderer->layoutAttributesWillBeDestroyed(this, affectedAttributes);
-
-    RenderText::willBeDestroyed();
-    if (affectedAttributes.isEmpty())
-        return;
-
-    if (!documentBeingDestroyed())
-        textRenderer->rebuildLayoutAttributes(affectedAttributes);
-}
-
 void RenderSVGInlineText::setTextInternal(PassRefPtr<StringImpl> text)
 {
     RenderText::setTextInternal(text);
-
-    // When the underlying text content changes, call both textDOMChanged() & layoutAttributesChanged()
-    // The former will clear the SVGTextPositioningElement cache, which depends on the textLength() of
-    // the RenderSVGInlineText objects, and thus needs to be rebuild. The latter will assure that the
-    // SVGTextLayoutAttributes associated with the RenderSVGInlineText will be updated.
-    if (RenderSVGText* textRenderer = RenderSVGText::locateRenderSVGTextAncestor(this)) {
-        textRenderer->invalidateTextPositioningElements();
-        textRenderer->layoutAttributesChanged(this);
-    }
+    if (RenderSVGText* textRenderer = RenderSVGText::locateRenderSVGTextAncestor(this))
+        textRenderer->subtreeTextDidChange(this);
 }
 
 void RenderSVGInlineText::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
@@ -127,7 +101,7 @@ void RenderSVGInlineText::styleDidChange(StyleDifference diff, const RenderStyle
 
     // The text metrics may be influenced by style changes.
     if (RenderSVGText* textRenderer = RenderSVGText::locateRenderSVGTextAncestor(this))
-        textRenderer->layoutAttributesChanged(this);
+        textRenderer->subtreeStyleDidChange(this);
 }
 
 InlineTextBox* RenderSVGInlineText::createTextBox()
index 51378fd..ab81ca9 100644 (file)
@@ -48,7 +48,6 @@ public:
 private:
     virtual const char* renderName() const { return "RenderSVGInlineText"; }
 
-    virtual void willBeDestroyed();
     virtual void setTextInternal(PassRefPtr<StringImpl>);
     virtual void styleDidChange(StyleDifference, const RenderStyle*);
 
index f512ab8..2bb583c 100644 (file)
@@ -57,12 +57,17 @@ namespace WebCore {
 RenderSVGText::RenderSVGText(SVGTextElement* node) 
     : RenderSVGBlock(node)
     , m_needsReordering(false)
-    , m_needsPositioningValuesUpdate(true)
+    , m_needsPositioningValuesUpdate(false)
     , m_needsTransformUpdate(true)
-    , m_needsTextMetricsUpdate(true)
+    , m_needsTextMetricsUpdate(false)
 {
 }
 
+RenderSVGText::~RenderSVGText()
+{
+    ASSERT(m_layoutAttributes.isEmpty());
+}
+
 bool RenderSVGText::isChildAllowed(RenderObject* child, RenderStyle*) const
 {
     return child->isInline();
@@ -110,31 +115,19 @@ void RenderSVGText::mapLocalToContainer(RenderBoxModelObject* repaintContainer,
     SVGRenderSupport::mapLocalToContainer(this, repaintContainer, transformState, wasFixed);
 }
 
-static inline void recursiveUpdateLayoutAttributes(RenderObject* start, SVGTextLayoutAttributesBuilder& builder)
+static inline void collectLayoutAttributes(RenderObject* text, Vector<SVGTextLayoutAttributes*>& attributes)
 {
-    if (start->isSVGInlineText()) {
-        builder.buildLayoutAttributesForTextRenderer(toRenderSVGInlineText(start));
-        return;
+    for (RenderObject* descendant = text; descendant; descendant = descendant->nextInPreOrder(text)) {
+        if (descendant->isSVGInlineText())
+            attributes.append(toRenderSVGInlineText(descendant)->layoutAttributes());
     }
-
-    for (RenderObject* child = start->firstChild(); child; child = child->nextSibling())
-        recursiveUpdateLayoutAttributes(child, builder);
-}
-
-void RenderSVGText::layoutAttributesChanged(RenderObject* child)
-{
-    ASSERT(child);
-    if (m_needsPositioningValuesUpdate)
-        return;
-    FontCachePurgePreventer fontCachePurgePreventer;
-    recursiveUpdateLayoutAttributes(child, m_layoutAttributesBuilder);
-    rebuildLayoutAttributes();
 }
 
 static inline bool findPreviousAndNextAttributes(RenderObject* start, RenderSVGInlineText* locateElement, bool& stopAfterNext, SVGTextLayoutAttributes*& previous, SVGTextLayoutAttributes*& next)
 {
     ASSERT(start);
     ASSERT(locateElement);
+    // FIXME: Make this iterative.
     for (RenderObject* child = start->firstChild(); child; child = child->nextSibling()) {
         if (child->isSVGInlineText()) {
             RenderSVGInlineText* text = toRenderSVGInlineText(child);
@@ -162,40 +155,177 @@ static inline bool findPreviousAndNextAttributes(RenderObject* start, RenderSVGI
     return false;
 }
 
-void RenderSVGText::layoutAttributesWillBeDestroyed(RenderSVGInlineText* text, Vector<SVGTextLayoutAttributes*>& affectedAttributes)
+inline bool RenderSVGText::shouldHandleSubtreeMutations() const
+{
+    if (beingDestroyed() || !everHadLayout()) {
+        ASSERT(m_layoutAttributes.isEmpty());
+        ASSERT(!m_layoutAttributesBuilder.numberOfTextPositioningElements());
+        return false;
+    }
+    return true;
+}
+
+void RenderSVGText::subtreeChildWasAdded(RenderObject* child)
+{
+    ASSERT(child);
+    if (!shouldHandleSubtreeMutations() || documentBeingDestroyed())
+        return;
+
+    // The positioning elements cache doesn't include the new 'child' yet. Clear the
+    // cache, as the next buildLayoutAttributesForTextRenderer() call rebuilds it.
+    m_layoutAttributesBuilder.clearTextPositioningElements();
+
+    // Detect changes in layout attributes and only measure those text parts that have changed!
+    Vector<SVGTextLayoutAttributes*> newLayoutAttributes;
+    collectLayoutAttributes(this, newLayoutAttributes);
+    if (newLayoutAttributes.isEmpty()) {
+        ASSERT(m_layoutAttributes.isEmpty());
+        return;
+    }
+
+    // Compare m_layoutAttributes with newLayoutAttributes to figure out which attribute got added.
+    size_t size = newLayoutAttributes.size();
+    SVGTextLayoutAttributes* attributes = 0;
+    for (size_t i = 0; i < size; ++i) {
+        attributes = newLayoutAttributes[i];
+        if (m_layoutAttributes.find(attributes) == notFound) {
+            // Every time this is invoked, there's only a single new entry in the newLayoutAttributes list, compared to the old in m_layoutAttributes.
+            bool stopAfterNext = false;
+            SVGTextLayoutAttributes* previous = 0;
+            SVGTextLayoutAttributes* next = 0;
+            ASSERT_UNUSED(child, attributes->context() == child);
+            findPreviousAndNextAttributes(this, attributes->context(), stopAfterNext, previous, next);
+
+            if (previous)
+                m_layoutAttributesBuilder.buildLayoutAttributesForTextRenderer(previous->context());
+            m_layoutAttributesBuilder.buildLayoutAttributesForTextRenderer(attributes->context());
+            if (next)
+                m_layoutAttributesBuilder.buildLayoutAttributesForTextRenderer(next->context());
+            break;
+        }
+    }
+
+#ifndef NDEBUG
+    // Verify that m_layoutAttributes only differs by a maximum of one entry.
+    for (size_t i = 0; i < size; ++i)
+        ASSERT(m_layoutAttributes.find(newLayoutAttributes[i]) != notFound || newLayoutAttributes[i] == attributes);
+#endif
+
+    m_layoutAttributes = newLayoutAttributes;
+}
+
+static inline void checkLayoutAttributesConsistency(RenderSVGText* text, Vector<SVGTextLayoutAttributes*>& expectedLayoutAttributes)
+{
+#ifndef NDEBUG
+    Vector<SVGTextLayoutAttributes*> newLayoutAttributes;
+    collectLayoutAttributes(text, newLayoutAttributes);
+    ASSERT(newLayoutAttributes == expectedLayoutAttributes);
+#else
+    UNUSED_PARAM(text);
+    UNUSED_PARAM(expectedLayoutAttributes);
+#endif
+}
+
+void RenderSVGText::willBeDestroyed()
+{
+    m_layoutAttributes.clear();
+    m_layoutAttributesBuilder.clearTextPositioningElements();
+
+    RenderSVGBlock::willBeDestroyed();
+}
+
+void RenderSVGText::subtreeChildWillBeRemoved(RenderSVGInlineText* text, Vector<SVGTextLayoutAttributes*, 2>& affectedAttributes)
 {
     ASSERT(text);
-    if (m_needsPositioningValuesUpdate)
+    if (!shouldHandleSubtreeMutations())
+        return;
+
+    checkLayoutAttributesConsistency(this, m_layoutAttributes);
+
+    // The positioning elements cache depends on the size of each text renderer in the
+    // subtree. If this changes, clear the cache. It's going to be rebuilt below.
+    m_layoutAttributesBuilder.clearTextPositioningElements();
+    if (m_layoutAttributes.isEmpty())
         return;
 
+    // This logic requires that the 'text' child is still inserted in the tree.
     bool stopAfterNext = false;
     SVGTextLayoutAttributes* previous = 0;
     SVGTextLayoutAttributes* next = 0;
-    findPreviousAndNextAttributes(this, text, stopAfterNext, previous, next);
+    if (!documentBeingDestroyed())
+        findPreviousAndNextAttributes(this, text, stopAfterNext, previous, next);
+
     if (previous)
         affectedAttributes.append(previous);
     if (next)
         affectedAttributes.append(next);
+
+    size_t position = m_layoutAttributes.find(text->layoutAttributes());
+    ASSERT(position != notFound);
+    m_layoutAttributes.remove(position);
+}
+
+void RenderSVGText::subtreeChildWasRemoved(const Vector<SVGTextLayoutAttributes*, 2>& affectedAttributes)
+{
+    if (!shouldHandleSubtreeMutations() || documentBeingDestroyed()) {
+        ASSERT(affectedAttributes.isEmpty());
+        return;
+    }
+
+    // This is called immediately after subtreeChildWillBeDestroyed, once the RenderSVGInlineText::willBeDestroyed() method
+    // passes on to the base class, which removes us from the render tree. At this point we can update the layout attributes.
+    unsigned size = affectedAttributes.size();
+    for (unsigned i = 0; i < size; ++i)
+        m_layoutAttributesBuilder.buildLayoutAttributesForTextRenderer(affectedAttributes[i]->context());
 }
 
-void RenderSVGText::invalidateTextPositioningElements()
+void RenderSVGText::subtreeStyleDidChange(RenderSVGInlineText* text)
 {
-    // Clear the text positioning elements. This should be called when either the children
-    // of a DOM text element have changed, or the length of the text in any child element
-    // has changed. Failure to clear may leave us with invalid elements, as other code paths
-    // do not always cause the position elements to be marked invalid before use.
+    ASSERT(text);
+    if (!shouldHandleSubtreeMutations() || documentBeingDestroyed())
+        return;
+
+    checkLayoutAttributesConsistency(this, m_layoutAttributes);
+
+    // Only update the metrics cache, but not the text positioning element cache
+    // nor the layout attributes cached in the leaf #text renderers.
+    FontCachePurgePreventer fontCachePurgePreventer;
+    for (RenderObject* descendant = text; descendant; descendant = descendant->nextInPreOrder(text)) {
+        if (descendant->isSVGInlineText())
+            m_layoutAttributesBuilder.rebuildMetricsForTextRenderer(toRenderSVGInlineText(descendant));
+    }
+}
+
+void RenderSVGText::subtreeTextDidChange(RenderSVGInlineText* text)
+{
+    ASSERT(text);
+    ASSERT(!beingDestroyed());
+    if (!everHadLayout()) {
+        ASSERT(m_layoutAttributes.isEmpty());
+        ASSERT(!m_layoutAttributesBuilder.numberOfTextPositioningElements());
+        return;
+    }
+
+    // The positioning elements cache depends on the size of each text renderer in the
+    // subtree. If this changes, clear the cache. It's going to be rebuilt below.
     m_layoutAttributesBuilder.clearTextPositioningElements();
+
+    checkLayoutAttributesConsistency(this, m_layoutAttributes);
+    for (RenderObject* descendant = text; descendant; descendant = descendant->nextInPreOrder(text)) {
+        if (descendant->isSVGInlineText())
+            m_layoutAttributesBuilder.buildLayoutAttributesForTextRenderer(toRenderSVGInlineText(descendant));
+    }
 }
 
-static inline void recursiveUpdateScaledFont(RenderObject* start)
+static inline void updateFontInAllDescendants(RenderObject* start, SVGTextLayoutAttributesBuilder* builder = 0)
 {
-    for (RenderObject* child = start->firstChild(); child; child = child->nextSibling()) {
-        if (child->isSVGInlineText()) {
-            toRenderSVGInlineText(child)->updateScaledFont();
+    for (RenderObject* descendant = start; descendant; descendant = descendant->nextInPreOrder(start)) {
+        if (!descendant->isSVGInlineText())
             continue;
-        }
-
-        recursiveUpdateScaledFont(child);
+        RenderSVGInlineText* text = toRenderSVGInlineText(descendant);
+        text->updateScaledFont();
+        if (builder)
+            builder->rebuildMetricsForTextRenderer(text);
     }
 }
 
@@ -212,23 +342,43 @@ void RenderSVGText::layout()
         updateCachedBoundariesInParents = true;
     }
 
-    // If the root layout size changed (eg. window size changes) or the positioning values change
-    // or the transform to the root context has changed then recompute the on-screen font size.
-    if (m_needsTextMetricsUpdate || SVGRenderSupport::findTreeRootObject(this)->isLayoutSizeChanged()) {
-        recursiveUpdateScaledFont(this);
-        rebuildLayoutAttributes(true);
-        updateCachedBoundariesInParents = true;
+    if (!everHadLayout()) {
+        // When laying out initially, collect all layout attributes, build the character data map,
+        // and propogate resulting SVGLayoutAttributes to all RenderSVGInlineText children in the subtree.
+        ASSERT(m_layoutAttributes.isEmpty());
+        collectLayoutAttributes(this, m_layoutAttributes);
+        updateFontInAllDescendants(this);
+        m_layoutAttributesBuilder.buildLayoutAttributesForForSubtree(this);
+
+        m_needsReordering = true;
         m_needsTextMetricsUpdate = false;
-    }
+        m_needsPositioningValuesUpdate = false;
+        updateCachedBoundariesInParents = true;
+    } else if (m_needsPositioningValuesUpdate) {
+        // When the x/y/dx/dy/rotate lists change, recompute the layout attributes, and eventually
+        // update the on-screen font objects as well in all descendants.
+        if (m_needsTextMetricsUpdate) {
+            updateFontInAllDescendants(this);
+            m_needsTextMetricsUpdate = false;
+        }
 
-    if (m_needsPositioningValuesUpdate) {
-        // Perform SVG text layout phase one (see SVGTextLayoutAttributesBuilder for details).
-        m_layoutAttributesBuilder.buildLayoutAttributesForWholeTree(this);
+        m_layoutAttributesBuilder.buildLayoutAttributesForForSubtree(this);
         m_needsReordering = true;
         m_needsPositioningValuesUpdate = false;
         updateCachedBoundariesInParents = true;
+    } else if (m_needsTextMetricsUpdate || SVGRenderSupport::findTreeRootObject(this)->isLayoutSizeChanged()) {
+        // If the root layout size changed (eg. window size changes) or the transform to the root
+        // context has changed then recompute the on-screen font size.
+        updateFontInAllDescendants(this, &m_layoutAttributesBuilder);
+
+        ASSERT(!m_needsReordering);
+        ASSERT(!m_needsPositioningValuesUpdate);
+        m_needsTextMetricsUpdate = false;
+        updateCachedBoundariesInParents = true;
     }
 
+    checkLayoutAttributesConsistency(this, m_layoutAttributes);
+
     // Reduced version of RenderBlock::layoutBlock(), which only takes care of SVG text.
     // All if branches that could cause early exit in RenderBlocks layoutBlock() method are turned into assertions.
     ASSERT(!isInline());
@@ -364,7 +514,21 @@ FloatRect RenderSVGText::repaintRectInLocalCoordinates() const
 void RenderSVGText::addChild(RenderObject* child, RenderObject* beforeChild)
 {
     RenderSVGBlock::addChild(child, beforeChild);
-    layoutAttributesChanged(child);
+    subtreeChildWasAdded(child);
+}
+
+void RenderSVGText::removeChild(RenderObject* child)
+{
+    if (!child->isSVGInlineText()) {
+        RenderSVGBlock::removeChild(child);
+        return;
+    }
+
+    RenderSVGInlineText* text = toRenderSVGInlineText(child);
+    Vector<SVGTextLayoutAttributes*, 2> affectedAttributes;
+    subtreeChildWillBeRemoved(text, affectedAttributes);
+    RenderSVGBlock::removeChild(child);
+    subtreeChildWasRemoved(affectedAttributes);
 }
 
 // Fix for <rdar://problem/8048875>. We should not render :first-line CSS Style
@@ -380,61 +544,6 @@ void RenderSVGText::updateFirstLetter()
 {
 }
 
-static inline void recursiveCollectLayoutAttributes(RenderObject* start, Vector<SVGTextLayoutAttributes*>& attributes)
-{
-    for (RenderObject* child = start->firstChild(); child; child = child->nextSibling()) {
-        if (child->isSVGInlineText()) {
-            attributes.append(toRenderSVGInlineText(child)->layoutAttributes());
-            continue;
-        }
-
-        recursiveCollectLayoutAttributes(child, attributes);
-    }
-}
-
-void RenderSVGText::rebuildLayoutAttributes(bool performFullRebuild)
-{
-    if (performFullRebuild)
-        m_layoutAttributes.clear();
-
-    if (m_layoutAttributes.isEmpty()) {
-        recursiveCollectLayoutAttributes(this, m_layoutAttributes);
-        if (m_layoutAttributes.isEmpty() || !performFullRebuild)
-            return;
-
-        m_layoutAttributesBuilder.rebuildMetricsForWholeTree(this);
-        return;
-    }
-
-    Vector<SVGTextLayoutAttributes*> affectedAttributes;
-    rebuildLayoutAttributes(affectedAttributes);
-}
-
-void RenderSVGText::rebuildLayoutAttributes(Vector<SVGTextLayoutAttributes*>& affectedAttributes)
-{
-    // Detect changes in layout attributes and only measure those text parts that have changed!
-    Vector<SVGTextLayoutAttributes*> newLayoutAttributes;
-    recursiveCollectLayoutAttributes(this, newLayoutAttributes);
-    if (newLayoutAttributes.isEmpty()) {
-        m_layoutAttributes.clear();
-        return;
-    }
-
-    // Compare m_layoutAttributes with newLayoutAttributes to figure out which attributes got added/removed.
-    size_t size = newLayoutAttributes.size();
-    for (size_t i = 0; i < size; ++i) {
-        SVGTextLayoutAttributes* attributes = newLayoutAttributes[i];
-        if (m_layoutAttributes.find(attributes) == notFound)
-            m_layoutAttributesBuilder.rebuildMetricsForTextRenderer(attributes->context());
-    }
-
-    size = affectedAttributes.size();
-    for (size_t i = 0; i < size; ++i)
-        m_layoutAttributesBuilder.rebuildMetricsForTextRenderer(affectedAttributes[i]->context());
-
-    m_layoutAttributes = newLayoutAttributes;
-}
-
 }
 
 #endif // ENABLE(SVG)
index 5665b44..ee7b3d0 100644 (file)
@@ -36,6 +36,7 @@ class RenderSVGInlineText;
 class RenderSVGText : public RenderSVGBlock {
 public:
     RenderSVGText(SVGTextElement*);
+    virtual ~RenderSVGText();
 
     virtual bool isChildAllowed(RenderObject*, RenderStyle*) const;
 
@@ -48,18 +49,14 @@ public:
     static const RenderSVGText* locateRenderSVGTextAncestor(const RenderObject*);
 
     bool needsReordering() const { return m_needsReordering; }
-
-    // Call this method when either the children of a DOM text element have changed, or the length of
-    // the text in any child element has changed.
-    void invalidateTextPositioningElements();
-
-    void layoutAttributesChanged(RenderObject*);
-    void layoutAttributesWillBeDestroyed(RenderSVGInlineText*, Vector<SVGTextLayoutAttributes*>& affectedAttributes);
-    void rebuildLayoutAttributes(bool performFullRebuild = false);
-    void rebuildLayoutAttributes(Vector<SVGTextLayoutAttributes*>& affectedAttributes);
-
     Vector<SVGTextLayoutAttributes*>& layoutAttributes() { return m_layoutAttributes; }
 
+    void subtreeChildWasAdded(RenderObject*);
+    void subtreeChildWillBeRemoved(RenderSVGInlineText*, Vector<SVGTextLayoutAttributes*, 2>& affectedAttributes);
+    void subtreeChildWasRemoved(const Vector<SVGTextLayoutAttributes*, 2>& affectedAttributes);
+    void subtreeStyleDidChange(RenderSVGInlineText*);
+    void subtreeTextDidChange(RenderSVGInlineText*);
+
 private:
     virtual const char* renderName() const { return "RenderSVGText"; }
     virtual bool isSVGText() const { return true; }
@@ -80,6 +77,8 @@ private:
 
     virtual void mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool useTransforms, bool fixed, TransformState&, ApplyContainerFlipOrNot = ApplyContainerFlip, bool* wasFixed = 0) const;
     virtual void addChild(RenderObject* child, RenderObject* beforeChild = 0);
+    virtual void removeChild(RenderObject*) OVERRIDE;
+    virtual void willBeDestroyed() OVERRIDE;
 
     virtual FloatRect objectBoundingBox() const { return frameRect(); }
     virtual FloatRect strokeBoundingBox() const;
@@ -91,6 +90,8 @@ private:
     virtual RenderBlock* firstLineBlock() const;
     virtual void updateFirstLetter();
 
+    bool shouldHandleSubtreeMutations() const;
+
     bool m_needsReordering : 1;
     bool m_needsPositioningValuesUpdate : 1;
     bool m_needsTransformUpdate : 1;
index b206cb6..ddc7c91 100644 (file)
@@ -197,8 +197,10 @@ void SVGRenderSupport::layoutChildren(RenderObject* start, bool selfNeedsLayout)
                     // When the layout size changed and when using relative values tell the RenderSVGShape to update its shape object
                     if (child->isSVGShape())
                         toRenderSVGShape(child)->setNeedsShapeUpdate();
-                    else if (child->isSVGText())
+                    else if (child->isSVGText()) {
+                        toRenderSVGText(child)->setNeedsTextMetricsUpdate();
                         toRenderSVGText(child)->setNeedsPositioningValuesUpdate();
+                    }
 
                     needsLayout = true;
                 }
index 57146c9..34e93a0 100644 (file)
@@ -73,7 +73,6 @@ void SVGRootInlineBox::computePerCharacterLayoutInformation()
     RenderSVGText* textRoot = toRenderSVGText(block());
     ASSERT(textRoot);
 
-    textRoot->rebuildLayoutAttributes();
     Vector<SVGTextLayoutAttributes*>& layoutAttributes = textRoot->layoutAttributes();
     if (layoutAttributes.isEmpty())
         return;
index 02a2123..be2a12f 100644 (file)
@@ -26,9 +26,6 @@
 #include "RenderSVGText.h"
 #include "SVGTextPositioningElement.h"
 
-// Set to a value > 0 to dump the text layout attributes
-#define DUMP_TEXT_LAYOUT_ATTRIBUTES 0
-
 namespace WebCore {
 
 SVGTextLayoutAttributesBuilder::SVGTextLayoutAttributesBuilder()
@@ -44,41 +41,27 @@ void SVGTextLayoutAttributesBuilder::buildLayoutAttributesForTextRenderer(Render
     if (!textRoot)
         return;
 
-    if (!buildLayoutAttributesIfNeeded(textRoot))
-        return;
-
-    m_metricsBuilder.buildMetricsAndLayoutAttributes(textRoot, text, m_characterDataMap);
-}
+    if (m_textPositions.isEmpty()) {
+        m_characterDataMap.clear();
 
-void SVGTextLayoutAttributesBuilder::buildLayoutAttributesForWholeTree(RenderSVGText* textRoot)
-{
-    ASSERT(textRoot);
+        m_textLength = 0;
+        const UChar* lastCharacter = 0;
+        collectTextPositioningElements(textRoot, lastCharacter);
 
-    if (!buildLayoutAttributesIfNeeded(textRoot))
-        return;
+        if (!m_textLength)
+            return;
 
-    m_metricsBuilder.buildMetricsAndLayoutAttributes(textRoot, 0, m_characterDataMap);
-}
+        buildCharacterDataMap(textRoot);
+    }
 
-void SVGTextLayoutAttributesBuilder::rebuildMetricsForTextRenderer(RenderSVGInlineText* text)
-{
-    ASSERT(text);
-    m_metricsBuilder.measureTextRenderer(text);
+    m_metricsBuilder.buildMetricsAndLayoutAttributes(textRoot, text, m_characterDataMap);
 }
 
-void SVGTextLayoutAttributesBuilder::rebuildMetricsForWholeTree(RenderSVGText* textRoot)
+bool SVGTextLayoutAttributesBuilder::buildLayoutAttributesForForSubtree(RenderSVGText* textRoot)
 {
     ASSERT(textRoot);
-    Vector<SVGTextLayoutAttributes*>& layoutAttributes = textRoot->layoutAttributes();
 
-    size_t layoutAttributesSize = layoutAttributes.size();
-    for (size_t i = 0; i < layoutAttributesSize; ++i)
-        m_metricsBuilder.measureTextRenderer(layoutAttributes[i]->context());
-}
-
-bool SVGTextLayoutAttributesBuilder::buildLayoutAttributesIfNeeded(RenderSVGText* textRoot)
-{
-    ASSERT(textRoot);
+    m_characterDataMap.clear();
 
     if (m_textPositions.isEmpty()) {
         m_textLength = 0;
@@ -86,14 +69,20 @@ bool SVGTextLayoutAttributesBuilder::buildLayoutAttributesIfNeeded(RenderSVGText
         collectTextPositioningElements(textRoot, lastCharacter);
     }
 
-    m_characterDataMap.clear();
     if (!m_textLength)
         return false;
 
-    buildLayoutAttributes(textRoot);
+    buildCharacterDataMap(textRoot);
+    m_metricsBuilder.buildMetricsAndLayoutAttributes(textRoot, 0, m_characterDataMap);
     return true;
 }
 
+void SVGTextLayoutAttributesBuilder::rebuildMetricsForTextRenderer(RenderSVGInlineText* text)
+{
+    ASSERT(text);
+    m_metricsBuilder.measureTextRenderer(text);
+}
+
 static inline void processRenderSVGInlineText(RenderSVGInlineText* text, unsigned& atCharacter, const UChar*& lastCharacter)
 {
     if (text->style()->whiteSpace() == PRE) {
@@ -143,10 +132,8 @@ void SVGTextLayoutAttributesBuilder::collectTextPositioningElements(RenderObject
     }
 }
 
-void SVGTextLayoutAttributesBuilder::buildLayoutAttributes(RenderSVGText* textRoot)
+void SVGTextLayoutAttributesBuilder::buildCharacterDataMap(RenderSVGText* textRoot)
 {
-    ASSERT(m_textLength);
-
     SVGTextPositioningElement* outermostTextElement = SVGTextPositioningElement::elementFromRenderer(textRoot);
     ASSERT(outermostTextElement);
 
@@ -173,11 +160,6 @@ void SVGTextLayoutAttributesBuilder::buildLayoutAttributes(RenderSVGText* textRo
     unsigned size = m_textPositions.size();
     for (unsigned i = 0; i < size; ++i)
         fillCharacterDataMap(m_textPositions[i]);
-
-#if DUMP_TEXT_LAYOUT_ATTRIBUTES > 0
-    fprintf(stderr, "\nDumping ALL layout attributes for RenderSVGText, renderer=%p, node=%p (m_textLength: %i)\n", textRoot, textRoot->node(), m_textLength);
-    m_characterDataMap.dump();
-#endif
 }
 
 static inline void updateCharacterData(unsigned i, float& lastRotation, SVGCharacterData& data, const SVGLengthContext& lengthContext, const SVGLengthList* xList, const SVGLengthList* yList, const SVGLengthList* dxList, const SVGLengthList* dyList, const SVGNumberList* rotateList)
index 45fad24..7dac96f 100644 (file)
@@ -43,14 +43,14 @@ class SVGTextLayoutAttributesBuilder {
     WTF_MAKE_NONCOPYABLE(SVGTextLayoutAttributesBuilder);
 public:
     SVGTextLayoutAttributesBuilder();
-    void buildLayoutAttributesForWholeTree(RenderSVGText*);
+    bool buildLayoutAttributesForForSubtree(RenderSVGText*);
     void buildLayoutAttributesForTextRenderer(RenderSVGInlineText*);
 
-    void rebuildMetricsForWholeTree(RenderSVGText*);
     void rebuildMetricsForTextRenderer(RenderSVGInlineText*);
 
     // Invoked whenever the underlying DOM tree changes, so that m_textPositions is rebuild.
     void clearTextPositioningElements() { m_textPositions.clear(); }
+    unsigned numberOfTextPositioningElements() const { return m_textPositions.size(); }
 
 private:
     struct TextPosition {
@@ -66,9 +66,8 @@ private:
         unsigned length;
     };
 
-    bool buildLayoutAttributesIfNeeded(RenderSVGText*);
+    void buildCharacterDataMap(RenderSVGText*);
     void collectTextPositioningElements(RenderObject*, const UChar*& lastCharacter);
-    void buildLayoutAttributes(RenderSVGText*);
     void fillCharacterDataMap(const TextPosition&);
 
 private:
index 4f521f3..a714d72 100644 (file)
@@ -238,19 +238,6 @@ bool SVGAElement::childShouldCreateRenderer(const NodeRenderingContext& childCon
     return SVGElement::childShouldCreateRenderer(childContext);
 }
 
-void SVGAElement::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
-{
-    SVGStyledTransformableElement::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
-
-    if (changedByParser || !renderer())
-        return;
-
-    // Invalidate the TextPosition cache in SVGTextLayoutAttributesBuilder as it may now point
-    // to no-longer existing SVGTextPositioningElements and thus needs to be rebuilt.
-    if (RenderSVGText* textRenderer = RenderSVGText::locateRenderSVGTextAncestor(renderer()))
-        textRenderer->invalidateTextPositioningElements();
-}
-
 } // namespace WebCore
 
 #endif // ENABLE(SVG)
index e2658c0..60e7b58 100644 (file)
@@ -40,9 +40,6 @@ class SVGAElement : public SVGStyledTransformableElement,
 public:
     static PassRefPtr<SVGAElement> create(const QualifiedName&, Document*);
 
-protected:
-    virtual void childrenChanged(bool changedByParser = false, Node* beforeChange = 0, Node* afterChange = 0, int childCountDelta = 0) OVERRIDE;
-
 private:
     SVGAElement(const QualifiedName&, Document*);
 
index b678824..612b605 100644 (file)
@@ -321,19 +321,6 @@ SVGTextContentElement* SVGTextContentElement::elementFromRenderer(RenderObject*
     return static_cast<SVGTextContentElement*>(node);
 }
 
-void SVGTextContentElement::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
-{
-    SVGStyledElement::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
-
-    if (changedByParser || !renderer())
-        return;
-
-    // Invalidate the TextPosition cache in SVGTextLayoutAttributesBuilder as it may now point
-    // to no-longer existing SVGTextPositioningElements and thus needs to be rebuilt.
-    if (RenderSVGText* textRenderer = RenderSVGText::locateRenderSVGTextAncestor(renderer()))
-        textRenderer->invalidateTextPositioningElements();
-}
-
 }
 
 #endif // ENABLE(SVG)
index df461ea..892f9f0 100644 (file)
@@ -109,7 +109,6 @@ protected:
     virtual void svgAttributeChanged(const QualifiedName&);
 
     virtual bool selfHasRelativeLengths() const;
-    virtual void childrenChanged(bool changedByParser = false, Node* beforeChange = 0, Node* afterChange = 0, int childCountDelta = 0);
 
 private:
     virtual bool isTextContent() const { return true; }