Reviewed by Oliver.
authoroliver <oliver@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 12 Oct 2007 15:40:39 +0000 (15:40 +0000)
committeroliver <oliver@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 12 Oct 2007 15:40:39 +0000 (15:40 +0000)
Fixes: http://bugs.webkit.org/show_bug.cgi?id=6421 (<text> textLength attribute is not respected)
Fixes: http://bugs.webkit.org/show_bug.cgi?id=6422 (<text> lengthAdjust attribute is not respected)
Implement textLength and full lengthAdjust (both 'spacing' & 'spacingAndGlyphs' mode)
for <text> & <tspan> & friends. <textPath> is still todo, as it's special.

Also fix usage of cummulatedGlyphWidth/Height in SVGInlineTextBox, calculateGlyphBoundaries was
supposed to be used in the distance calculations, to take per character transformations into account (ie. rotation).

Fixes: svg/W3C-SVG-1.1/text-text-01-b.svg (complelty fixed the single W3C textLength testcase)
Partly fixed: svg/batik/text/textOnPathSpaces.svg (kerning support missing)
Partly fixed: svg/batik/text/textLayout.svg (word-letter spacing & textLength is todo)

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

31 files changed:
LayoutTests/ChangeLog
LayoutTests/platform/mac/svg/W3C-SVG-1.1/animate-elem-28-t-expected.checksum
LayoutTests/platform/mac/svg/W3C-SVG-1.1/animate-elem-28-t-expected.png
LayoutTests/platform/mac/svg/W3C-SVG-1.1/extend-namespace-01-f-expected.checksum
LayoutTests/platform/mac/svg/W3C-SVG-1.1/filters-felem-01-b-expected.checksum
LayoutTests/platform/mac/svg/W3C-SVG-1.1/filters-felem-01-b-expected.png
LayoutTests/platform/mac/svg/W3C-SVG-1.1/filters-tile-01-b-expected.checksum
LayoutTests/platform/mac/svg/W3C-SVG-1.1/interact-zoom-01-t-expected.checksum
LayoutTests/platform/mac/svg/W3C-SVG-1.1/interact-zoom-01-t-expected.png
LayoutTests/platform/mac/svg/W3C-SVG-1.1/text-text-01-b-expected.checksum
LayoutTests/platform/mac/svg/W3C-SVG-1.1/text-text-01-b-expected.png
LayoutTests/platform/mac/svg/W3C-SVG-1.1/text-text-01-b-expected.txt
LayoutTests/platform/mac/svg/custom/use-infinite-recursion-expected.checksum [new file with mode: 0644]
LayoutTests/svg/batik/text/textLayout-expected.checksum
LayoutTests/svg/batik/text/textLayout-expected.png
LayoutTests/svg/batik/text/textLayout-expected.txt
LayoutTests/svg/batik/text/textLength-expected.checksum
LayoutTests/svg/batik/text/textLength-expected.png
LayoutTests/svg/batik/text/textLength-expected.txt
LayoutTests/svg/batik/text/textOnPathSpaces-expected.checksum
LayoutTests/svg/batik/text/textOnPathSpaces-expected.png
LayoutTests/svg/batik/text/textOnPathSpaces-expected.txt
LayoutTests/svg/text/text-text-01-b-expected.checksum
LayoutTests/svg/text/text-text-01-b-expected.png
LayoutTests/svg/text/text-text-01-b-expected.txt
WebCore/ChangeLog
WebCore/ksvg2/svg/SVGTextContentElement.cpp
WebCore/rendering/SVGCharacterLayoutInfo.cpp
WebCore/rendering/SVGCharacterLayoutInfo.h
WebCore/rendering/SVGInlineTextBox.cpp
WebCore/rendering/SVGRootInlineBox.cpp

index 915b99df618700704803825195a406ffae0ce141..60e05ae31375b81ad5086b16f05de1f11f25a71f 100644 (file)
@@ -1,3 +1,34 @@
+2007-10-11  Nikolas Zimmermann  <zimmermann@kde.org>
+
+        Reviewed by Oliver.
+
+        Update SVG baseline after the textLength addition & string bound fixes.
+
+        * platform/mac/svg/W3C-SVG-1.1/animate-elem-28-t-expected.checksum:
+        * platform/mac/svg/W3C-SVG-1.1/animate-elem-28-t-expected.png:
+        * platform/mac/svg/W3C-SVG-1.1/extend-namespace-01-f-expected.checksum:
+        * platform/mac/svg/W3C-SVG-1.1/filters-felem-01-b-expected.checksum:
+        * platform/mac/svg/W3C-SVG-1.1/filters-felem-01-b-expected.png:
+        * platform/mac/svg/W3C-SVG-1.1/filters-tile-01-b-expected.checksum:
+        * platform/mac/svg/W3C-SVG-1.1/interact-zoom-01-t-expected.checksum:
+        * platform/mac/svg/W3C-SVG-1.1/interact-zoom-01-t-expected.png:
+        * platform/mac/svg/W3C-SVG-1.1/text-text-01-b-expected.checksum:
+        * platform/mac/svg/W3C-SVG-1.1/text-text-01-b-expected.png:
+        * platform/mac/svg/W3C-SVG-1.1/text-text-01-b-expected.txt:
+        * platform/mac/svg/custom/use-infinite-recursion-expected.checksum: Added. (was missing in SVN)
+        * svg/batik/text/textLayout-expected.checksum:
+        * svg/batik/text/textLayout-expected.png:
+        * svg/batik/text/textLayout-expected.txt:
+        * svg/batik/text/textLength-expected.checksum:
+        * svg/batik/text/textLength-expected.png:
+        * svg/batik/text/textLength-expected.txt:
+        * svg/batik/text/textOnPathSpaces-expected.checksum:
+        * svg/batik/text/textOnPathSpaces-expected.png:
+        * svg/batik/text/textOnPathSpaces-expected.txt:
+        * svg/text/text-text-01-b-expected.checksum:
+        * svg/text/text-text-01-b-expected.png:
+        * svg/text/text-text-01-b-expected.txt:
+
 2007-10-11  Oliver Hunt  <oliver@apple.com>
 
         Reviewed by Niko.
 
 2007-10-09  Nikolas Zimmermann  <zimmermann@kde.org>
 
-       Not reviewed.
+        Not reviewed.
 
-       Regenerate the SVG test baseline, they have been generated with _trunk_ instead of feature-branch.
-       Not sure who committed it, but it's wrong - so I'm fixing.
+        Regenerate the SVG test baseline, they have been generated with _trunk_ instead of feature-branch.
+        Not sure who committed it, but it's wrong - so I'm fixing.
 
         * platform/mac/svg/W3C-SVG-1.1/animate-elem-02-t-expected.txt:
         * platform/mac/svg/W3C-SVG-1.1/animate-elem-03-t-expected.txt:
index 8ec34c79f2da48cb4ad05225940bd287b001e93a..a3cb7f82d9e47cf83e8c0bc2455aa3df298806d0 100644 (file)
@@ -1 +1 @@
-eab09a32f511cf018741581bcb6ca7e5
\ No newline at end of file
+c2eafe7d15d5eb765e547380777938e2
index 5eba3dad6422b0c6f35179410c214930108fbe09..ef9d5824ea02c0094ecc5bffa7a43d90ae3acecc 100644 (file)
Binary files a/LayoutTests/platform/mac/svg/W3C-SVG-1.1/animate-elem-28-t-expected.png and b/LayoutTests/platform/mac/svg/W3C-SVG-1.1/animate-elem-28-t-expected.png differ
index ebee20f7359ad31df511a3978e040b908bca06ba..329b287c2acede9615944ad49c213641acbae7e9 100644 (file)
@@ -1 +1 @@
-6bec537adc9856ee908ffca80528e7a9
\ No newline at end of file
+62bbc3d96005b48293ea8bc88ec56719
index e3fe10a32d60418fe4abef3e5460be77068bba61..5a1de15262a57848758e82f3ddea6488abbb6d77 100644 (file)
@@ -1 +1 @@
-4354a4d77b3b055eb57f7a91c0a0b20f
\ No newline at end of file
+1d499e0b986f898aad120bf66766d84f
index 630d13f30c43ab9ff7bf2a399d05bf171b9757ec..0a5cc2d727e5cdad903643d71eeaf34a283d9b47 100644 (file)
Binary files a/LayoutTests/platform/mac/svg/W3C-SVG-1.1/filters-felem-01-b-expected.png and b/LayoutTests/platform/mac/svg/W3C-SVG-1.1/filters-felem-01-b-expected.png differ
index 48d08293ad4fc6c301e23daac8cb35ed68cd6328..711b3fd6a58cc8207fb5c52fef4c9dd0d4f31b69 100644 (file)
@@ -1 +1 @@
-4e6e3f115bd47f89e321c1a42d1a1f57
\ No newline at end of file
+5d3ef6ebe55194bbd3cafa8b4ea68d99
index efcaa44b7e765aaa02208185ad944eabd70e7a6e..6905b3068a97714c733006de463021815d749459 100644 (file)
@@ -1 +1 @@
-509baec6e114159582ee3223c656bba2
\ No newline at end of file
+b59579709fbd5bce51e44fc236326a10
index f026a1f09a1fd0d49e906d880c5c24a98c2bf0d8..74a5e8694f8ff05fdb4ac70c0588491213f976cb 100644 (file)
Binary files a/LayoutTests/platform/mac/svg/W3C-SVG-1.1/interact-zoom-01-t-expected.png and b/LayoutTests/platform/mac/svg/W3C-SVG-1.1/interact-zoom-01-t-expected.png differ
index 6485fd70785322fef1301da92123cb035bbf2136..04d6e0b4d7477a82202abe1a34794d11d82ffcfe 100644 (file)
@@ -1 +1 @@
-64d268ee88c03bed709732d4a87220f0
\ No newline at end of file
+945c16e5a6dd6e8ced662a900054023f
index 0fb649aaf7423004d00fef9323a1db9203196529..838986ecefbb33de27eb174c8321b15e96ba2d17 100644 (file)
Binary files a/LayoutTests/platform/mac/svg/W3C-SVG-1.1/text-text-01-b-expected.png and b/LayoutTests/platform/mac/svg/W3C-SVG-1.1/text-text-01-b-expected.png differ
index bda07d63699fcfe15fdc48a692b18f150bc50319..6ce41b9217746ec59380c5f2b3a1518e13d67703 100644 (file)
@@ -37,13 +37,13 @@ layer at (0,0) size 480x360
           RenderSVGText {text} at (76,44) size 52x6 contains 1 chunk(s)
             RenderSVGInlineText {#text} at (0,-5) size 52x6
               chunk 1 text run 1 at (76.00,44.00) startOffset 0 endOffset 21 width 52.00: "lengthAdjust: default"
-      RenderSVGContainer {g} at (4.50,135) size 454.50x66 [transform={m=((1.00,0.00)(0.00,1.00)) t=(0.00,22.00)}]
-        RenderSVGContainer {g} at (9,135) size 450x27
-          RenderSVGText {text} at (3,30) size 48x9 contains 1 chunk(s)
-            RenderSVGInlineText {#text} at (0,-7) size 48x9
+      RenderSVGContainer {g} at (4.50,135) size 420x66 [transform={m=((1.00,0.00)(0.00,1.00)) t=(0.00,22.00)}]
+        RenderSVGContainer {g} at (9,135) size 414x27
+          RenderSVGText {text} at (3,30) size 64x9 contains 1 chunk(s)
+            RenderSVGInlineText {#text} at (0,-7) size 64x9
               chunk 1 text run 1 at (3.00,30.00) startOffset 0 endOffset 15 width 48.00: "Line to Stretch"
-          RenderSVGText {text} at (75,30) size 78x9 contains 1 chunk(s)
-            RenderSVGInlineText {#text} at (0,-7) size 78x9
+          RenderSVGText {text} at (75,30) size 66x9 contains 1 chunk(s)
+            RenderSVGInlineText {#text} at (0,-7) size 66x9
               chunk 1 text run 1 at (75.00,30.00) startOffset 0 endOffset 25 width 78.00: "this is a line to squeeze"
         RenderSVGContainer {g} at (4.50,160.50) size 420x13.50
           RenderPath {line} at (6,160.50) size 201x3 [stroke={[type=SOLID] [color=#FF0000]}] [fill={[type=SOLID] [color=#000000]}] [data="M2.00,32.00L69.00,32.00"]
@@ -65,13 +65,13 @@ layer at (0,0) size 480x360
           RenderSVGText {text} at (76,44) size 52x6 contains 1 chunk(s)
             RenderSVGInlineText {#text} at (0,-5) size 52x6
               chunk 1 text run 1 at (76.00,44.00) startOffset 0 endOffset 21 width 52.00: "lengthAdjust: default"
-      RenderSVGContainer {g} at (4.50,201) size 454.50x66 [transform={m=((1.00,0.00)(0.00,1.00)) t=(0.00,44.00)}]
-        RenderSVGContainer {g} at (9,201) size 450x27
-          RenderSVGText {text} at (3,30) size 48x9 contains 1 chunk(s)
-            RenderSVGInlineText {#text} at (0,-7) size 48x9
+      RenderSVGContainer {g} at (4.50,201) size 420x66 [transform={m=((1.00,0.00)(0.00,1.00)) t=(0.00,44.00)}]
+        RenderSVGContainer {g} at (9,201) size 414x27
+          RenderSVGText {text} at (3,30) size 64x9 contains 1 chunk(s)
+            RenderSVGInlineText {#text} at (0,-7) size 64x9
               chunk 1 text run 1 at (3.00,30.00) startOffset 0 endOffset 15 width 48.00: "Line to Stretch"
-          RenderSVGText {text} at (75,30) size 78x9 contains 1 chunk(s)
-            RenderSVGInlineText {#text} at (0,-7) size 78x9
+          RenderSVGText {text} at (75,30) size 66x9 contains 1 chunk(s)
+            RenderSVGInlineText {#text} at (0,-7) size 66x9
               chunk 1 text run 1 at (75.00,30.00) startOffset 0 endOffset 25 width 78.00: "this is a line to squeeze"
         RenderSVGContainer {g} at (4.50,226.50) size 420x13.50
           RenderPath {line} at (6,226.50) size 201x3 [stroke={[type=SOLID] [color=#FF0000]}] [fill={[type=SOLID] [color=#000000]}] [data="M2.00,32.00L69.00,32.00"]
diff --git a/LayoutTests/platform/mac/svg/custom/use-infinite-recursion-expected.checksum b/LayoutTests/platform/mac/svg/custom/use-infinite-recursion-expected.checksum
new file mode 100644 (file)
index 0000000..d69a371
--- /dev/null
@@ -0,0 +1 @@
+853de00567d121bea0b7bece66a5d61c
\ No newline at end of file
index 3e8bf1c239a0a2021e082ea616ae0687e4c6d25d..4a2727cdade9a2ce366037744da7f82d1845c18d 100644 (file)
@@ -1 +1 @@
-d1a743c431f0f2de24ac21dd03891d46
\ No newline at end of file
+d4c70f2c2714cc28b3c000e21e780d33
\ No newline at end of file
index efeac5b177f8d721a40f75cf319a907560a27a8d..69b681609d09ffdb4fed59ea09e81b5f9c4cccf7 100644 (file)
Binary files a/LayoutTests/svg/batik/text/textLayout-expected.png and b/LayoutTests/svg/batik/text/textLayout-expected.png differ
index 079d737969c2db935de320093476f7a129eafcd1..ffafbf3540209e7e99da0ec367d4b80d9f00f4e3 100644 (file)
@@ -44,16 +44,16 @@ layer at (0,0) size 450x500
       RenderSVGText {text} at (102,150) size 246x13 contains 1 chunk(s)
         RenderSVGInlineText {#text} at (0,-10) size 246x13
           chunk 1 (middle anchor) text run 1 at (102.00,150.00) startOffset 0 endOffset 59 width 246.00: "Letter Spacing Adjustment and Explicit Length Specification"
-      RenderSVGContainer {g} at (40,158) size 69x39
-        RenderSVGText {text} at (40,180) size 69x28 contains 1 chunk(s)
-          RenderSVGInlineText {#text} at (0,-22) size 69x28
+      RenderSVGContainer {g} at (40,158) size 112x39
+        RenderSVGText {text} at (40,180) size 112x28 contains 1 chunk(s)
+          RenderSVGInlineText {#text} at (0,-22) size 112x28
             chunk 1 text run 1 at (40.00,180.00) startOffset 0 endOffset 6 width 69.00: "sample"
         RenderSVGText {text} at (40,195) size 58x9 contains 1 chunk(s)
           RenderSVGInlineText {#text} at (0,-7) size 58x9
             chunk 1 text run 1 at (40.00,195.00) startOffset 0 endOffset 16 width 58.00: "textLength=\"120\""
-      RenderSVGContainer {g} at (185,158) size 69x39
-        RenderSVGText {text} at (185,180) size 69x28 contains 1 chunk(s)
-          RenderSVGInlineText {#text} at (0,-22) size 69x28
+      RenderSVGContainer {g} at (185,158) size 70x39
+        RenderSVGText {text} at (185,180) size 70x28 contains 1 chunk(s)
+          RenderSVGInlineText {#text} at (0,-22) size 70x28
             chunk 1 text run 1 at (185.00,180.00) startOffset 0 endOffset 6 width 69.00: "sample"
         RenderSVGText {text} at (185,195) size 54x9 contains 1 chunk(s)
           RenderSVGInlineText {#text} at (0,-7) size 54x9
@@ -116,16 +116,16 @@ layer at (0,0) size 450x500
       RenderSVGText {text} at (171,320) size 108x13 contains 1 chunk(s)
         RenderSVGInlineText {#text} at (0,-10) size 108x13
           chunk 1 (middle anchor) text run 1 at (171.50,320.00) startOffset 0 endOffset 23 width 107.00: "Word Spacing Adjustment"
-      RenderSVGContainer {g} at (40,337) size 199x30
-        RenderSVGText {text} at (40,350) size 199x17 contains 1 chunk(s)
-          RenderSVGInlineText {#text} at (0,-13) size 199x17
+      RenderSVGContainer {g} at (40,337) size 214x30
+        RenderSVGText {text} at (40,350) size 214x17 contains 1 chunk(s)
+          RenderSVGInlineText {#text} at (0,-13) size 214x17
             chunk 1 text run 1 at (40.00,350.00) startOffset 0 endOffset 29 width 334.00: "Wide separation between words"
         RenderSVGText {text} at (40,365) size 130x9 contains 1 chunk(s)
           RenderSVGInlineText {#text} at (0,-7) size 130x9
             chunk 1 text run 1 at (40.00,365.00) startOffset 0 endOffset 35 width 130.00: "textLength=\"350\" word-spacing=\"3em\""
-      RenderSVGContainer {g} at (40,382) size 213x30
-        RenderSVGText {text} at (40,395) size 213x17 contains 1 chunk(s)
-          RenderSVGInlineText {#text} at (0,-13) size 213x17
+      RenderSVGContainer {g} at (40,382) size 360x30
+        RenderSVGText {text} at (40,395) size 360x17 contains 1 chunk(s)
+          RenderSVGInlineText {#text} at (0,-13) size 360x17
             chunk 1 text run 1 at (40.00,395.00) startOffset 0 endOffset 31 width 198.00: "Narrow separation between words"
         RenderSVGText {text} at (40,410) size 123x9 contains 1 chunk(s)
           RenderSVGInlineText {#text} at (0,-7) size 123x9
index f8709f8c2e8889b44fc297262e66a208caea1f42..dad760a012eee318d7880e0625aa70846dfb8b08 100644 (file)
@@ -1 +1 @@
-6c54bd25b8bfe2a9f95fc962239ea1b6
\ No newline at end of file
+85d32e2fbc2dfc00d78f5758ec6a7f14
\ No newline at end of file
index 0f0187e498de9e65db1acb1afc1b35bd5877d6c0..8ec59a4d868f4012dacd3d0908443baf1595711b 100644 (file)
Binary files a/LayoutTests/svg/batik/text/textLength-expected.png and b/LayoutTests/svg/batik/text/textLength-expected.png differ
index c71092d227b5b9adaa4b341bec23579f9f8dfdb0..ecd785592fd65bfc6cf305d42ebef7ecaffb282c 100644 (file)
@@ -93,9 +93,9 @@ layer at (0,0) size 450x500
                 RenderSVGContainer {g} at (200,213) size 50x24
                   RenderPath {rect} at (200,215) size 50x20 [fill={[type=SOLID] [color=#DDE8FF]}] [data="M200.00,5.00L250.00,5.00L250.00,25.00L200.00,25.00"]
                   RenderPath {line} at (224.50,213) size 1x24 [stroke={[type=SOLID] [color=#FF0000]}] [fill={[type=SOLID] [color=#000000]}] [data="M225.00,3.00L225.00,27.00"]
-        RenderSVGText {text} at (212,19) size 26x14 contains 1 chunk(s)
-          RenderSVGInlineText {#text} at (0,-11) size 26x14
-            chunk 1 (middle anchor) text run 1 at (212.50,19.00) startOffset 0 endOffset 5 width 25.00: "Batik"
+        RenderSVGText {text} at (202,19) size 46x14 contains 1 chunk(s)
+          RenderSVGInlineText {#text} at (0,-11) size 46x14
+            chunk 1 (middle anchor) text run 1 at (202.50,19.00) startOffset 0 endOffset 5 width 25.00: "Batik"
         RenderSVGText {text} at (127,40) size 196x14 contains 1 chunk(s)
           RenderSVGInlineText {#text} at (0,-11) size 196x14
             chunk 1 (middle anchor) text run 1 at (127.00,40.00) startOffset 0 endOffset 38 width 196.00: "textLength=\"50\" lengthAdjust=\"spacing\""
index 80b01a65285f3a3fb1b1ec6d9714f798e8fb6671..bac99ede72f3c4914b2d6ef6ad105c393a77c32d 100644 (file)
@@ -1 +1 @@
-91a008e0253f60e8d05d36a9a47e51b9
\ No newline at end of file
+59ea8c331ed40be8a21570bdaa6d87b2
\ No newline at end of file
index 2ad96593426ba326ba550e73fd4c7be820f5b2cd..cd93b35e7b6989fba7102c4cc150bbd8cca33357 100644 (file)
Binary files a/LayoutTests/svg/batik/text/textOnPathSpaces-expected.png and b/LayoutTests/svg/batik/text/textOnPathSpaces-expected.png differ
index 64714b126145c34d8b9ab7594fba014afc8b9410..d1f616c5123779549b9f6306d615f5bf0e6baa19 100644 (file)
@@ -43,15 +43,15 @@ layer at (0,0) size 450x500
         RenderSVGText {text} at (35,70) size 34x13 contains 1 chunk(s)
           RenderSVGInlineText {#text} at (0,-10) size 34x13
             chunk 1 text run 1 at (35.00,70.00) startOffset 0 endOffset 7 width 34.00: "y=\"110\""
-      RenderSVGContainer {g} at (302,54) size 133x79 [transform={m=((1.00,0.00)(0.00,1.00)) t=(300.00,70.00)}]
+      RenderSVGContainer {g} at (302,61) size 133x72 [transform={m=((1.00,0.00)(0.00,1.00)) t=(300.00,70.00)}]
         RenderSVGContainer {use} at (314.89,77.29) size 120.11x30.43
           RenderSVGContainer {g} at (314.89,77.29) size 120.11x30.43
             RenderPath {path} at (314.89,77.29) size 120.11x30.43 [transform={m=((0.15,0.00)(0.00,0.15)) t=(0.00,0.00)}] [stroke={[type=SOLID] [color=#0000FF] [stroke width=2.00]}] [data="M100.00,200.00C200.00,100.00,300.00,0.00,400.00,100.00C500.00,200.00,600.00,300.00,700.00,200.00C800.00,100.00,900.00,100.00,900.00,100.00"]
-        RenderSVGText {text} at (17,8) size 109x72 contains 1 chunk(s)
-          RenderSVGTextPath {textPath} at (0,0) size 109x72
-            RenderSVGTSpan {tspan} at (0,0) size 109x72
-              RenderSVGInlineText {#text} at (-15,-24) size 109x72
-                chunk 1 text run 1 at (17.83,8.83) startOffset 0 endOffset 6 width 58.00: "sample"
+        RenderSVGText {text} at (17,9) size 106x50 contains 1 chunk(s)
+          RenderSVGTextPath {textPath} at (0,0) size 106x50
+            RenderSVGTSpan {tspan} at (0,0) size 106x50
+              RenderSVGInlineText {#text} at (-15,-18) size 106x50
+                chunk 1 text run 1 at (17.83,9.88) startOffset 0 endOffset 6 width 58.00: "sample"
           RenderSVGInlineText {#text} at (0,0) size 0x0
         RenderSVGText {text} at (15,60) size 118x13 contains 1 chunk(s)
           RenderSVGInlineText {#text} at (0,-10) size 118x13
index 39ae0fc4d49f1382cb5e82e896ad73ca9a66961f..c67cb6c08cb2906dad2d28fdfe2a06d493c49cc0 100644 (file)
@@ -1 +1 @@
-0bb60b52fc5e3563650aabc77576d0ab
\ No newline at end of file
+0e1ba3e53934964b0dbb227f649c5b09
\ No newline at end of file
index 80dabae996bfa0912d48b8b33eeb55442a34e407..36e10f1531f263354a165014bea528c6a4c77f86 100644 (file)
Binary files a/LayoutTests/svg/text/text-text-01-b-expected.png and b/LayoutTests/svg/text/text-text-01-b-expected.png differ
index f5c40d6d04faebfdecf8e262779b4759cb593f16..0f8db33b1f3d9838ddb684554148b409e77a1746 100644 (file)
@@ -37,13 +37,13 @@ layer at (0,0) size 800x600
           RenderSVGText {text} at (76,44) size 52x6 contains 1 chunk(s)
             RenderSVGInlineText {#text} at (0,-5) size 52x6
               chunk 1 text run 1 at (76.00,44.00) startOffset 0 endOffset 21 width 52.00: "lengthAdjust: default"
-      RenderSVGContainer {g} at (7.50,225) size 757.50x110 [transform={m=((1.00,0.00)(0.00,1.00)) t=(0.00,22.00)}]
-        RenderSVGContainer {g} at (15,225) size 750x45
-          RenderSVGText {text} at (3,30) size 48x9 contains 1 chunk(s)
-            RenderSVGInlineText {#text} at (0,-7) size 48x9
+      RenderSVGContainer {g} at (7.50,225) size 700x110 [transform={m=((1.00,0.00)(0.00,1.00)) t=(0.00,22.00)}]
+        RenderSVGContainer {g} at (15,225) size 690x45
+          RenderSVGText {text} at (3,30) size 64x9 contains 1 chunk(s)
+            RenderSVGInlineText {#text} at (0,-7) size 64x9
               chunk 1 text run 1 at (3.00,30.00) startOffset 0 endOffset 15 width 48.00: "Line to Stretch"
-          RenderSVGText {text} at (75,30) size 78x9 contains 1 chunk(s)
-            RenderSVGInlineText {#text} at (0,-7) size 78x9
+          RenderSVGText {text} at (75,30) size 66x9 contains 1 chunk(s)
+            RenderSVGInlineText {#text} at (0,-7) size 66x9
               chunk 1 text run 1 at (75.00,30.00) startOffset 0 endOffset 25 width 78.00: "this is a line to squeeze"
         RenderSVGContainer {g} at (7.50,267.50) size 700x22.50
           RenderPath {line} at (10,267.50) size 335x5 [stroke={[type=SOLID] [color=#FF0000]}] [fill={[type=SOLID] [color=#000000]}] [data="M2.00,32.00L69.00,32.00"]
@@ -65,13 +65,13 @@ layer at (0,0) size 800x600
           RenderSVGText {text} at (76,44) size 52x6 contains 1 chunk(s)
             RenderSVGInlineText {#text} at (0,-5) size 52x6
               chunk 1 text run 1 at (76.00,44.00) startOffset 0 endOffset 21 width 52.00: "lengthAdjust: default"
-      RenderSVGContainer {g} at (7.50,335) size 757.50x110 [transform={m=((1.00,0.00)(0.00,1.00)) t=(0.00,44.00)}]
-        RenderSVGContainer {g} at (15,335) size 750x45
-          RenderSVGText {text} at (3,30) size 48x9 contains 1 chunk(s)
-            RenderSVGInlineText {#text} at (0,-7) size 48x9
+      RenderSVGContainer {g} at (7.50,335) size 700x110 [transform={m=((1.00,0.00)(0.00,1.00)) t=(0.00,44.00)}]
+        RenderSVGContainer {g} at (15,335) size 690x45
+          RenderSVGText {text} at (3,30) size 64x9 contains 1 chunk(s)
+            RenderSVGInlineText {#text} at (0,-7) size 64x9
               chunk 1 text run 1 at (3.00,30.00) startOffset 0 endOffset 15 width 48.00: "Line to Stretch"
-          RenderSVGText {text} at (75,30) size 78x9 contains 1 chunk(s)
-            RenderSVGInlineText {#text} at (0,-7) size 78x9
+          RenderSVGText {text} at (75,30) size 66x9 contains 1 chunk(s)
+            RenderSVGInlineText {#text} at (0,-7) size 66x9
               chunk 1 text run 1 at (75.00,30.00) startOffset 0 endOffset 25 width 78.00: "this is a line to squeeze"
         RenderSVGContainer {g} at (7.50,377.50) size 700x22.50
           RenderPath {line} at (10,377.50) size 335x5 [stroke={[type=SOLID] [color=#FF0000]}] [fill={[type=SOLID] [color=#000000]}] [data="M2.00,32.00L69.00,32.00"]
index cc730f0b7d810e0811658146ac753257e1c0c628..88d630330f3a260456cc22d5e3578c48d8b89d85 100644 (file)
@@ -1,3 +1,44 @@
+2007-10-11  Nikolas Zimmermann  <zimmermann@kde.org>
+
+        Reviewed by Oliver.
+
+        Fixes: http://bugs.webkit.org/show_bug.cgi?id=6421 (<text> textLength attribute is not respected)
+        Fixes: http://bugs.webkit.org/show_bug.cgi?id=6422 (<text> lengthAdjust attribute is not respected)
+
+        Implement textLength and full lengthAdjust (both 'spacing' & 'spacingAndGlyphs' mode)
+        for <text> & <tspan> & friends. <textPath> is still todo, as it's special.
+
+        Also fix usage of cummulatedGlyphWidth/Height in SVGInlineTextBox, calculateGlyphBoundaries was
+        supposed to be used in the distance calculations, to take per character transformations into account (ie. rotation).
+
+        Fixes: svg/W3C-SVG-1.1/text-text-01-b.svg (complelty fixed the single W3C textLength testcase)
+        Partly fixed: svg/batik/text/textOnPathSpaces.svg (kerning support missing)
+        Partly fixed: svg/batik/text/textLayout.svg (word-letter spacing & textLength is todo)
+
+        * ksvg2/svg/SVGTextContentElement.cpp:
+        (WebCore::SVGTextContentElement::SVGTextContentElement):
+        (WebCore::SVGTextContentElement::parseMappedAttribute):
+        * rendering/SVGCharacterLayoutInfo.cpp:
+        (WebCore::SVGCharacterLayoutInfo::nextPathLayoutPointAndAngle):
+        * rendering/SVGCharacterLayoutInfo.h:
+        (WebCore::SVGTextChunk::SVGTextChunk):
+        (WebCore::SVGTextChunkWalker::operator()):
+        * rendering/SVGInlineTextBox.cpp:
+        (WebCore::SVGInlineTextBoxClosestCharacterToPositionWalker::chunkPortionCallback):
+        (WebCore::SVGInlineTextBoxSelectionRectWalker::chunkPortionCallback):
+        (WebCore::SVGInlineTextBox::svgCharacterHitsPosition):
+        * rendering/SVGRootInlineBox.cpp:
+        (WebCore::SVGRootInlineBoxPaintWalker::chunkPortionCallback):
+        (WebCore::cummulatedWidthOrHeightOfTextChunk):
+        (WebCore::cummulatedWidthOfTextChunk):
+        (WebCore::cummulatedHeightOfTextChunk):
+        (WebCore::applyTextAnchorToTextChunk):
+        (WebCore::applyTextLengthCorrectionToTextChunk):
+        (WebCore::SVGRootInlineBox::buildLayoutInformationForTextBox):
+        (WebCore::SVGRootInlineBox::buildTextChunks):
+        (WebCore::SVGRootInlineBox::layoutTextChunks):
+        (WebCore::SVGRootInlineBox::walkTextChunks):
+
 2007-10-11  Oliver Hunt  <oliver@apple.com>
 
         Reviewed by Niko.
index 20985b3a75039877a643d73390018d5a4be99330..2d250fc6f090047f21d1b739683395a1d94708d6 100644 (file)
@@ -40,8 +40,8 @@ SVGTextContentElement::SVGTextContentElement(const QualifiedName& tagName, Docum
     , SVGTests()
     , SVGLangSpace()
     , SVGExternalResourcesRequired()
-    , m_textLength(this, LengthModeWidth)
-    , m_lengthAdjust(0)
+    , m_textLength(this, LengthModeOther)
+    , m_lengthAdjust(LENGTHADJUST_SPACING)
 {
 }
 
@@ -98,10 +98,12 @@ void SVGTextContentElement::selectSubString(unsigned long charnum, unsigned long
 
 void SVGTextContentElement::parseMappedAttribute(MappedAttribute* attr)
 {
-    //if (attr->name() == SVGNames::lengthAdjustAttr)
-    //    setXBaseValue(SVGLength(this, LengthModeWidth, attr->value()));
-    //else
-    if (attr->name() == SVGNames::textLengthAttr) {
+    if (attr->name() == SVGNames::lengthAdjustAttr) {
+        if (attr->value() == "spacing")
+            setLengthAdjustBaseValue(LENGTHADJUST_SPACING);
+        else if (attr->value() == "spacingAndGlyphs")
+            setLengthAdjustBaseValue(LENGTHADJUST_SPACINGANDGLYPHS);
+    } else if (attr->name() == SVGNames::textLengthAttr) {
         setTextLengthBaseValue(SVGLength(this, LengthModeOther, attr->value()));
         if (textLength().value() < 0.0)
             document()->accessSVGExtensions()->reportError("A negative value for text attribute <textLength> is not allowed");
index 90ba5d0e76dd95c1255374f62f691d2d3abcc6a8..c80256bfd44df8160539014042d98225402e5631 100644 (file)
@@ -217,7 +217,7 @@ void SVGCharacterLayoutInfo::processedChunk(float savedShiftX, float savedShiftY
     }
 }
 
-bool SVGCharacterLayoutInfo::nextPathLayoutPointAndAngle(float& x, float& y, float& angle, float glyphAdvance, float newOffset)
+bool SVGCharacterLayoutInfo::nextPathLayoutPointAndAngle(float& x, float& y, float& angle, float glyphAdvance, float extraAdvance, float newOffset)
 {
     if (layoutPathLength <= 0.0)
         return false;
@@ -225,6 +225,9 @@ bool SVGCharacterLayoutInfo::nextPathLayoutPointAndAngle(float& x, float& y, flo
     if (newOffset != FLT_MIN)
         currentOffset = startOffset + newOffset;
 
+    // Respect translation along path (extraAdvance is orthogonal to the path)
+    currentOffset += extraAdvance;
+
     float offset = currentOffset + glyphAdvance / 2.0;
     currentOffset += glyphAdvance;
 
index 314c2016e951b79e8f7e48f9e41c5b53bbd22b2b..fa9f408770895ffe48088ecb7cf451e89be735e8 100644 (file)
@@ -32,6 +32,7 @@
 
 #include "AffineTransform.h"
 #include "SVGRenderStyle.h"
+#include "SVGTextContentElement.h"
 
 namespace WebCore {
 
@@ -96,7 +97,7 @@ struct SVGCharacterLayoutInfo {
     void processedChunk(float savedShiftX, float savedShiftY);
     void processedSingleCharacter();
 
-    bool nextPathLayoutPointAndAngle(float& x, float& y, float& angle, float glyphAdvance, float newOffset);
+    bool nextPathLayoutPointAndAngle(float& x, float& y, float& angle, float glyphAdvance, float extraAdvance, float newOffset);
 
     // Used for text-on-path.
     void addLayoutInformation(InlineFlowBox*, float textAnchorOffset = 0.0);
@@ -202,19 +203,34 @@ struct SVGInlineBoxCharacterRange {
     InlineBox* box;
 };
 
+// Convenience typedef
+typedef SVGTextContentElement::SVGLengthAdjustType ELengthAdjust;
+
 struct SVGTextChunk {
     SVGTextChunk()
         : anchor(TA_START)
+        , textLength(0.0)
+        , lengthAdjust(SVGTextContentElement::LENGTHADJUST_SPACING)
+        , ctm()
         , isVerticalText(false)
         , isTextPath(false)
         , start(0)
         , end(0)
     { }
 
+    // text-anchor support
     ETextAnchor anchor;
+
+    // textLength & lengthAdjust support
+    float textLength;
+    ELengthAdjust lengthAdjust;
+    AffineTransform ctm;
+
+    // status flags
     bool isVerticalText : 1;
     bool isTextPath : 1;
 
+    // main chunk data
     Vector<SVGChar>::iterator start;
     Vector<SVGChar>::iterator end;
 
@@ -224,8 +240,9 @@ struct SVGTextChunk {
 struct SVGTextChunkWalkerBase {
     virtual ~SVGTextChunkWalkerBase() { }
 
-    virtual void operator()(SVGInlineTextBox* textBox, int startOffset, const Vector<SVGChar>::iterator& start, const Vector<SVGChar>::iterator& end) = 0;
-    
+    virtual void operator()(SVGInlineTextBox* textBox, int startOffset, const AffineTransform& chunkCtm,
+                            const Vector<SVGChar>::iterator& start, const Vector<SVGChar>::iterator& end) = 0;
+
     // Followings methods are only used for painting text chunks
     virtual void start(InlineBox*) = 0;
     virtual void end(InlineBox*) = 0;
@@ -239,6 +256,7 @@ struct SVGTextChunkWalker : public SVGTextChunkWalkerBase {
 public:
     typedef void (CallbackClass::*SVGTextChunkWalkerCallback)(SVGInlineTextBox* textBox,
                                                               int startOffset,
+                                                              const AffineTransform& chunkCtm,
                                                               const Vector<SVGChar>::iterator& start,
                                                               const Vector<SVGChar>::iterator& end);
 
@@ -266,9 +284,10 @@ public:
         ASSERT(walker);
     }
 
-    virtual void operator()(SVGInlineTextBox* textBox, int startOffset, const Vector<SVGChar>::iterator& start, const Vector<SVGChar>::iterator& end)
+    virtual void operator()(SVGInlineTextBox* textBox, int startOffset, const AffineTransform& chunkCtm,
+                            const Vector<SVGChar>::iterator& start, const Vector<SVGChar>::iterator& end)
     {
-        (*m_object.*m_walkerCallback)(textBox, startOffset, start, end);
+        (*m_object.*m_walkerCallback)(textBox, startOffset, chunkCtm, start, end);
     }
 
     // Followings methods are only used for painting text chunks
index 9a3753b9d136feac65b0391d18ec8e2377dccd70..14b4f2b6b2133e29a64ff91252b2786630cae194 100644 (file)
@@ -125,7 +125,8 @@ struct SVGInlineTextBoxClosestCharacterToPositionWalker {
     {
     }
 
-    void chunkPortionCallback(SVGInlineTextBox* textBox, int startOffset, const Vector<SVGChar>::iterator& start, const Vector<SVGChar>::iterator& end)
+    void chunkPortionCallback(SVGInlineTextBox* textBox, int startOffset, const AffineTransform& chunkCtm,
+                              const Vector<SVGChar>::iterator& start, const Vector<SVGChar>::iterator& end)
     {
         RenderStyle* style = textBox->textObject()->style();
 
@@ -139,12 +140,11 @@ struct SVGInlineTextBoxClosestCharacterToPositionWalker {
             if (textBox->m_reversed)
                 newOffset = textBox->start() + textBox->end() - newOffset;
 
-            float glyphWidth = textBox->calculateGlyphWidth(style, newOffset);
-            float glyphHeight = textBox->calculateGlyphHeight(style, newOffset);
+            FloatRect glyphRect = chunkCtm.mapRect(textBox->calculateGlyphBoundaries(style, newOffset, *it));
 
             // Calculate distances relative to the glyph mid-point. I hope this is accurate enough.
-            float xDistance = (*it).x + glyphWidth / 2.0 - m_x;
-            float yDistance = (*it).y - glyphHeight / 2.0 - m_y;
+            float xDistance = glyphRect.x() + glyphRect.width() / 2.0 - m_x;
+            float yDistance = glyphRect.y() - glyphRect.height() / 2.0 - m_y;
 
             float newDistance = sqrt(xDistance * xDistance + yDistance * yDistance);
             if (newDistance <= m_distance) {
@@ -189,7 +189,8 @@ struct SVGInlineTextBoxSelectionRectWalker {
     {
     }
 
-    void chunkPortionCallback(SVGInlineTextBox* textBox, int startOffset, const Vector<SVGChar>::iterator& start, const Vector<SVGChar>::iterator& end)
+    void chunkPortionCallback(SVGInlineTextBox* textBox, int startOffset, const AffineTransform& chunkCtm,
+                              const Vector<SVGChar>::iterator& start, const Vector<SVGChar>::iterator& end)
     {
         RenderStyle* style = textBox->textObject()->style();
 
@@ -202,6 +203,8 @@ struct SVGInlineTextBoxSelectionRectWalker {
 
             m_selectionRect.unite(textBox->calculateGlyphBoundaries(style, newOffset, *it));
         }
+
+        m_selectionRect = chunkCtm.mapRect(m_selectionRect);
     }
 
     FloatRect selectionRect() const
@@ -234,9 +237,7 @@ bool SVGInlineTextBox::svgCharacterHitsPosition(int x, int y, int& offset) const
 
     SVGChar& charAtPos = *charAtPosPtr;
     RenderStyle* style = textObject()->style(m_firstLine);
-
-    float glyphWidth = calculateGlyphWidth(style, offset);
-    float glyphHeight = calculateGlyphHeight(style, offset);
+    FloatRect glyphRect = calculateGlyphBoundaries(style, offset, charAtPos);
 
     if (m_reversed)
         offset++;
@@ -245,7 +246,7 @@ bool SVGInlineTextBox::svgCharacterHitsPosition(int x, int y, int& offset) const
     // (#13910) This code does not handle bottom-to-top/top-to-bottom vertical text.
 
     // Check whether y position hits the current character 
-    if (y < charAtPos.y - glyphHeight || y > charAtPos.y)
+    if (y < charAtPos.y - glyphRect.height() || y > charAtPos.y)
         return false;
 
     // Check whether x position hits the current character
@@ -259,11 +260,11 @@ bool SVGInlineTextBox::svgCharacterHitsPosition(int x, int y, int& offset) const
     }
 
     // If we are past the last glyph of this box, don't mark it as 'hit' anymore.
-    if (x >= charAtPos.x + glyphWidth && offset == (int) end())
+    if (x >= charAtPos.x + glyphRect.width() && offset == (int) end())
         return false;
 
     // Snap to character at half of it's advance
-    if (x >= charAtPos.x + glyphWidth / 2.0)
+    if (x >= charAtPos.x + glyphRect.width() / 2.0)
         offset += m_reversed ? -1 : 1;
 
     return true;
index 709fe6e4cbe2a66635dcf56e1cdcb7f6d1b1af8a..4c82b3724d024b45759bdc5d3fd645923f80bada 100644 (file)
@@ -253,7 +253,8 @@ struct SVGRootInlineBoxPaintWalker {
         return false;
     }
 
-    void chunkPortionCallback(SVGInlineTextBox* textBox, int startOffset, const Vector<SVGChar>::iterator& start, const Vector<SVGChar>::iterator& end)
+    void chunkPortionCallback(SVGInlineTextBox* textBox, int startOffset, const AffineTransform& chunkCtm,
+                              const Vector<SVGChar>::iterator& start, const Vector<SVGChar>::iterator& end)
     {
         RenderText* text = textBox->textObject();
         ASSERT(text);
@@ -269,6 +270,9 @@ struct SVGRootInlineBoxPaintWalker {
         IntPoint decorationOrigin;
         SVGTextDecorationInfo info;
 
+        if (!chunkCtm.isIdentity())
+            m_paintInfo.context->concatCTM(chunkCtm);
+
         for (Vector<SVGChar>::iterator it = start; it != end; ++it) {
             if (!(*it).visible)
                 continue;
@@ -308,6 +312,9 @@ struct SVGRootInlineBoxPaintWalker {
             // Skip processed characters
             it = itSearch - 1;
         }
+
+        if (!chunkCtm.isIdentity())
+            m_paintInfo.context->concatCTM(chunkCtm.inverse());
     }
 
 private:
@@ -412,51 +419,89 @@ TextStyle svgTextStyleForInlineTextBox(RenderStyle* style, const InlineTextBox*
     return TextStyle(false, xPos, textBox->toAdd(), textBox->m_reversed, textBox->m_dirOverride || style->visuallyOrdered());
 }
 
-static float cummulatedWidthOfTextChunk(SVGTextChunk& chunk)
+static float cummulatedWidthOrHeightOfTextChunk(SVGTextChunk& chunk, bool calcWidthOnly)
 {
-    float width = 0.0;
+    float length = 0.0;
+    Vector<SVGChar>::iterator charIt = chunk.start;
 
     Vector<SVGInlineBoxCharacterRange>::iterator it = chunk.boxes.begin();
     Vector<SVGInlineBoxCharacterRange>::iterator end = chunk.boxes.end();
 
-    for (; it != end; ++it)
-        width += cummulatedWidthOfInlineBoxCharacterRange(*it);
+    for (; it != end; ++it) {
+        SVGInlineBoxCharacterRange& range = *it;
 
-    return width;
-}
+        SVGInlineTextBox* box = static_cast<SVGInlineTextBox*>(range.box);
+        RenderStyle* style = box->object()->style();
 
-static float cummulatedHeightOfTextChunk(SVGTextChunk& chunk)
-{
-    float height = 0.0;
+        for (int i = range.startOffset; i < range.endOffset; ++i) {
+            ASSERT(charIt <= chunk.end);
 
-    Vector<SVGInlineBoxCharacterRange>::iterator it = chunk.boxes.begin();
-    Vector<SVGInlineBoxCharacterRange>::iterator end = chunk.boxes.end();
+            // Determine how many characters - starting from the current - can be measured at once.
+            // Important for non-absolute positioned non-latin1 text (ie. Arabic) where ie. the width
+            // of a string is not the sum of the boundaries of all contained glyphs.
+            Vector<SVGChar>::iterator itSearch = charIt + 1;
+            Vector<SVGChar>::iterator endSearch = charIt + range.endOffset - i;
+            while (itSearch != endSearch) {
+                if ((*itSearch).drawnSeperated)
+                    break;
+
+                itSearch++;
+            }
 
-    for (; it != end; ++it)
-        height += cummulatedHeightOfInlineBoxCharacterRange(*it);
+            unsigned int positionOffset = itSearch - charIt;
 
-    return height;
-}
+            // Calculate width/height of subrange
+            SVGInlineBoxCharacterRange subRange;
+            subRange.box = range.box;
+            subRange.startOffset = i;
+            subRange.endOffset = i + positionOffset;
 
-static void applyTextAnchorToTextChunk(SVGTextChunk& chunk)
-{
-#if DEBUG_CHUNK_BUILDING > 0
-    {
-        fprintf(stderr, "Handle TEXT CHUNK! anchor=%i, isVerticalText=%i, isTextPath=%i start=%p, end=%p -> dist: %i\n",
-                (int) chunk.anchor, (int) chunk.isVerticalText, (int) chunk.isTextPath, chunk.start, chunk.end, (unsigned int) (chunk.end-chunk.start));
+            if (calcWidthOnly)
+                length += cummulatedWidthOfInlineBoxCharacterRange(subRange);
+            else
+                length += cummulatedHeightOfInlineBoxCharacterRange(subRange);
 
-        Vector<SVGInlineBoxCharacterRange>::iterator boxIt = chunk.boxes.begin();
-        Vector<SVGInlineBoxCharacterRange>::iterator boxEnd = chunk.boxes.end();
+            // Calculate gap between the previous & current range
+            // <text x="10 50 70">ABCD</text> - we need to take the gaps between A & B into account
+            // so add "40" as width, and analogous for B & C, add "20" as width.
+            if (itSearch > chunk.start && itSearch < chunk.end) {
+                SVGChar& lastCharacter = *(itSearch - 1);
+                SVGChar& currentCharacter = *itSearch;
 
-        unsigned int i = 0;
-        for (; boxIt != boxEnd; ++boxIt) {
-            SVGInlineBoxCharacterRange& range = *boxIt; i++;
-            fprintf(stderr, "RANGE %i STARTOFFSET: %i, ENDOFFSET: %i, BOX: %p\n", i, range.startOffset, range.endOffset, range.box);
+                int offset = box->m_reversed ? box->end() - i - positionOffset + 1: box->start() + i + positionOffset - 1;
+
+                if (calcWidthOnly) {
+                    float lastGlyphWidth = box->calculateGlyphWidth(style, offset);
+                    length += currentCharacter.x - lastCharacter.x - lastGlyphWidth;
+                } else {
+                    float lastGlyphHeight = box->calculateGlyphHeight(style, offset);
+                    length += currentCharacter.y - lastCharacter.y - lastGlyphHeight;
+                }
+            }
+
+            // Advance processed characters
+            i += positionOffset - 1;
+            charIt = itSearch;
         }
     }
-#endif
 
-    if (chunk.anchor == TA_START || chunk.isTextPath)
+    ASSERT(charIt == chunk.end);
+    return length;
+}
+
+static float cummulatedWidthOfTextChunk(SVGTextChunk& chunk)
+{
+    return cummulatedWidthOrHeightOfTextChunk(chunk, true);
+}
+
+static float cummulatedHeightOfTextChunk(SVGTextChunk& chunk)
+{
+    return cummulatedWidthOrHeightOfTextChunk(chunk, false);
+}
+
+static void applyTextAnchorToTextChunk(SVGTextChunk& chunk)
+{
+    if (chunk.anchor == TA_START)
         return;
 
     float shift = 0.0;
@@ -501,6 +546,52 @@ static void applyTextAnchorToTextChunk(SVGTextChunk& chunk)
     }
 }
 
+static void applyTextLengthCorrectionToTextChunk(SVGTextChunk& chunk)
+{
+    if (chunk.textLength <= FLT_EPSILON) // Not sure, why <= 0.0 doesn't work here (some fltpoint issue)
+        return;
+
+    float computedWidth = cummulatedWidthOfTextChunk(chunk);
+    float computedHeight = cummulatedHeightOfTextChunk(chunk);
+
+    if ((computedWidth <= 0.0 && !chunk.isVerticalText) ||
+        (computedHeight <= 0.0 && chunk.isVerticalText))
+        return;
+
+    float computedLength;
+
+    if (chunk.isVerticalText)
+        computedLength = computedHeight;
+    else
+        computedLength = computedWidth;
+
+    if (chunk.lengthAdjust == SVGTextContentElement::LENGTHADJUST_SPACINGANDGLYPHS) {
+        SVGChar& firstChar = *(chunk.start);
+        chunk.ctm.translate(firstChar.x, firstChar.y);
+
+        if (chunk.isVerticalText)
+            chunk.ctm.scale(1.0, chunk.textLength / computedLength);
+        else
+            chunk.ctm.scale(chunk.textLength / computedLength, 1.0);
+
+        chunk.ctm.translate(-firstChar.x, -firstChar.y);
+    } else {
+        float spacingToApply = (chunk.textLength - computedLength) / float(chunk.end - chunk.start);
+
+        // Apply correction to chunk 
+        Vector<SVGChar>::iterator chunkIt = chunk.start;
+        for (; chunkIt != chunk.end; ++chunkIt) {
+            SVGChar& curChar = *chunkIt;
+            curChar.drawnSeperated = true;
+
+            if (chunk.isVerticalText)
+                curChar.y += (chunkIt - chunk.start) * spacingToApply;
+            else
+                curChar.x += (chunkIt - chunk.start) * spacingToApply;
+        }
+    }
+}
+
 void SVGRootInlineBox::computePerCharacterLayoutInformation()
 {
     // Clean up any previous layout information
@@ -790,27 +881,14 @@ void SVGRootInlineBox::buildLayoutInformationForTextBox(SVGCharacterLayoutInfo&
             info.cury = info.yValueNext();
         }
 
-        // Calculate absolute x/y values, if needed
-        if (!info.inPathLayout())
-            svgChar.visible = true;
-        else {
-            float glyphAdvance = isVerticalText ? glyphHeight : glyphWidth;
-            float newOffset = FLT_MIN;
-
-            if (assignedX && !isVerticalText)
-                newOffset = info.curx;
-            else if (assignedY && isVerticalText)
-                newOffset = info.cury;
-
-            svgChar.visible = info.nextPathLayoutPointAndAngle(info.curx, info.cury, info.angle, glyphAdvance, newOffset);
-            svgChar.drawnSeperated = true;
-        }
+        float dx = 0.0;
+        float dy = 0.0;
 
         // Apply x-axis shift
         if (info.dxValueAvailable()) {
             svgChar.drawnSeperated = true;
 
-            float dx = info.dxValueNext();
+            dx = info.dxValueNext();
             info.dx += dx;
 
             if (!info.inPathLayout())
@@ -821,13 +899,31 @@ void SVGRootInlineBox::buildLayoutInformationForTextBox(SVGCharacterLayoutInfo&
         if (info.dyValueAvailable()) {
             svgChar.drawnSeperated = true;
 
-            float dy = info.dyValueNext();
+            dy = info.dyValueNext();
             info.dy += dy;
 
             if (!info.inPathLayout())
                 info.cury += dy;
         }
 
+        // Calculate absolute x/y values, if needed
+        if (!info.inPathLayout())
+            svgChar.visible = true;
+        else {
+            float glyphAdvance = isVerticalText ? glyphHeight : glyphWidth;
+            float extraAdvance = isVerticalText ? dy : dx;
+
+            float newOffset = FLT_MIN;
+
+            if (assignedX && !isVerticalText)
+                newOffset = info.curx;
+            else if (assignedY && isVerticalText)
+                newOffset = info.cury;
+
+            svgChar.visible = info.nextPathLayoutPointAndAngle(info.curx, info.cury, info.angle, glyphAdvance, extraAdvance, newOffset);
+            svgChar.drawnSeperated = true;
+        }
+
         // Apply rotation
         if (info.angleValueAvailable())
             info.angle = info.angleValueNext();
@@ -854,14 +950,17 @@ void SVGRootInlineBox::buildLayoutInformationForTextBox(SVGCharacterLayoutInfo&
             svgChar.pathXShift = 0.0;
             svgChar.pathYShift = 0.0;
         } else {
-            svgChar.pathXShift = info.dx + info.shiftx;
-            svgChar.pathYShift = info.dy + info.shifty;
+            svgChar.pathXShift = info.shiftx;
+            svgChar.pathYShift = info.shifty;
 
             // Translate to glyph midpoint
-            if (isVerticalText)
+            if (isVerticalText) {
                 svgChar.pathYShift -= glyphHeight / 2.0;
-            else
+                svgChar.pathXShift += info.dx;
+            } else {
+                svgChar.pathYShift += info.dy;
                 svgChar.pathXShift -= glyphWidth / 2.0;
+            }
         }
  
         // Correct character position for vertical text layout
@@ -920,6 +1019,12 @@ void SVGRootInlineBox::buildTextChunks(InlineFlowBox* start, SVGTextChunkLayoutI
             RenderText* text = textBox->textObject();
             ASSERT(text);
 
+            SVGElement* textElement = svg_dynamic_cast(text->element()->parent());
+            ASSERT(text->element());
+
+            SVGTextContentElement* textContent = static_cast<SVGTextContentElement*>(textElement);
+            ASSERT(textContent);
+            
             // Start new character range for the first chunk
             bool isFirstCharacter = m_svgTextChunks.isEmpty() && info.chunk.start == info.it && info.chunk.start == info.chunk.end;
             if (isFirstCharacter) {
@@ -949,6 +1054,8 @@ void SVGRootInlineBox::buildTextChunks(InlineFlowBox* start, SVGTextChunkLayoutI
                     info.chunk.isVerticalText = isVerticalWritingMode(text->style()->svgStyle());
                     info.chunk.isTextPath = info.handlingTextPath;
                     info.chunk.anchor = text->style()->svgStyle()->textAnchor();
+                    info.chunk.textLength = textContent->textLength().value();
+                    info.chunk.lengthAdjust = (ELengthAdjust) textContent->lengthAdjust();
 
 #if DEBUG_CHUNK_BUILDING > 1
                     fprintf(stderr, " | -> Assign chunk properties, isVerticalText=%i, anchor=%i\n", info.chunk.isVerticalText, info.chunk.anchor);
@@ -981,6 +1088,8 @@ void SVGRootInlineBox::buildTextChunks(InlineFlowBox* start, SVGTextChunkLayoutI
                         info.chunk.isVerticalText = isVerticalWritingMode(text->style()->svgStyle());
                         info.chunk.isTextPath = info.handlingTextPath;
                         info.chunk.anchor = text->style()->svgStyle()->textAnchor();
+                        info.chunk.textLength = textContent->textLength().value();
+                        info.chunk.lengthAdjust = (ELengthAdjust) textContent->lengthAdjust();
 
                         range.box = curr;
                         range.startOffset = i;
@@ -1076,8 +1185,33 @@ void SVGRootInlineBox::layoutTextChunks()
     Vector<SVGTextChunk>::iterator it = m_svgTextChunks.begin();
     Vector<SVGTextChunk>::iterator end = m_svgTextChunks.end();
 
-    for (; it != end; ++it)
-        applyTextAnchorToTextChunk(*it);
+    for (; it != end; ++it) {
+        SVGTextChunk& chunk = *it;
+
+#if DEBUG_CHUNK_BUILDING > 0
+        {
+            fprintf(stderr, "Handle TEXT CHUNK! anchor=%i, textLength=%f, lengthAdjust=%i, isVerticalText=%i, isTextPath=%i start=%p, end=%p -> dist: %i\n",
+                    (int) chunk.anchor, chunk.textLength, (int) chunk.lengthAdjust, (int) chunk.isVerticalText,
+                    (int) chunk.isTextPath, chunk.start, chunk.end, (unsigned int) (chunk.end - chunk.start));
+
+            Vector<SVGInlineBoxCharacterRange>::iterator boxIt = chunk.boxes.begin();
+            Vector<SVGInlineBoxCharacterRange>::iterator boxEnd = chunk.boxes.end();
+
+            unsigned int i = 0;
+            for (; boxIt != boxEnd; ++boxIt) {
+                SVGInlineBoxCharacterRange& range = *boxIt; i++;
+                fprintf(stderr, " -> RANGE %i STARTOFFSET: %i, ENDOFFSET: %i, BOX: %p\n", i, range.startOffset, range.endOffset, range.box);
+            }
+        }
+#endif
+
+        // text-path & text-anchor/textLength need special treatment.
+        if (chunk.isTextPath)
+            continue;
+
+        applyTextLengthCorrectionToTextChunk(chunk);
+        applyTextAnchorToTextChunk(chunk);
+    }
 }
 
 static inline void addPaintServerToTextDecorationInfo(ETextDecoration decoration, SVGTextDecorationInfo& info, RenderObject* object)
@@ -1184,13 +1318,13 @@ void SVGRootInlineBox::walkTextChunks(SVGTextChunkWalkerBase* walker, const SVGI
 
             // Process this chunk portion
             if (textBox)
-                (*walker)(rangeTextBox, range.startOffset, itCharBegin, itCharEnd);
+                (*walker)(rangeTextBox, range.startOffset, curChunk.ctm, itCharBegin, itCharEnd);
             else {
                 if (walker->setupFill(range.box))
-                    (*walker)(rangeTextBox, range.startOffset, itCharBegin, itCharEnd);
+                    (*walker)(rangeTextBox, range.startOffset, curChunk.ctm, itCharBegin, itCharEnd);
 
                 if (walker->setupStroke(range.box))
-                    (*walker)(rangeTextBox, range.startOffset, itCharBegin, itCharEnd);
+                    (*walker)(rangeTextBox, range.startOffset, curChunk.ctm, itCharBegin, itCharEnd);
             }
 
             chunkOffset += length;