Clear SVGInlineTextBox fragments when the text changes.
authormmaxfield@apple.com <mmaxfield@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 28 Mar 2014 18:25:26 +0000 (18:25 +0000)
committermmaxfield@apple.com <mmaxfield@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 28 Mar 2014 18:25:26 +0000 (18:25 +0000)
https://bugs.webkit.org/show_bug.cgi?id=130879

Reviewed by Darin Adler.

Blink: https://src.chromium.org/viewvc/blink?revision=150456&view=revision
Source/WebCore:

This patch modifies SVGInlineTextBox::dirtyLineBoxes to clear all
following text boxes when invoked. Typically this method is called
when the underlying text string changes, and that change needs to
be propagated to all the boxes that use the text beyond the point
where the text is first modified.

Also cleans up final function keywords for SVGRootInlineBox.

Test: svg/custom/unicode-in-tspan-multi-svg-crash.html

* rendering/InlineTextBox.h: Added (non-recursive) dirtyOwnLineBoxes() function
(WebCore::InlineTextBox::dirtyOwnLineBoxes): Calls dirtyLineBoxes()
* rendering/svg/SVGInlineTextBox.h: Added (non-recursive) dirtyOwnLineBoxes() function
(WebCore::SVGInlineTextBox::dirtyOwnLineBoxes):
* rendering/svg/SVGInlineTextBox.cpp:
(WebCore::SVGInlineTextBox::dirtyOwnLineBoxes): Non-recursive part of dirtyLineBoxes()
(WebCore::SVGInlineTextBox::dirtyLineBoxes): Calls dirtyOwnLineBoxes() in a loop
* rendering/svg/SVGRootInlineBox.h:

LayoutTests:

When failing, this test will render garbage characters or crash.

* svg/custom/unicode-in-tspan-multi-svg-crash-expected.txt: Added.
* svg/custom/unicode-in-tspan-multi-svg-crash.html: Added.

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

LayoutTests/ChangeLog
LayoutTests/svg/custom/unicode-in-tspan-multi-svg-crash-expected.txt [new file with mode: 0644]
LayoutTests/svg/custom/unicode-in-tspan-multi-svg-crash.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/rendering/InlineTextBox.h
Source/WebCore/rendering/svg/SVGInlineTextBox.cpp
Source/WebCore/rendering/svg/SVGInlineTextBox.h
Source/WebCore/rendering/svg/SVGRootInlineBox.h

index 45ebadb..59bab27 100644 (file)
@@ -1,3 +1,17 @@
+2014-03-28  Myles C. Maxfield  <mmaxfield@apple.com>
+
+        Clear SVGInlineTextBox fragments when the text changes.
+        https://bugs.webkit.org/show_bug.cgi?id=130879
+
+        Reviewed by Darin Adler.
+
+        Ported from Blink: https://src.chromium.org/viewvc/blink?revision=150456&view=revision
+
+        When failing, this test will render garbage characters or crash.
+
+        * svg/custom/unicode-in-tspan-multi-svg-crash-expected.txt: Added.
+        * svg/custom/unicode-in-tspan-multi-svg-crash.html: Added.
+
 2014-03-28  Michael Saboff  <msaboff@apple.com>
 
         Unreviewed, rolling r166248 back in.
diff --git a/LayoutTests/svg/custom/unicode-in-tspan-multi-svg-crash-expected.txt b/LayoutTests/svg/custom/unicode-in-tspan-multi-svg-crash-expected.txt
new file mode 100644 (file)
index 0000000..bfee7e9
--- /dev/null
@@ -0,0 +1 @@
+Test Passes if there is no crash in Debug or Asan builds. There should be no characters preceding "Test".
diff --git a/LayoutTests/svg/custom/unicode-in-tspan-multi-svg-crash.html b/LayoutTests/svg/custom/unicode-in-tspan-multi-svg-crash.html
new file mode 100644 (file)
index 0000000..19b4301
--- /dev/null
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<html>
+  <script>
+    if (window.testRunner)
+      testRunner.dumpAsText(false);
+
+    onload = function() {
+      tSpanElement = document.getElementById('tSpanInFirstRoot');
+      tSpanElement.appendChild(document.createTextNode(unescape('%ufe9e%ue28f%ue47e')));
+
+      document.body.offsetTop;
+      document.body.style.zoom=0.9;
+
+      document.designMode='on';
+      filterInFirstRoot = document.getElementById('filterInFirstRoot');
+      useElement = document.getElementById('useElement');
+      window.getSelection().setBaseAndExtent(filterInFirstRoot, useElement, 5);
+      document.execCommand('ForwardDelete');
+      document.designMode='off';
+    }
+  </script>
+  <body>
+    <svg xmlns="http://www.w3.org/2000/svg">
+      <text>
+        <filter id="filterInFirstRoot"/>
+        <tspan id="tSpanInFirstRoot"/>
+      </text>
+      <path filter="url(#filterInSecondRoot)"/>
+    </svg>
+
+    <svg xmlns="http://www.w3.org/2000/svg">
+      <use id="useElement"/>
+      <filter id="filterInSecondRoot"/>
+    </svg>
+
+    <p>Test Passes if there is no crash in Debug or Asan builds. There should be no characters preceding "Test".</p>
+  </body>
+</html>
index 80c3bc2..2740019 100644 (file)
@@ -1,3 +1,31 @@
+2014-03-28  Myles C. Maxfield  <mmaxfield@apple.com>
+
+        Clear SVGInlineTextBox fragments when the text changes.
+        https://bugs.webkit.org/show_bug.cgi?id=130879
+
+        Reviewed by Darin Adler.
+
+        Ported from Blink: https://src.chromium.org/viewvc/blink?revision=150456&view=revision
+
+        This patch modifies SVGInlineTextBox::dirtyLineBoxes to clear all
+        following text boxes when invoked. Typically this method is called
+        when the underlying text string changes, and that change needs to
+        be propagated to all the boxes that use the text beyond the point
+        where the text is first modified.
+        
+        Also cleans up final function keywords for SVGRootInlineBox.
+
+        Test: svg/custom/unicode-in-tspan-multi-svg-crash.html
+
+        * rendering/InlineTextBox.h: Added (non-recursive) dirtyOwnLineBoxes() function
+        (WebCore::InlineTextBox::dirtyOwnLineBoxes): Calls dirtyLineBoxes()
+        * rendering/svg/SVGInlineTextBox.h: Added (non-recursive) dirtyOwnLineBoxes() function
+        (WebCore::SVGInlineTextBox::dirtyOwnLineBoxes):
+        * rendering/svg/SVGInlineTextBox.cpp:
+        (WebCore::SVGInlineTextBox::dirtyOwnLineBoxes): Non-recursive part of dirtyLineBoxes()
+        (WebCore::SVGInlineTextBox::dirtyLineBoxes): Calls dirtyOwnLineBoxes() in a loop
+        * rendering/svg/SVGRootInlineBox.h:
+
 2014-03-28  Andreas Kling  <akling@apple.com>
 
         Rebaseline bindings tests.
index 5214216..577521a 100644 (file)
@@ -98,6 +98,8 @@ public:
     LayoutUnit logicalLeftVisualOverflow() const { return logicalOverflowRect().x(); }
     LayoutUnit logicalRightVisualOverflow() const { return logicalOverflowRect().maxX(); }
 
+    virtual void dirtyOwnLineBoxes() { dirtyLineBoxes(); }
+
 #ifndef NDEBUG
     virtual void showBox(int = 0) const;
     virtual const char* boxName() const;
index fe75246..3948efc 100644 (file)
@@ -57,7 +57,7 @@ SVGInlineTextBox::SVGInlineTextBox(RenderSVGInlineText& renderer)
 {
 }
 
-void SVGInlineTextBox::dirtyLineBoxes()
+void SVGInlineTextBox::dirtyOwnLineBoxes()
 {
     InlineTextBox::dirtyLineBoxes();
 
@@ -65,6 +65,16 @@ void SVGInlineTextBox::dirtyLineBoxes()
     clearTextFragments();
 }
 
+void SVGInlineTextBox::dirtyLineBoxes()
+{
+    dirtyOwnLineBoxes();
+
+    // And clear any following text fragments as the text on which they
+    // depend may now no longer exist, or glyph positions may be wrong
+    for (InlineTextBox* nextBox = nextTextBox(); nextBox; nextBox = nextBox->nextTextBox())
+        nextBox->dirtyOwnLineBoxes();
+}
+
 int SVGInlineTextBox::offsetForPosition(float, bool) const
 {
     // SVG doesn't use the standard offset <-> position selection system, as it's not suitable for SVGs complex needs.
index 529c9f3..f0894f0 100644 (file)
@@ -57,7 +57,8 @@ public:
     Vector<SVGTextFragment>& textFragments() { return m_textFragments; }
     const Vector<SVGTextFragment>& textFragments() const { return m_textFragments; }
 
-    virtual void dirtyLineBoxes() override;
+    virtual void dirtyOwnLineBoxes() override final;
+    virtual void dirtyLineBoxes() override final;
 
     bool startsNewTextChunk() const { return m_startsNewTextChunk; }
     void setStartsNewTextChunk(bool newTextChunk) { m_startsNewTextChunk = newTextChunk; }
index f6ce1d8..74023b5 100644 (file)
@@ -38,17 +38,17 @@ public:
 
     RenderSVGText& renderSVGText();
 
-    virtual float virtualLogicalHeight() const override { return m_logicalHeight; }
+    virtual float virtualLogicalHeight() const override final { return m_logicalHeight; }
     void setLogicalHeight(float height) { m_logicalHeight = height; }
 
-    virtual void paint(PaintInfo&, const LayoutPoint&, LayoutUnit lineTop, LayoutUnit lineBottom) override;
+    virtual void paint(PaintInfo&, const LayoutPoint&, LayoutUnit lineTop, LayoutUnit lineBottom) override final;
 
     void computePerCharacterLayoutInformation();
 
     InlineBox* closestLeafChildForPosition(const LayoutPoint&);
 
 private:
-    virtual bool isSVGRootInlineBox() const override { return true; }
+    virtual bool isSVGRootInlineBox() const override final { return true; }
     void reorderValueLists(Vector<SVGTextLayoutAttributes*>&);
     void layoutCharactersInTextBoxes(InlineFlowBox*, SVGTextLayoutEngine&);
     void layoutChildBoxes(InlineFlowBox*, FloatRect* = 0);