Reviewed by Eric.
authorzimmermann@webkit.org <zimmermann@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 16 Nov 2007 11:20:56 +0000 (11:20 +0000)
committerzimmermann@webkit.org <zimmermann@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 16 Nov 2007 11:20:56 +0000 (11:20 +0000)
Fixes: http://bugs.webkit.org/show_bug.cgi?id=12290
Implement all SVGTextContentElement DOM methods.
This is the last missing SVG text feature. SVG fonts is next.

Added testcase: svg/custom/text-dom-01-f.svg (tests all new methods)

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

15 files changed:
LayoutTests/ChangeLog
LayoutTests/platform/mac/svg/W3C-SVG-1.1/text-tselect-02-f-expected.checksum
LayoutTests/platform/mac/svg/W3C-SVG-1.1/text-tselect-02-f-expected.png
LayoutTests/platform/mac/svg/W3C-SVG-1.1/text-tselect-02-f-expected.txt
LayoutTests/platform/mac/svg/custom/text-dom-01-f-expected.checksum [new file with mode: 0644]
LayoutTests/platform/mac/svg/custom/text-dom-01-f-expected.png [new file with mode: 0644]
LayoutTests/platform/mac/svg/custom/text-dom-01-f-expected.txt [new file with mode: 0644]
LayoutTests/svg/custom/text-dom-01-f.svg [new file with mode: 0644]
LayoutTests/svg/text/text-tselect-02-f-expected.checksum
LayoutTests/svg/text/text-tselect-02-f-expected.png
LayoutTests/svg/text/text-tselect-02-f-expected.txt
WebCore/ChangeLog
WebCore/ksvg2/svg/SVGTextContentElement.cpp
WebCore/ksvg2/svg/SVGTextContentElement.h
WebCore/rendering/SVGInlineTextBox.h

index bc91248225839ebd548174d1f5e3736a9f2bd0c6..eecd148633b62b96cabab7bcde9d458cf8114b65 100644 (file)
@@ -1,3 +1,20 @@
+2007-11-16  Nikolas Zimmermann  <zimmermann@kde.org>
+
+        Reviewed by Eric.
+
+        Update layout test results after the addition of the SVGTextContentElement DOM methods.
+
+        * platform/mac/svg/W3C-SVG-1.1/text-tselect-02-f-expected.checksum:
+        * platform/mac/svg/W3C-SVG-1.1/text-tselect-02-f-expected.png:
+        * platform/mac/svg/W3C-SVG-1.1/text-tselect-02-f-expected.txt:
+        * platform/mac/svg/custom/text-dom-01-f-expected.checksum: Added.
+        * platform/mac/svg/custom/text-dom-01-f-expected.png: Added.
+        * platform/mac/svg/custom/text-dom-01-f-expected.txt: Added.
+        * svg/custom/text-dom-01-f.svg: Added.
+        * svg/text/text-tselect-02-f-expected.checksum:
+        * svg/text/text-tselect-02-f-expected.png:
+        * svg/text/text-tselect-02-f-expected.txt:
+
 2007-11-15  Adele Peterson  <adele@apple.com>
 
         Reviewed by Oliver.
index 35ded767cb3972650e49687c6e39b6ab79ffd506..5489a5661cf51f5cd65ea1c5380ad05f3c82aa46 100644 (file)
@@ -1 +1 @@
-54716022e8bb30d6886c54485bcf5a88
\ No newline at end of file
+0cdd7f9f52ec5ee59a1b84ef447fe47e
\ No newline at end of file
index d9f4a0ce3a332ad28eaff6dfb0541d76a9999d62..6179f623d0f515be8623e84c6b95e8a717c0451a 100644 (file)
Binary files a/LayoutTests/platform/mac/svg/W3C-SVG-1.1/text-tselect-02-f-expected.png and b/LayoutTests/platform/mac/svg/W3C-SVG-1.1/text-tselect-02-f-expected.png differ
index 677af1b06d4488b6d86e9c7c6746479ae536c313..ecc113716b4f97931d0b7f255bbe1212262c2803 100644 (file)
@@ -36,3 +36,5 @@ layer at (0,0) size 480x360
       RenderSVGInlineText {#text} at (0,-36) size 264x46
         chunk 1 text run 1 at (10.00,340.00) startOffset 0 endOffset 16 width 264.00: "$Revision: 1.2 $"
     RenderPath {rect} at (0.50,0.50) size 479x359 [stroke={[type=SOLID] [color=#000000]}] [data="M1.00,1.00L479.00,1.00L479.00,359.00L1.00,359.00"]
+selection start: position 3 of child 0 {#text} of child 3 {text} of child 3 {g} of child 35 {g} of child 0 {svg} of document
+selection end:   position 12 of child 0 {#text} of child 3 {text} of child 3 {g} of child 35 {g} of child 0 {svg} of document
diff --git a/LayoutTests/platform/mac/svg/custom/text-dom-01-f-expected.checksum b/LayoutTests/platform/mac/svg/custom/text-dom-01-f-expected.checksum
new file mode 100644 (file)
index 0000000..a1f92ac
--- /dev/null
@@ -0,0 +1 @@
+536a2457354cfd76e533641d0063cfea
\ No newline at end of file
diff --git a/LayoutTests/platform/mac/svg/custom/text-dom-01-f-expected.png b/LayoutTests/platform/mac/svg/custom/text-dom-01-f-expected.png
new file mode 100644 (file)
index 0000000..f1b92d6
Binary files /dev/null and b/LayoutTests/platform/mac/svg/custom/text-dom-01-f-expected.png differ
diff --git a/LayoutTests/platform/mac/svg/custom/text-dom-01-f-expected.txt b/LayoutTests/platform/mac/svg/custom/text-dom-01-f-expected.txt
new file mode 100644 (file)
index 0000000..c3f048d
--- /dev/null
@@ -0,0 +1,62 @@
+layer at (0,0) size 800x600
+  RenderView at (0,0) size 800x600
+layer at (0,0) size 480x360
+  RenderSVGRoot {svg} at (0.50,0.50) size 479x359
+    RenderSVGContainer {g} at (30,15) size 405x268
+      RenderSVGContainer {g} at (30,15) size 405x268
+        RenderPath {rect} at (125,16) size 8x17 [fill={[type=SOLID] [color=#ADD8E6]}] [data="M125.00,16.00L133.00,16.00L133.00,33.00L125.00,33.00"]
+        RenderPath {rect} at (91.88,20.10) size 14.14x14.14 [fill={[type=SOLID] [color=#ADD8E6]}] [data="M91.88,20.10L106.02,20.10L106.02,34.24L91.88,34.24"]
+        RenderPath {line} at (62,29.50) size 356x1 [stroke={[type=SOLID] [color=#FF0000]}] [fill={[type=SOLID] [color=#000000]}] [data="M62.00,30.00L418.00,30.00"]
+        RenderPath {line} at (132.50,15) size 1x15 [stroke={[type=SOLID] [color=#FF0000]}] [fill={[type=SOLID] [color=#000000]}] [data="M133.00,30.00L133.00,15.00"]
+        RenderPath {line} at (124.50,15) size 1x15 [stroke={[type=SOLID] [color=#FF0000]}] [fill={[type=SOLID] [color=#000000]}] [data="M125.00,30.00L125.00,15.00"]
+        RenderPath {line} at (189,29.50) size 60x1 [stroke={[type=SOLID] [color=#00FF00]}] [fill={[type=SOLID] [color=#000000]}] [data="M189.00,30.00L249.00,30.00"]
+        RenderSVGText {text} at (62,30) size 356x22 contains 1 chunk(s)
+          RenderSVGInlineText {#text} at (0,-14) size 32x17
+            chunk 1 (middle anchor) text run 1 at (62.00,30.00) startOffset 0 endOffset 5 width 32.00: "This "
+          RenderSVGTSpan {tspan} at (0,0) size 20x18
+            RenderSVGInlineText {#text} at (29,-10) size 20x18
+              chunk 1 (middle anchor) text run 2 at (94.00,30.00) startOffset 0 endOffset 2 width 11.00: "is"
+          RenderSVGInlineText {#text} at (43,-14) size 313x17
+            chunk 1 (middle anchor) text run 3 at (105.00,30.00) startOffset 0 endOffset 47 width 313.00: " a test of the interface SVGTextContentElement."
+        RenderSVGText {text} at (30,60) size 227x17 contains 1 chunk(s)
+          RenderSVGInlineText {#text} at (0,-14) size 227x17
+            chunk 1 text run 1 at (30.00,60.00) startOffset 0 endOffset 34 width 227.00: ".getCharNumAtPosition() result: 30"
+        RenderSVGText {text} at (30,80) size 246x17 contains 1 chunk(s)
+          RenderSVGInlineText {#text} at (0,-14) size 246x17
+            chunk 1 text run 1 at (30.00,80.00) startOffset 0 endOffset 36 width 246.00: ".getComputedTextLength() result: 356"
+        RenderSVGText {text} at (30,100) size 296x17 contains 1 chunk(s)
+          RenderSVGInlineText {#text} at (0,-14) size 296x17
+            chunk 1 text run 1 at (30.00,100.00) startOffset 0 endOffset 46 width 296.00: ".getEndPositionOfChar(11) result ('e'): 133,30"
+        RenderSVGText {text} at (30,120) size 292x17 contains 1 chunk(s)
+          RenderSVGInlineText {#text} at (0,-14) size 292x17
+            chunk 1 text run 1 at (30.00,120.00) startOffset 0 endOffset 46 width 292.00: ".getExtentOfChar(11) result ('e'): 125,16,8,17"
+        RenderSVGText {text} at (30,140) size 206x17 contains 1 chunk(s)
+          RenderSVGInlineText {#text} at (0,-14) size 206x17
+            chunk 1 text run 1 at (30.00,140.00) startOffset 0 endOffset 30 width 206.00: ".getNumberOfChars() result: 54"
+        RenderSVGText {text} at (30,160) size 208x17 contains 1 chunk(s)
+          RenderSVGInlineText {#text} at (0,-14) size 208x17
+            chunk 1 text run 1 at (30.00,160.00) startOffset 0 endOffset 32 width 208.00: ".getRotationOfChar(5) result: 45"
+        RenderSVGText {text} at (30,180) size 301x17 contains 1 chunk(s)
+          RenderSVGInlineText {#text} at (0,-14) size 301x17
+            chunk 1 text run 1 at (30.00,180.00) startOffset 0 endOffset 48 width 301.00: ".getStartPositionOfChar(11) result ('e'): 125,30"
+        RenderSVGText {text} at (30,200) size 310x17 contains 1 chunk(s)
+          RenderSVGInlineText {#text} at (0,-14) size 310x17
+            chunk 1 text run 1 at (30.00,200.00) startOffset 0 endOffset 50 width 310.00: ".getSubStringLength(22,9) result ('interface'): 60"
+        RenderSVGText {text} at (30,220) size 405x17 contains 1 chunk(s)
+          RenderSVGInlineText {#text} at (0,-14) size 405x17
+            chunk 1 text run 1 at (30.00,220.00) startOffset 0 endOffset 64 width 405.00: ".selectSubString(18,3) result: the word 'the' should be selected"
+        RenderSVGText {text} at (30,240) size 224x17 contains 1 chunk(s)
+          RenderSVGInlineText {#text} at (0,-14) size 224x17
+            chunk 1 text run 1 at (30.00,240.00) startOffset 0 endOffset 35 width 224.00: ".textLength.baseVal.value result: 0"
+        RenderSVGText {text} at (30,260) size 223x17 contains 1 chunk(s)
+          RenderSVGInlineText {#text} at (0,-14) size 223x17
+            chunk 1 text run 1 at (30.00,260.00) startOffset 0 endOffset 35 width 223.00: ".textLength.animVal.value result: 0"
+        RenderSVGText {text} at (30,280) size 381x17 contains 1 chunk(s)
+          RenderSVGInlineText {#text} at (0,-14) size 381x17
+            chunk 1 text run 1 at (30.00,280.00) startOffset 0 endOffset 59 width 381.00: ".lengthAdjust.baseVal and .lengthAdjust.animVal result: 1,1"
+    RenderSVGText {text} at (10,340) size 264x46 contains 1 chunk(s)
+      RenderSVGInlineText {#text} at (0,-36) size 264x46
+        chunk 1 text run 1 at (10.00,340.00) startOffset 0 endOffset 16 width 264.00: "$Revision: 1.1 $"
+    RenderPath {rect} at (0.50,0.50) size 479x359 [stroke={[type=SOLID] [color=#000000]}] [data="M1.00,1.00L479.00,1.00L479.00,359.00L1.00,359.00"]
+selection start: position 11 of child 2 {#text} of child 7 {text} of child 3 {g} of child 35 {g} of child 0 {svg} of document
+selection end:   position 14 of child 2 {#text} of child 7 {text} of child 3 {g} of child 35 {g} of child 0 {svg} of document
diff --git a/LayoutTests/svg/custom/text-dom-01-f.svg b/LayoutTests/svg/custom/text-dom-01-f.svg
new file mode 100644 (file)
index 0000000..46925ac
--- /dev/null
@@ -0,0 +1,206 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1 Full//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11-flat.dtd">
+<svg version="1.1" baseProfile="full" id="svg-root" width="480" height="360" viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" onload="testSVGTextContentElement()">
+  <!--========================================================================-->
+  <!--=  Copyright 2006 World Wide Web Consortium, (Massachusetts          =-->
+  <!--=  Institute of Technology, European Research Consortium for         =-->
+  <!--=  Informatics and Mathematics (ERCIM), Keio University).            =-->
+  <!--=  All Rights Reserved.                                              =-->
+  <!--=  See http://www.w3.org/Consortium/Legal/.                          =-->
+  <!--========================================================================-->
+  <!-- NOTE:  CVS will automatically update the                             -->
+  <!--        "$RCSfile: text-dom-01-f.svg,v $" and "$Revision: 1.1 $"         -->
+  <!--        fields in the file.                                           -->
+  <!--        There is no need to update this information.                  -->
+  <!-- =====================================================================-->
+       <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/" reviewer="[reviewer]" owner="AN" desc="Tests the interface SVGTextContentElement" status="created" version="$Revision: 1.1 $" testname="$RCSfile: text-dom-01-f.svg,v $">
+    <OperatorScript>
+      <Paragraph>
+       This tests the methods and properties of the SVGTextContentElement interface on the text element with the id 'testText'
+       and the content 'This is a test of the interface SVGTextContentElement'. The word 'is' has two glyphs with different
+       rotation values defined with a &lt;tspan/&gt; element. There are 12 subtests testing the 9 methods and 2 properties.
+       Note that the numeric results of some methods may vary. The additional instructions state where the result may vary
+       and where it should have an exact value.
+      </Paragraph>
+       <Paragraph>
+               The first subtest is testing the method .getCharNumAtPosition(svgPt), where svgPt has an x value of 240 and y value of 25.
+               The result of this subtest must be "30".
+       </Paragraph>
+       <Paragraph>
+               The second subtest is testing the method .getComputedTextLength(). The rounded result may vary in the implementations but should be around 364.
+               A red line below the testText is visually indicating the result of the method .getComputedTextLength() and must look like a red underline
+               with a length that spans the whole text length from 'T' to '.'.
+       </Paragraph>
+       <Paragraph>
+               The third subtest is testing the method .getEndPositionOfChar() at the 11th character ('e').
+               The rounded result may vary in the implementations but should be around 131 for the 'x' value and must be 30 for the 'y' value.
+               Additionally, a red vertical line is indicating the end position of the character 'e'. Its lower 'y' value must be at 30
+               and the 'x' values must match the end position of the 11th character 'e'.
+       </Paragraph>
+       <Paragraph>
+               The fourth subtest is testing the method .getExtentOfChar() at the 11th character ('e').
+               The rounded result may vary in the implementations but should be around '123,16,8,17' for the 'x,y,width,height' values.
+               A lightblue rectangle below the character 'e' must fully enclose the 11th glyph.
+       </Paragraph>
+       <Paragraph>
+               The fifth subtest is testing the method .getNumberOfChars(). The result must be 54.
+       </Paragraph>
+       <Paragraph>
+               The sixth subtest is testing the method .getRotationOfChar() for the fifth character. The result must be 45.
+               Additionally, a lightblue rectangle below the text indicates the extent of the fifth glyph 'i'.
+               It must fully enclose the diagonally rotated fifth glyph 'i'.
+       </Paragraph>
+       <Paragraph>
+               The seventh subtest is testing the method .getStartPositionOfChar() at the 11th character ('e').
+               The rounded result may vary in the implementations but should be around 123 for the 'x' value and must be 30 for the 'y' value.
+               Additionally, a red vertical line is indicating the start position of the character 'e'. Its lower 'y' value must be at 30
+               and the 'x' values must match the end position of the 11th character 'e'.
+       </Paragraph>
+       <Paragraph>
+               The eighth subtest is testing the method .getSubStringLength(), starting at character 22 and including the 9 following characters.
+               The result may vary in the implementations but should be around 58. Additionally, a green (lime) line visually indicates
+               the result of the method. The word 'interface' must be fully underlined with the green line.
+       </Paragraph>
+       <Paragraph>
+               The ninth subtest is testing the method .selectSubString(). After loading the file, the word "the" must be selected.
+       </Paragraph>
+       <Paragraph>
+               The tenth subtest is testing the property .textLength. The rounded result of .textLength.baseVal.value may vary in
+               the implementations but should be around 364.
+               It must match the value calculated in the second subtest (.getComputedTextLength()).
+       </Paragraph>
+       <Paragraph>
+               The eleventh subtest is again testing the property .textLength. The rounded result of .textLength.animVal.value may vary in
+               the implementations but should be around 364.
+               It must match the value calculated in the second subtest (.getComputedTextLength()).
+       </Paragraph>
+       <Paragraph>
+               The twelfth subtest is again testing the property .lengthAdjust. The results of .lengthAdjust.baseVal and
+               .lengthAdjust.animVal must be 1 and 1.
+       </Paragraph>
+    </OperatorScript>
+  </SVGTestCase>
+  <title id="test-title">$RCSfile: text-dom-01-f.svg,v $</title>
+  <!--======================================================================-->
+  <!--Content of Test Case follows...                  =====================-->
+  <!--======================================================================-->
+  <g id="test-body-content">
+       <script type="text/ecmascript"><![CDATA[        
+               function testSVGTextContentElement() {
+               var svgNS = "http://www.w3.org/2000/svg";
+                       var tContentEl = document.getElementById("testText");
+               var textGroup = document.getElementById("textGroup");
+               var svgPt = document.documentElement.createSVGPoint();
+               svgPt.x = 240;
+               svgPt.y = 25;
+               
+               //1: testing .getCharNumAtPosition()
+               var charNumresult = tContentEl.getCharNumAtPosition(svgPt);
+               document.getElementById("text1").firstChild.data = ".getCharNumAtPosition() result: "+charNumresult;
+               
+               //2: testing .getCharNumAtPosition()
+                       var compTextLength = tContentEl.getComputedTextLength();
+               document.getElementById("text2").firstChild.data = ".getComputedTextLength() result: "+Math.round(compTextLength);
+                       var baseLine = document.createElementNS(svgNS,"line");
+               baseLine.setAttributeNS(null,"stroke","red");
+               baseLine.setAttributeNS(null,"x1",(240 - compTextLength * 0.5));
+               baseLine.setAttributeNS(null,"x2",(240 + compTextLength * 0.5));
+               baseLine.setAttributeNS(null,"y1",30);
+               baseLine.setAttributeNS(null,"y2",30);
+               textGroup.insertBefore(baseLine,tContentEl);
+               
+               //3: testing .getEndPositionOfChar(), end of character                  
+                       var endPosChar = tContentEl.getEndPositionOfChar(11);
+               document.getElementById("text3").firstChild.data = ".getEndPositionOfChar(11) result ('e'): "+Math.round(endPosChar.x)+","+Math.round(endPosChar.y);
+                       var endPosLine = document.createElementNS(svgNS,"line");
+               endPosLine.setAttributeNS(null,"stroke","red");
+               endPosLine.setAttributeNS(null,"x1",endPosChar.x);
+               endPosLine.setAttributeNS(null,"x2",endPosChar.x);
+               endPosLine.setAttributeNS(null,"y1",endPosChar.y);
+               endPosLine.setAttributeNS(null,"y2",endPosChar.y-15);
+               textGroup.insertBefore(endPosLine,tContentEl);
+               
+               //4: testing getExtentOfChar
+               var charExtent = tContentEl.getExtentOfChar(11);
+               document.getElementById("text4").firstChild.data = ".getExtentOfChar(11) result ('e'): "+Math.round(charExtent.x)+","+Math.round(charExtent.y)+","+Math.round(charExtent.width)+","+Math.round(charExtent.height);
+                       var extentRect = document.createElementNS(svgNS,"rect");
+               extentRect.setAttributeNS(null,"fill","lightblue");
+               extentRect.setAttributeNS(null,"x",charExtent.x);
+               extentRect.setAttributeNS(null,"y",charExtent.y);
+               extentRect.setAttributeNS(null,"width",charExtent.width);
+               extentRect.setAttributeNS(null,"height",charExtent.height);
+               textGroup.insertBefore(extentRect,baseLine);            
+               
+               //5: testing getNumberOfChars
+               var numChars = tContentEl.getNumberOfChars();
+               document.getElementById("text5").firstChild.data = ".getNumberOfChars() result: "+numChars;
+               
+               //6: testing getRotationOfChar
+               var charRot = tContentEl.getRotationOfChar(5);
+               document.getElementById("text6").firstChild.data = ".getRotationOfChar(5) result: "+charRot;
+               var rotCharExtent = tContentEl.getExtentOfChar(5);
+                       var rotExtentRect = document.createElementNS(svgNS,"rect");
+               rotExtentRect.setAttributeNS(null,"fill","lightblue");
+               rotExtentRect.setAttributeNS(null,"x",rotCharExtent.x);
+               rotExtentRect.setAttributeNS(null,"y",rotCharExtent.y);
+               rotExtentRect.setAttributeNS(null,"width",rotCharExtent.width);
+               rotExtentRect.setAttributeNS(null,"height",rotCharExtent.height);
+               textGroup.insertBefore(rotExtentRect,baseLine);                 
+               
+               //7: testing .getStartPositionOfChar(), end of character
+                       var startPosChar = tContentEl.getStartPositionOfChar(11);
+               document.getElementById("text7").firstChild.data = ".getStartPositionOfChar(11) result ('e'): "+Math.round(startPosChar.x)+","+Math.round(startPosChar.y);
+                       var startPosLine = document.createElementNS(svgNS,"line");
+               startPosLine.setAttributeNS(null,"stroke","red");
+               startPosLine.setAttributeNS(null,"x1",startPosChar.x);
+               startPosLine.setAttributeNS(null,"x2",startPosChar.x);
+               startPosLine.setAttributeNS(null,"y1",startPosChar.y);
+               startPosLine.setAttributeNS(null,"y2",startPosChar.y-15);
+               textGroup.insertBefore(startPosLine,tContentEl);
+               
+               //8: testing .getSubStringLength()
+               var startPosInterface = tContentEl.getStartPositionOfChar(22);
+               var subStrLength = tContentEl.getSubStringLength(22,9);
+               document.getElementById("text8").firstChild.data = ".getSubStringLength(22,9) result ('interface'): "+Math.round(subStrLength);
+                       var subStrLine = document.createElementNS(svgNS,"line");
+               subStrLine.setAttributeNS(null,"stroke","lime");
+               subStrLine.setAttributeNS(null,"x1",startPosInterface.x);
+               subStrLine.setAttributeNS(null,"x2",(startPosInterface.x+subStrLength));
+               subStrLine.setAttributeNS(null,"y1",startPosInterface.y);
+               subStrLine.setAttributeNS(null,"y2",startPosInterface.y);
+               textGroup.insertBefore(subStrLine,tContentEl);
+               
+               //9: testing .selectSubString()
+               tContentEl.selectSubString(18,3);
+               
+               //10: testing textLength.baseVal.value
+               var tlbaseval = tContentEl.textLength.baseVal.value;
+               document.getElementById("text10").firstChild.data = ".textLength.baseVal.value result: "+Math.round(tlbaseval);
+               
+               //11: testing textLength.baseVal.value
+               var tlanimval = tContentEl.textLength.animVal.value;
+               document.getElementById("text11").firstChild.data = ".textLength.animVal.value result: "+Math.round(tlanimval);
+               
+               //12: testing lengthAdjust baseVal and animVal
+               document.getElementById("text12").firstChild.data = ".lengthAdjust.baseVal and .lengthAdjust.animVal result: "+tContentEl.lengthAdjust.baseVal+","+tContentEl.lengthAdjust.animVal;;
+       }       
+       ]]></script>    
+       <g id="textGroup" font-family="Arial" font-size="15">
+               <text x="240" y="30" text-anchor="middle" id="testText">This <tspan rotate="45,90">is</tspan> a test of the interface SVGTextContentElement.</text>
+               <text id="text1" x="30" y="60">.getCharNumAtPosition() result: </text>
+               <text id="text2" x="30" y="80">.getComputedTextLength() result: </text>
+               <text id="text3" x="30" y="100">.getEndPositionOfChar(11) result ('e'): </text>
+               <text id="text4" x="30" y="120">.getExtentOfChar(11) result ('e'): </text>
+               <text id="text5" x="30" y="140">.getNumberOfChars() result: </text>
+               <text id="text6" x="30" y="160">.getRotationOfChar(5) result: </text>
+               <text id="text7" x="30" y="180">.getStartPositionOfChar(11) result: </text>
+               <text id="text8" x="30" y="200">.getSubStringLength(22,9) result ('interface'): </text>
+               <text id="text9" x="30" y="220">.selectSubString(18,3) result: the word 'the' should be selected</text>
+               <text id="text10" x="30" y="240">.textLength.baseVal.value result:</text>
+               <text id="text11" x="30" y="260">.textLength.animVal.value result:</text>
+               <text id="text12" x="30" y="280">.lengthAdjust.baseVal and .lengthAdjust.animVal result:</text>
+       </g>
+  </g>
+  <text id="revision" x="10" y="340" font-size="40" stroke="none" fill="black">$Revision: 1.1 $</text>
+  <rect id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000"/>
+</svg>
index b7f21f2b13389d944645a704bb8735da2ba8b9e5..864c60165eb11bc35c63be382160fd176f73ce69 100644 (file)
@@ -1 +1 @@
-8134633414eba4f7ed52a725056b17a3
\ No newline at end of file
+2b667bf1c69194fb6f0ca5894e059a07
\ No newline at end of file
index 53eaddc697fcc6bddc5e7b48e13aeb7d5c3eb58e..dba130a71ccdf8b2ec6fb144cc352a14bf6d810c 100644 (file)
Binary files a/LayoutTests/svg/text/text-tselect-02-f-expected.png and b/LayoutTests/svg/text/text-tselect-02-f-expected.png differ
index 1e2c918667e00e8a8ca5929c6df98e72b6e3d8b2..d1e514d1f1b851eae62fff49b583d331b3d910f2 100644 (file)
@@ -36,5 +36,5 @@ layer at (0,0) size 800x600
       RenderSVGInlineText {#text} at (0,-36) size 264x46
         chunk 1 text run 1 at (10.00,340.00) startOffset 0 endOffset 16 width 264.00: "$Revision: 1.2 $"
     RenderPath {rect} at (0.83,0.83) size 798.33x598.33 [stroke={[type=SOLID] [color=#000000]}] [data="M1.00,1.00L479.00,1.00L479.00,359.00L1.00,359.00"]
-selection start: position 0 of child 0 {#text} of child 1 {text} of child 3 {g} of child 35 {g} of child 0 {svg} of document
-selection end:   position 16 of child 0 {#text} of child 37 {text} of child 0 {svg} of document
+selection start: position 3 of child 0 {#text} of child 3 {text} of child 3 {g} of child 35 {g} of child 0 {svg} of document
+selection end:   position 12 of child 0 {#text} of child 3 {text} of child 3 {g} of child 35 {g} of child 0 {svg} of document
index 530f9f5621af2159e6b5b0482d1c639d0efe147f..ba780ee07bf1b4eaed48c57226b5eed44aeb232c 100644 (file)
@@ -1,3 +1,40 @@
+2007-11-16  Nikolas Zimmermann  <zimmermann@kde.org>
+
+        Reviewed by Eric.
+
+        Fixes: http://bugs.webkit.org/show_bug.cgi?id=12290
+
+        Implement all SVGTextContentElement DOM methods.
+        This is the last missing SVG text feature. SVG fonts is next.
+
+        Added testcase: svg/custom/text-dom-01-f.svg (tests all new methods)
+
+        * ksvg2/svg/SVGTextContentElement.cpp:
+        (WebCore::cummulatedCharacterRangeLength):
+        (WebCore::SVGInlineTextBoxQueryWalker::):
+        (WebCore::SVGInlineTextBoxQueryWalker::SVGInlineTextBoxQueryWalker):
+        (WebCore::SVGInlineTextBoxQueryWalker::chunkPortionCallback):
+        (WebCore::SVGInlineTextBoxQueryWalker::setQueryInputParameters):
+        (WebCore::SVGInlineTextBoxQueryWalker::longResult):
+        (WebCore::SVGInlineTextBoxQueryWalker::floatResult):
+        (WebCore::SVGInlineTextBoxQueryWalker::pointResult):
+        (WebCore::SVGInlineTextBoxQueryWalker::rectResult):
+        (WebCore::SVGInlineTextBoxQueryWalker::stopProcessing):
+        (WebCore::findInlineTextBoxInTextChunks):
+        (WebCore::rootInlineBoxForTextContentElement):
+        (WebCore::executeTextQuery):
+        (WebCore::SVGTextContentElement::getNumberOfChars):
+        (WebCore::SVGTextContentElement::getComputedTextLength):
+        (WebCore::SVGTextContentElement::getSubStringLength):
+        (WebCore::SVGTextContentElement::getStartPositionOfChar):
+        (WebCore::SVGTextContentElement::getEndPositionOfChar):
+        (WebCore::SVGTextContentElement::getExtentOfChar):
+        (WebCore::SVGTextContentElement::getRotationOfChar):
+        (WebCore::SVGTextContentElement::getCharNumAtPosition):
+        (WebCore::SVGTextContentElement::selectSubString):
+        * ksvg2/svg/SVGTextContentElement.h:
+        * rendering/SVGInlineTextBox.h:
+
 2007-11-15  Adele Peterson  <adele@apple.com>
 
         Reviewed by Oliver.
index 2d250fc6f090047f21d1b739683395a1d94708d6..56fa0a1b8afc928252dc286977c4501b444c6f25 100644 (file)
 
 #include "CSSPropertyNames.h"
 #include "CSSValueKeywords.h"
+#include "ExceptionCode.h"
 #include "FloatPoint.h"
 #include "FloatRect.h"
+#include "Frame.h"
+#include "Position.h"
+#include "RenderSVGText.h"
+#include "SelectionController.h"
+#include "SVGCharacterLayoutInfo.h"
+#include "SVGRootInlineBox.h"
 #include "SVGLength.h"
+#include "SVGInlineTextBox.h"
 #include "SVGNames.h"
 #include "XMLNames.h"
 
@@ -52,48 +60,402 @@ SVGTextContentElement::~SVGTextContentElement()
 ANIMATED_PROPERTY_DEFINITIONS(SVGTextContentElement, SVGLength, Length, length, TextLength, textLength, SVGNames::textLengthAttr.localName(), m_textLength)
 ANIMATED_PROPERTY_DEFINITIONS(SVGTextContentElement, int, Enumeration, enumeration, LengthAdjust, lengthAdjust, SVGNames::lengthAdjustAttr.localName(), m_lengthAdjust)
 
+static inline float cummulatedCharacterRangeLength(const Vector<SVGChar>::iterator& start, const Vector<SVGChar>::iterator& end, SVGInlineTextBox* textBox,
+                                                   int startOffset, long startPosition, long length, bool isVerticalText, long& atCharacter)
+{
+    float textLength = 0.0f;
+    RenderStyle* style = textBox->textObject()->style();
+
+    bool usesFullRange = (startPosition == -1 && length == -1);
+
+    for (Vector<SVGChar>::iterator it = start; it != end; ++it) {
+        if (usesFullRange || (atCharacter >= startPosition && atCharacter <= startPosition + length)) {
+            unsigned int newOffset = textBox->start() + (it - start) + startOffset;
+
+            // Take RTL text into account and pick right glyph width/height.
+            if (textBox->m_reversed)
+                newOffset = textBox->start() + textBox->end() - newOffset;
+
+            if (isVerticalText)
+                textLength += textBox->calculateGlyphHeight(style, newOffset);
+            else
+                textLength += textBox->calculateGlyphWidth(style, newOffset);
+        }
+
+        if (!usesFullRange) {
+            if (atCharacter < startPosition + length)
+                atCharacter++;
+            else if (atCharacter == startPosition + length)
+                break;
+        }
+    }
+
+    return textLength;
+}
+
+// Helper class for querying certain glyph information
+struct SVGInlineTextBoxQueryWalker {
+    typedef enum {
+        NumberOfCharacters,
+        TextLength,
+        SubStringLength,
+        StartPosition,
+        EndPosition,
+        Extent,
+        Rotation,
+        CharacterNumberAtPosition
+    } QueryMode;
+
+    SVGInlineTextBoxQueryWalker(const SVGTextContentElement* reference, QueryMode mode)
+        : m_reference(reference)
+        , m_mode(mode)
+        , m_queryStartPosition(0)
+        , m_queryLength(0)
+        , m_queryPointInput()
+        , m_queryLongResult(0)
+        , m_queryFloatResult(0.0f)
+        , m_queryPointResult()
+        , m_queryRectResult()
+        , m_stopProcessing(true)    
+        , m_atCharacter(0)
+    {
+    }
+
+    void chunkPortionCallback(SVGInlineTextBox* textBox, int startOffset, const AffineTransform& chunkCtm,
+                              const Vector<SVGChar>::iterator& start, const Vector<SVGChar>::iterator& end)
+    {
+        RenderStyle* style = textBox->textObject()->style();
+        bool isVerticalText = style->svgStyle()->writingMode() == WM_TBRL || style->svgStyle()->writingMode() == WM_TB;
+
+        switch (m_mode) {
+        case NumberOfCharacters:
+        {    
+            m_queryLongResult += (end - start);
+            m_stopProcessing = false;
+            return;
+        }
+        case TextLength:
+        {
+            float textLength = cummulatedCharacterRangeLength(start, end, textBox, startOffset, -1, -1, isVerticalText, m_atCharacter);
+
+            if (isVerticalText)
+                m_queryFloatResult += textLength;
+            else
+                m_queryFloatResult += textLength;
+
+            m_stopProcessing = false;
+            return;
+        }
+        case SubStringLength:
+        {
+            long startPosition = m_queryStartPosition;
+            long length = m_queryLength;
+
+            float textLength = cummulatedCharacterRangeLength(start, end, textBox, startOffset, startPosition, length, isVerticalText, m_atCharacter);
+
+            if (isVerticalText)
+                m_queryFloatResult += textLength;
+            else
+                m_queryFloatResult += textLength;
+
+            if (m_atCharacter == startPosition + length)
+                m_stopProcessing = true;
+            else
+                m_stopProcessing = false;
+
+            return;
+        }
+        case StartPosition:
+        {
+            for (Vector<SVGChar>::iterator it = start; it != end; ++it) {
+                if (m_atCharacter == m_queryStartPosition) {
+                    m_queryPointResult = FloatPoint(it->x, it->y);
+                    m_stopProcessing = true;
+                    return;
+                }
+
+                m_atCharacter++;
+            }
+
+            m_stopProcessing = false;
+            return;
+        }
+        case EndPosition:
+        {
+            for (Vector<SVGChar>::iterator it = start; it != end; ++it) {
+                if (m_atCharacter == m_queryStartPosition) {
+                    unsigned int newOffset = textBox->start() + (it - start) + startOffset;
+
+                    // Take RTL text into account and pick right glyph width/height.
+                    if (textBox->m_reversed)
+                        newOffset = textBox->start() + textBox->end() - newOffset;
+
+                    if (isVerticalText)
+                        m_queryPointResult.move(it->x, it->y + textBox->calculateGlyphHeight(style, newOffset));
+                    else
+                        m_queryPointResult.move(it->x + textBox->calculateGlyphWidth(style, newOffset), it->y);
+
+                    m_stopProcessing = true;
+                    return;
+                }
+
+                m_atCharacter++;
+            }
+
+            m_stopProcessing = false;
+            return;
+        }
+        case Extent:
+        {
+            for (Vector<SVGChar>::iterator it = start; it != end; ++it) {
+                if (m_atCharacter == m_queryStartPosition) {
+                    unsigned int newOffset = textBox->start() + (it - start) + startOffset;
+                    m_queryRectResult = textBox->calculateGlyphBoundaries(style, newOffset, *it);
+                    m_stopProcessing = true;
+                    return;
+                }
+
+                m_atCharacter++;
+            }
+
+            m_stopProcessing = false;
+            return;
+        }
+        case Rotation:
+        {
+            for (Vector<SVGChar>::iterator it = start; it != end; ++it) {
+                if (m_atCharacter == m_queryStartPosition) {
+                    m_queryFloatResult = it->angle;
+                    m_stopProcessing = true;
+                    return;
+                }
+
+                m_atCharacter++;
+            }
+
+            m_stopProcessing = false;
+            return;
+        }
+        case CharacterNumberAtPosition:
+        {
+            int offset = 0;
+            SVGChar* charAtPos = textBox->closestCharacterToPosition(m_queryPointInput.x(), m_queryPointInput.y(), offset);
+
+            offset += m_atCharacter;
+            if (charAtPos && offset > m_queryLongResult)
+                m_queryLongResult = offset;
+
+            m_atCharacter += end - start;
+            m_stopProcessing = false;
+            return;
+        }
+        default:
+            ASSERT_NOT_REACHED();
+            m_stopProcessing = true;
+            return;
+        }
+    }
+
+    void setQueryInputParameters(long startPosition, long length, FloatPoint referencePoint)
+    {
+        m_queryStartPosition = startPosition;
+        m_queryLength = length;
+        m_queryPointInput = referencePoint;
+    }
+
+    long longResult() const { return m_queryLongResult; }
+    float floatResult() const { return m_queryFloatResult; }
+    FloatPoint pointResult() const { return m_queryPointResult; }
+    FloatRect rectResult() const { return m_queryRectResult; }
+    bool stopProcessing() const { return m_stopProcessing; }
+
+private:
+    const SVGTextContentElement* m_reference;
+    QueryMode m_mode;
+
+    long m_queryStartPosition;
+    long m_queryLength;
+    FloatPoint m_queryPointInput;
+
+    long m_queryLongResult;
+    float m_queryFloatResult;
+    FloatPoint m_queryPointResult;
+    FloatRect m_queryRectResult;
+
+    bool m_stopProcessing;
+    long m_atCharacter;
+};
+
+static Vector<SVGInlineTextBox*> findInlineTextBoxInTextChunks(const SVGTextContentElement* element, const Vector<SVGTextChunk>& chunks)
+{   
+    Vector<SVGTextChunk>::const_iterator it = chunks.begin();
+    const Vector<SVGTextChunk>::const_iterator end = chunks.end();
+
+    Vector<SVGInlineTextBox*> boxes;
+
+    for (; it != end; ++it) {
+        Vector<SVGInlineBoxCharacterRange>::const_iterator boxIt = it->boxes.begin();
+        const Vector<SVGInlineBoxCharacterRange>::const_iterator boxEnd = it->boxes.end();
+
+        for (; boxIt != boxEnd; ++boxIt) {
+            SVGInlineTextBox* textBox = static_cast<SVGInlineTextBox*>(boxIt->box);
+
+            Node* textElement = textBox->textObject()->parent()->element();
+            ASSERT(textElement);
+
+            if (textElement == element || textElement->parent() == element)
+                boxes.append(textBox);
+        }
+    }
+
+    return boxes;
+}
+
+static inline SVGRootInlineBox* rootInlineBoxForTextContentElement(const SVGTextContentElement* element)
+{
+    RenderObject* object = element->renderer();
+    ASSERT(object);
+
+    if (!object->isSVGText() || object->isText())
+        return 0;
+
+    RenderSVGText* svgText = static_cast<RenderSVGText*>(object);
+
+    // Find root inline box
+    SVGRootInlineBox* rootBox = static_cast<SVGRootInlineBox*>(svgText->firstRootBox());
+    if (!rootBox) {
+        // Layout is not sync yet!
+        element->document()->updateLayoutIgnorePendingStylesheets();
+        rootBox = static_cast<SVGRootInlineBox*>(svgText->firstRootBox());
+    }
+
+    ASSERT(rootBox);
+    return rootBox;
+}
+
+static inline SVGInlineTextBoxQueryWalker executeTextQuery(const SVGTextContentElement* element, SVGInlineTextBoxQueryWalker::QueryMode mode,
+                                                           long startPosition = 0, long length = 0, FloatPoint referencePoint = FloatPoint())
+{
+    SVGRootInlineBox* rootBox = rootInlineBoxForTextContentElement(element);
+    if (!rootBox)
+        return SVGInlineTextBoxQueryWalker(0, mode);
+
+    // Find all inline text box associated with our renderer
+    Vector<SVGInlineTextBox*> textBoxes = findInlineTextBoxInTextChunks(element, rootBox->svgTextChunks());
+
+    // Walk text chunks to find chunks associated with our inline text box
+    SVGInlineTextBoxQueryWalker walkerCallback(element, mode);
+    walkerCallback.setQueryInputParameters(startPosition, length, referencePoint);
+
+    SVGTextChunkWalker<SVGInlineTextBoxQueryWalker> walker(&walkerCallback, &SVGInlineTextBoxQueryWalker::chunkPortionCallback);
+
+    Vector<SVGInlineTextBox*>::iterator it = textBoxes.begin();
+    Vector<SVGInlineTextBox*>::iterator end = textBoxes.end();
+
+    for (; it != end; ++it) {
+        rootBox->walkTextChunks(&walker, *it);
+
+        if (walkerCallback.stopProcessing())
+            break;
+    }
+
+    return walkerCallback;
+}
+
 long SVGTextContentElement::getNumberOfChars() const
 {
-    return 0;
+    return executeTextQuery(this, SVGInlineTextBoxQueryWalker::NumberOfCharacters).longResult();
 }
 
 float SVGTextContentElement::getComputedTextLength() const
 {
-    return 0.0f;
+    return executeTextQuery(this, SVGInlineTextBoxQueryWalker::TextLength).floatResult();
 }
 
-float SVGTextContentElement::getSubStringLength(unsigned long charnum, unsigned long nchars, ExceptionCode&) const
+float SVGTextContentElement::getSubStringLength(long charnum, unsigned long nchars, ExceptionCode& ec) const
 {
-    return 0.0f;
+    if (charnum < 0 || charnum > getNumberOfChars()) {
+        ec = INDEX_SIZE_ERR;
+        return 0.0f;
+    }
+
+    return executeTextQuery(this, SVGInlineTextBoxQueryWalker::SubStringLength, charnum, nchars).floatResult();
 }
 
-FloatPoint SVGTextContentElement::getStartPositionOfChar(unsigned long charnum, ExceptionCode&) const
+FloatPoint SVGTextContentElement::getStartPositionOfChar(long charnum, ExceptionCode& ec) const
 {
-    return FloatPoint();
+    if (charnum < 0 || charnum > getNumberOfChars()) {
+        ec = INDEX_SIZE_ERR;
+        return FloatPoint();
+    }
+
+    return executeTextQuery(this, SVGInlineTextBoxQueryWalker::StartPosition, charnum).pointResult();
 }
 
-FloatPoint SVGTextContentElement::getEndPositionOfChar(unsigned long charnum, ExceptionCode&) const
+FloatPoint SVGTextContentElement::getEndPositionOfChar(long charnum, ExceptionCode& ec) const
 {
-    return FloatPoint();
+    if (charnum < 0 || charnum > getNumberOfChars()) {
+        ec = INDEX_SIZE_ERR;
+        return FloatPoint();
+    }
+
+    return executeTextQuery(this, SVGInlineTextBoxQueryWalker::EndPosition, charnum).pointResult();
 }
 
-FloatRect SVGTextContentElement::getExtentOfChar(unsigned long charnum, ExceptionCode&) const
+FloatRect SVGTextContentElement::getExtentOfChar(long charnum, ExceptionCode& ec) const
 {
-    return FloatRect();
+    if (charnum < 0 || charnum > getNumberOfChars()) {
+        ec = INDEX_SIZE_ERR;
+        return FloatRect();
+    }
+
+    return executeTextQuery(this, SVGInlineTextBoxQueryWalker::Extent, charnum).rectResult();
 }
 
-float SVGTextContentElement::getRotationOfChar(unsigned long charnum, ExceptionCode&) const
+float SVGTextContentElement::getRotationOfChar(long charnum, ExceptionCode& ec) const
 {
-    return 0.0f;
+    if (charnum < 0 || charnum > getNumberOfChars()) {
+        ec = INDEX_SIZE_ERR;
+        return 0.0f;
+    }
+
+    return executeTextQuery(this, SVGInlineTextBoxQueryWalker::Rotation, charnum).floatResult();
 }
 
 long SVGTextContentElement::getCharNumAtPosition(const FloatPoint& point) const
 {
-    return 0;
+    return executeTextQuery(this, SVGInlineTextBoxQueryWalker::CharacterNumberAtPosition, 0.0f, 0.0f, point).longResult();
 }
 
-void SVGTextContentElement::selectSubString(unsigned long charnum, unsigned long nchars, ExceptionCode&) const
+void SVGTextContentElement::selectSubString(long charnum, long nchars, ExceptionCode& ec) const
 {
+    long numberOfChars = getNumberOfChars();
+    if (charnum < 0 || nchars < 0 || charnum > numberOfChars) {
+        ec = INDEX_SIZE_ERR;
+        return;
+    }
+
+    if (nchars > numberOfChars - charnum)
+        nchars = numberOfChars - charnum;
+
+    ASSERT(document());
+    ASSERT(document()->frame());
+
+    SelectionController* controller = document()->frame()->selectionController();
+    if (!controller)
+        return;
+
+    // Find selection start
+    VisiblePosition start(const_cast<SVGTextContentElement*>(this), 0, SEL_DEFAULT_AFFINITY);
+    for (long i = 0; i < charnum; ++i)
+        start = start.next();
+
+    // Find selection end
+    VisiblePosition end(start);
+    for (long i = 0; i < nchars; ++i)
+        end = end.next();
+
+    controller->setSelection(Selection(start, end));
 }
 
 void SVGTextContentElement::parseMappedAttribute(MappedAttribute* attr)
index 11beffdc602a043dec46f0dc2aae8a9d7534cd7e..570ed6b20faea67a21dda718dda0926040c1709e 100644 (file)
@@ -22,8 +22,8 @@
 
 #ifndef SVGTextContentElement_h
 #define SVGTextContentElement_h
-#if ENABLE(SVG)
 
+#if ENABLE(SVG)
 #include "SVGExternalResourcesRequired.h"
 #include "SVGLangSpace.h"
 #include "SVGStyledElement.h"
@@ -53,13 +53,13 @@ namespace WebCore {
         // 'SVGTextContentElement' functions
         long getNumberOfChars() const;
         float getComputedTextLength() const;
-        float getSubStringLength(unsigned long charnum, unsigned long nchars, ExceptionCode&) const;
-        FloatPoint getStartPositionOfChar(unsigned long charnum, ExceptionCode&) const;
-        FloatPoint getEndPositionOfChar(unsigned long charnum, ExceptionCode&) const;
-        FloatRect getExtentOfChar(unsigned long charnum, ExceptionCode&) const;
-        float getRotationOfChar(unsigned long charnum, ExceptionCode&) const;
+        float getSubStringLength(long charnum, unsigned long nchars, ExceptionCode&) const;
+        FloatPoint getStartPositionOfChar(long charnum, ExceptionCode&) const;
+        FloatPoint getEndPositionOfChar(long charnum, ExceptionCode&) const;
+        FloatRect getExtentOfChar(long charnum, ExceptionCode&) const;
+        float getRotationOfChar(long charnum, ExceptionCode&) const;
         long getCharNumAtPosition(const FloatPoint&) const;
-        void selectSubString(unsigned long charnum, unsigned long nchars, ExceptionCode&) const;
+        void selectSubString(long charnum, long nchars, ExceptionCode&) const;
 
         virtual void parseMappedAttribute(MappedAttribute*);
 
index 12c9e3273ff3d1815bfcb2efde11bd5bf3ce91d8..ca277a9e2cd639ccec5a2e5cd90c9d267c474051 100644 (file)
@@ -62,13 +62,11 @@ namespace WebCore {
         float calculateGlyphHeight(RenderStyle*, int offset) const;
 
         FloatRect calculateGlyphBoundaries(RenderStyle*, int offset, const SVGChar&) const;
+        SVGChar* closestCharacterToPosition(int x, int y, int& offset) const;
 
     private:
         friend class RenderSVGInlineText;
         bool svgCharacterHitsPosition(int x, int y, int& offset) const;
-
-    private:
-        SVGChar* closestCharacterToPosition(int x, int y, int& offset) const;
     };
 
 } // namespace WebCore