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 45ebadb0d04eb0cdcd87f721982c0af2040afbc6..59bab276cea9b1d59f9660609699e1c8d268c7b4 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 80c3bc2ddc163a1abc3ca69edad6fe8cd2b0df2a..27400192eaf6da532d0e227e9df42f5318a89a6b 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 521421674550bda016cd64e696675a7c26268058..577521a1b52dfb09ba5ddd87b5bcaefb75f4a1a8 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 fe75246191a223b2c6de753be44f4487efec9b6d..3948efc77b8d8de0e3f15076fb29d7260c56508b 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 529c9f3f4bdf29a6292b91d3abf31e121deb58e1..f0894f0b553a9db0d6bac5a1b84cf34aec7f1595 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 f6ce1d8d5e64004fef9eba4f05663f7dbc18ef19..74023b53a2f022e0da5f1f15860ad17bbe2b5aee 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);