WebCore:
authormjs@apple.com <mjs@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 26 Mar 2008 10:10:08 +0000 (10:10 +0000)
committermjs@apple.com <mjs@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 26 Mar 2008 10:10:08 +0000 (10:10 +0000)
2008-03-24  Maciej Stachowiak  <mjs@apple.com>

        Reviewed by Maciej.

        - fixed "SVGTextElement.getStartPositionOfChar does not correctly account for multichar glyphs"
        http://bugs.webkit.org/show_bug.cgi?id=18046

        * platform/graphics/Font.cpp:
        (WebCore::Font::floatWidth): Allow expressing a run that has extra "context" characters beyond the end,
        and reporting of how many characters were actually consumed, to support multichar glyphs in SVG fonts.
        * platform/graphics/Font.h:
        * rendering/SVGInlineTextBox.cpp:
        (WebCore::SVGInlineTextBox::calculateGlyphWidth): Pass along extra chars in argument and chars consumed out
        argument.
        (WebCore::SVGInlineTextBox::calculateGlyphHeight): Pass along extra chars in argument.
        (WebCore::SVGInlineTextBox::calculateGlyphBoundaries): Add boilerplate; may not handle multichar glyphs
        right but I don't know what effects this would have.
        * rendering/SVGInlineTextBox.h:
        * rendering/SVGRootInlineBox.cpp:
        (WebCore::cummulatedWidthOrHeightOfTextChunk): Add boilerplate; may not handle multichar glyphs right
        but again I am not sure what effect this would have.
        (WebCore::SVGRootInlineBox::buildLayoutInformationForTextBox): Account for multichar glyphs - let glyph
        selection consider extra chars, and account for the fact that a glyph may have consumed multiple chars.
        * rendering/SVGRootInlineBox.h:
        * svg/SVGFont.cpp:
        (WebCore::SVGTextRunWalker::walk): This is the place where glyph selection happens, so this is where
        we accout for multichar glyphs (both looking at extra chars past the end of the run, and reporting how
        many chars were consumed).
        (WebCore::floatWidthOfSubStringUsingSVGFont): Pass aforementioned info through the layers.
        (WebCore::Font::floatWidthUsingSVGFont): ditto
        (WebCore::Font::drawTextUsingSVGFont): ditto
        (WebCore::Font::selectionRectForTextUsingSVGFont): ditto
        * svg/SVGTextContentElement.cpp:
        (WebCore::cummulatedCharacterRangeLength): ditto
        (WebCore::SVGInlineTextBoxQueryWalker::chunkPortionCallback): ditto

LayoutTests:

2008-03-24  Maciej Stachowiak  <mjs@apple.com>

        Reviewed by Maciej.

        - test case and new results for "SVGTextElement.getStartPositionOfChar does not correctly account for multichar glyphs"
        http://bugs.webkit.org/show_bug.cgi?id=18046

        * svg/text/multichar-glyph.svg: Added. New test case for both rendering and getStartPositionOfChar
        access of multichar glyphs.
        * platform/mac/svg/text/multichar-glyph-expected.txt: Added.

        The following test results changed, all appear to be improvements.

        * platform/mac/svg/W3C-SVG-1.1/fonts-glyph-04-t-expected.txt:
        * platform/mac/svg/W3C-SVG-1.1/text-altglyph-01-b-expected.txt:
        * platform/mac/svg/W3C-SVG-1.1/text-text-06-t-expected.txt:
        * platform/mac/svg/text/text-altglyph-01-b-expected.txt:
        * platform/mac/svg/text/text-text-06-t-expected.txt:

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

17 files changed:
LayoutTests/ChangeLog
LayoutTests/platform/mac/svg/W3C-SVG-1.1/fonts-glyph-04-t-expected.txt
LayoutTests/platform/mac/svg/W3C-SVG-1.1/text-altglyph-01-b-expected.txt
LayoutTests/platform/mac/svg/W3C-SVG-1.1/text-text-06-t-expected.txt
LayoutTests/platform/mac/svg/text/multichar-glyph-expected.txt [new file with mode: 0644]
LayoutTests/platform/mac/svg/text/text-altglyph-01-b-expected.txt
LayoutTests/platform/mac/svg/text/text-text-06-t-expected.txt
LayoutTests/svg/text/multichar-glyph.svg [new file with mode: 0644]
WebCore/ChangeLog
WebCore/platform/graphics/Font.cpp
WebCore/platform/graphics/Font.h
WebCore/rendering/SVGInlineTextBox.cpp
WebCore/rendering/SVGInlineTextBox.h
WebCore/rendering/SVGRootInlineBox.cpp
WebCore/svg/SVGFont.cpp
WebCore/svg/SVGGlyphElement.h
WebCore/svg/SVGTextContentElement.cpp

index d8c754508f3d95e33637c94dfe086c2830482098..edcf84a050c9c503aaf77f32189593c2a7f27432 100644 (file)
@@ -1,3 +1,22 @@
+2008-03-24  Maciej Stachowiak  <mjs@apple.com>
+
+        Reviewed by Maciej.
+
+        - test case and new results for "SVGTextElement.getStartPositionOfChar does not correctly account for multichar glyphs"
+        http://bugs.webkit.org/show_bug.cgi?id=18046
+
+        * svg/text/multichar-glyph.svg: Added. New test case for both rendering and getStartPositionOfChar
+        access of multichar glyphs.
+        * platform/mac/svg/text/multichar-glyph-expected.txt: Added.
+
+        The following test results changed, all appear to be improvements.
+        
+        * platform/mac/svg/W3C-SVG-1.1/fonts-glyph-04-t-expected.txt:
+        * platform/mac/svg/W3C-SVG-1.1/text-altglyph-01-b-expected.txt:
+        * platform/mac/svg/W3C-SVG-1.1/text-text-06-t-expected.txt:
+        * platform/mac/svg/text/text-altglyph-01-b-expected.txt:
+        * platform/mac/svg/text/text-text-06-t-expected.txt:
+
 2008-03-25  Beth Dakin  <bdakin@apple.com>
 
         Reviewed by Oliver.
index df7d2c00e7bcec40b768f99fa45b08f6db8adcb9..6baaf4fc42688c6bc395733c45dcad8a55a5113c 100644 (file)
@@ -2,13 +2,13 @@ layer at (0,0) size 480x360
   RenderView at (0,0) size 480x360
 layer at (0,0) size 480x360
   RenderSVGRoot {svg} at (0.50,0.50) size 479x359
-    RenderSVGContainer {g} at (100,60) size 64x150
+    RenderSVGContainer {g} at (100,60) size 25x150
       RenderSVGHiddenContainer {defs} at (0,0) size 0x0
-      RenderSVGText {text} at (100,100) size 64x50 contains 1 chunk(s)
-        RenderSVGInlineText {#text} at (0,-40) size 64x50
+      RenderSVGText {text} at (100,100) size 25x50 contains 1 chunk(s)
+        RenderSVGInlineText {#text} at (0,-40) size 25x50
           chunk 1 text run 1 at (100.00,100.00) startOffset 0 endOffset 3 width 25.00: "ffl"
-      RenderSVGText {text} at (100,200) size 64x50 contains 1 chunk(s)
-        RenderSVGInlineText {#text} at (0,-40) size 64x50
+      RenderSVGText {text} at (100,200) size 25x50 contains 1 chunk(s)
+        RenderSVGInlineText {#text} at (0,-40) size 25x50
           chunk 1 text run 1 at (100.00,200.00) startOffset 0 endOffset 3 width 25.00: "ffl"
     RenderSVGText {text} at (10,340) size 284x46 contains 1 chunk(s)
       RenderSVGInlineText {#text} at (0,-36) size 284x46
index 8ea9f413224ea301fafc5f6c16a0860ea966bdf3..c9e034569ea3f6bc9686bcd23cc64a7e163104b4 100644 (file)
@@ -2,7 +2,7 @@ layer at (0,0) size 480x360
   RenderView at (0,0) size 480x360
 layer at (0,0) size 480x360
   RenderSVGRoot {svg} at (0.50,0.50) size 479x359
-    RenderSVGContainer {g} at (5,14) size 463.67x271.67
+    RenderSVGContainer {g} at (5,14) size 463x271.67
       RenderSVGText {text} at (5,50) size 403x44 contains 1 chunk(s)
         RenderSVGInlineText {#text} at (0,-36) size 403x44
           chunk 1 text run 1 at (5.00,50.00) startOffset 0 endOffset 26 width 403.00: "Test 'altGlyph' facilities"
@@ -10,7 +10,7 @@ layer at (0,0) size 480x360
         RenderSVGInlineText {#text} at (0,-27) size 463x33
           chunk 1 text run 1 at (5.00,90.00) startOffset 0 endOffset 32 width 463.00: "and many-to-many chars to glyphs"
       RenderSVGHiddenContainer {defs} at (0,0) size 0x0
-      RenderSVGContainer {g} at (49.33,137.33) size 419.33x148.33
+      RenderSVGContainer {g} at (49.33,137.33) size 389.33x148.33
         RenderSVGText {text} at (140,190) size 188x67 contains 1 chunk(s)
           RenderSVGTSpan {altGlyph} at (0,0) size 38x67
             RenderSVGInlineText {#text} at (0,-52) size 38x67
@@ -41,8 +41,8 @@ layer at (0,0) size 480x360
               chunk 1 text run 2 at (87.50,270.00) startOffset 0 endOffset 1 width 37.50: "A"
           RenderSVGInlineText {#text} at (75,-52) size 38x67
             chunk 1 text run 3 at (125.00,270.00) startOffset 0 endOffset 1 width 37.50: "D"
-        RenderSVGText {text} at (280,270) size 188x67 contains 1 chunk(s)
-          RenderSVGInlineText {#text} at (0,-52) size 188x67
+        RenderSVGText {text} at (280,270) size 158x67 contains 1 chunk(s)
+          RenderSVGInlineText {#text} at (0,-52) size 158x67
             chunk 1 text run 1 at (280.00,270.00) startOffset 0 endOffset 5 width 157.50: "SASSY"
     RenderSVGText {text} at (10,340) size 264x46 contains 1 chunk(s)
       RenderSVGInlineText {#text} at (0,-36) size 264x46
index 21130bbfd8e6528b178fe14b9b26f18f7c739aec..d10c71a59bfe354044cf737d642bd99f6d7ec157 100644 (file)
@@ -2,13 +2,13 @@ layer at (0,0) size 480x360
   RenderView at (0,0) size 480x360
 layer at (0,0) size 480x360
   RenderSVGRoot {svg} at (0.50,0.50) size 479x359
-    RenderSVGContainer {g} at (30,55) size 278x209
+    RenderSVGContainer {g} at (30,55) size 274x209
       RenderSVGHiddenContainer {defs} at (0,0) size 0x0
       RenderSVGHiddenContainer {defs} at (0,0) size 0x0
         RenderSVGContainer {g} at (-4,-15) size 8x19
           RenderPath {line} at (-0.50,-15) size 1x15 [stroke={[type=SOLID] [color=#FF0000]}] [fill={[type=SOLID] [color=#000000]}] [data="M0.00,0.00L0.00,-15.00"]
           RenderPath {rect} at (-4,-4) size 8x8 [fill={[type=SOLID] [color=#000000]}] [data="M-4.00,-4.00L4.00,-4.00L4.00,4.00L-4.00,4.00"]
-      RenderSVGContainer {g} at (30,55) size 278x209 [transform={m=((1.00,0.00)(0.00,1.00)) t=(20.00,30.00)}]
+      RenderSVGContainer {g} at (30,55) size 274x209 [transform={m=((1.00,0.00)(0.00,1.00)) t=(20.00,30.00)}]
         RenderSVGContainer {g} at (30,59) size 71x154 [transform={m=((1.00,0.00)(0.00,1.00)) t=(10.00,40.00)}]
           RenderSVGText {text} at (0,0) size 62x14 contains 1 chunk(s)
             RenderSVGInlineText {#text} at (0,-11) size 62x14
@@ -19,7 +19,7 @@ layer at (0,0) size 480x360
           RenderSVGText {text} at (0,140) size 71x14 contains 1 chunk(s)
             RenderSVGInlineText {#text} at (0,-11) size 71x14
               chunk 1 text run 1 at (0.00,140.00) startOffset 0 endOffset 15 width 71.00: "x/y positioning"
-        RenderSVGContainer {g} at (126,55) size 182x19 [transform={m=((1.00,0.00)(0.00,1.00)) t=(100.00,40.00)}]
+        RenderSVGContainer {g} at (126,55) size 178x19 [transform={m=((1.00,0.00)(0.00,1.00)) t=(100.00,40.00)}]
           RenderSVGContainer {use} at (126,55) size 8x19
             RenderSVGContainer {g} at (126,55) size 8x19 [transform={m=((1.00,0.00)(0.00,1.00)) t=(10.00,0.00)}]
               RenderSVGContainer {g} at (126,55) size 8x19
@@ -50,15 +50,14 @@ layer at (0,0) size 480x360
               RenderSVGContainer {g} at (246,55) size 8x19
                 RenderPath {line} at (249.50,55) size 1x15 [stroke={[type=SOLID] [color=#FF0000]}] [fill={[type=SOLID] [color=#8888FF]}] [data="M0.00,0.00L0.00,-15.00"]
                 RenderPath {rect} at (246,66) size 8x8 [fill={[type=SOLID] [color=#8888FF]}] [data="M-4.00,-4.00L4.00,-4.00L4.00,4.00L-4.00,4.00"]
-          RenderSVGText {text} at (10,0) size 178x10 contains 6 chunk(s)
-            RenderSVGInlineText {#text} at (0,-8) size 178x10
-              chunk 1 text run 1 at (10.00,0.00) startOffset 0 endOffset 1 width 8.00: "f"
-              chunk 2 text run 1 at (180.00,0.00) startOffset 1 endOffset 2 width 8.00: "i"
-              chunk 3 text run 1 at (40.00,0.00) startOffset 2 endOffset 3 width 15.00: "1"
-              chunk 4 text run 1 at (70.00,0.00) startOffset 3 endOffset 4 width 15.00: "2"
-              chunk 5 text run 1 at (100.00,0.00) startOffset 4 endOffset 5 width 15.00: "3"
-              chunk 6 text run 1 at (130.00,0.00) startOffset 5 endOffset 6 width 15.00: "4"
-        RenderSVGContainer {g} at (116,85) size 80x79 [transform={m=((1.00,0.00)(0.00,1.00)) t=(100.00,80.00)}]
+          RenderSVGText {text} at (10,0) size 135x10 contains 5 chunk(s)
+            RenderSVGInlineText {#text} at (0,-8) size 135x10
+              chunk 1 text run 1 at (10.00,0.00) startOffset 0 endOffset 2 width 15.00: "fi"
+              chunk 2 text run 1 at (40.00,0.00) startOffset 2 endOffset 3 width 15.00: "1"
+              chunk 3 text run 1 at (70.00,0.00) startOffset 3 endOffset 4 width 15.00: "2"
+              chunk 4 text run 1 at (100.00,0.00) startOffset 4 endOffset 5 width 15.00: "3"
+              chunk 5 text run 1 at (130.00,0.00) startOffset 5 endOffset 6 width 15.00: "4"
+        RenderSVGContainer {g} at (116,85) size 79x79 [transform={m=((1.00,0.00)(0.00,1.00)) t=(100.00,80.00)}]
           RenderSVGContainer {use} at (116,85) size 8x19
             RenderSVGContainer {g} at (116,85) size 8x19 [transform={m=((1.00,0.00)(0.00,1.00)) t=(0.00,-10.00)}]
               RenderSVGContainer {g} at (116,85) size 8x19
@@ -89,10 +88,10 @@ layer at (0,0) size 480x360
               RenderSVGContainer {g} at (176,125) size 8x19
                 RenderPath {line} at (179.50,125) size 1x15 [stroke={[type=SOLID] [color=#FF0000]}] [fill={[type=SOLID] [color=#8888FF]}] [data="M0.00,0.00L0.00,-15.00"]
                 RenderPath {rect} at (176,136) size 8x8 [fill={[type=SOLID] [color=#8888FF]}] [data="M-4.00,-4.00L4.00,-4.00L4.00,4.00L-4.00,4.00"]
-          RenderSVGText {text} at (0,-10) size 76x70 contains 1 chunk(s)
-            RenderSVGInlineText {#text} at (0,-8) size 76x70
+          RenderSVGText {text} at (0,-10) size 75x50 contains 1 chunk(s)
+            RenderSVGInlineText {#text} at (0,-8) size 75x50
               chunk 1 text run 1 at (0.00,-10.00) startOffset 0 endOffset 6 width 75.00: "fi1234"
-        RenderSVGContainer {g} at (126,185) size 182x79 [transform={m=((1.00,0.00)(0.00,1.00)) t=(100.00,180.00)}]
+        RenderSVGContainer {g} at (126,185) size 178x79 [transform={m=((1.00,0.00)(0.00,1.00)) t=(100.00,180.00)}]
           RenderSVGContainer {use} at (126,185) size 8x19
             RenderSVGContainer {g} at (126,185) size 8x19 [transform={m=((1.00,0.00)(0.00,1.00)) t=(10.00,-10.00)}]
               RenderSVGContainer {g} at (126,185) size 8x19
@@ -123,14 +122,13 @@ layer at (0,0) size 480x360
               RenderSVGContainer {g} at (246,225) size 8x19
                 RenderPath {line} at (249.50,225) size 1x15 [stroke={[type=SOLID] [color=#FF0000]}] [fill={[type=SOLID] [color=#8888FF]}] [data="M0.00,0.00L0.00,-15.00"]
                 RenderPath {rect} at (246,236) size 8x8 [fill={[type=SOLID] [color=#8888FF]}] [data="M-4.00,-4.00L4.00,-4.00L4.00,4.00L-4.00,4.00"]
-          RenderSVGText {text} at (10,-10) size 178x70 contains 6 chunk(s)
-            RenderSVGInlineText {#text} at (0,-8) size 178x70
-              chunk 1 text run 1 at (10.00,-10.00) startOffset 0 endOffset 1 width 8.00: "f"
-              chunk 2 text run 1 at (180.00,50.00) startOffset 1 endOffset 2 width 8.00: "i"
-              chunk 3 text run 1 at (40.00,0.00) startOffset 2 endOffset 3 width 15.00: "1"
-              chunk 4 text run 1 at (70.00,10.00) startOffset 3 endOffset 4 width 15.00: "2"
-              chunk 5 text run 1 at (100.00,20.00) startOffset 4 endOffset 5 width 15.00: "3"
-              chunk 6 text run 1 at (130.00,30.00) startOffset 5 endOffset 6 width 15.00: "4"
+          RenderSVGText {text} at (10,-10) size 135x50 contains 5 chunk(s)
+            RenderSVGInlineText {#text} at (0,-8) size 135x50
+              chunk 1 text run 1 at (10.00,-10.00) startOffset 0 endOffset 2 width 15.00: "fi"
+              chunk 2 text run 1 at (40.00,0.00) startOffset 2 endOffset 3 width 15.00: "1"
+              chunk 3 text run 1 at (70.00,10.00) startOffset 3 endOffset 4 width 15.00: "2"
+              chunk 4 text run 1 at (100.00,20.00) startOffset 4 endOffset 5 width 15.00: "3"
+              chunk 5 text run 1 at (130.00,30.00) startOffset 5 endOffset 6 width 15.00: "4"
     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.9 $"
diff --git a/LayoutTests/platform/mac/svg/text/multichar-glyph-expected.txt b/LayoutTests/platform/mac/svg/text/multichar-glyph-expected.txt
new file mode 100644 (file)
index 0000000..55f390f
--- /dev/null
@@ -0,0 +1,102 @@
+layer at (0,0) size 808x585
+  RenderView at (0,0) size 800x585
+layer at (0,0) size 808x585
+  RenderBlock {html} at (0,0) size 800x585
+    RenderBody {body} at (8,16) size 784x415
+      RenderBlock {p} at (0,0) size 784x36
+        RenderText {#text} at (0,0) size 783x36
+          text run at (0,0) width 783: "The left edges of the black boxes below should line up with the left edges of their containing red or green boxes. In addition,"
+          text run at (0,18) width 227: "all the assertions below should pass."
+      RenderBlock {div} at (0,52) size 800x200
+        RenderSVGRoot {svg} at (8,-2) size 450x240
+          RenderPath {rect} at (8,78) size 70x160 [fill={[type=SOLID] [color=#FF0000]}] [data="M0.00,10.00L70.00,10.00L70.00,170.00L0.00,170.00"]
+          RenderPath {rect} at (78,78) size 100x150 [fill={[type=SOLID] [color=#008000]}] [data="M70.00,10.00L170.00,10.00L170.00,160.00L70.00,160.00"]
+          RenderPath {rect} at (178,78) size 70x140 [fill={[type=SOLID] [color=#FF0000]}] [data="M170.00,10.00L240.00,10.00L240.00,150.00L170.00,150.00"]
+          RenderPath {rect} at (248,78) size 70x130 [fill={[type=SOLID] [color=#008000]}] [data="M240.00,10.00L310.00,10.00L310.00,140.00L240.00,140.00"]
+          RenderPath {rect} at (318,78) size 80x120 [fill={[type=SOLID] [color=#FF0000]}] [data="M310.00,10.00L390.00,10.00L390.00,130.00L310.00,130.00"]
+          RenderPath {rect} at (398,78) size 60x110 [fill={[type=SOLID] [color=#008000]}] [data="M390.00,10.00L450.00,10.00L450.00,120.00L390.00,120.00"]
+          RenderSVGText {text} at (0,10) size 450x100 contains 1 chunk(s)
+            RenderSVGInlineText {#text} at (0,-80) size 450x100
+              chunk 1 text run 1 at (0.00,10.00) startOffset 0 endOffset 10 width 450.00: "GGDGGBBBDB"
+        RenderText {#text} at (0,0) size 0x0
+      RenderBlock {pre} at (0,265) size 784x150
+        RenderInline {span} at (0,0) size 312x15
+          RenderInline {span} at (0,0) size 312x15
+            RenderInline {span} at (0,0) size 32x15
+              RenderText {#text} at (0,0) size 32x15
+                text run at (0,0) width 32: "PASS"
+            RenderText {#text} at (32,0) size 280x15
+              text run at (32,0) width 280: " t.getStartPositionOfChar(0).x is 0"
+          RenderBR {br} at (312,0) size 0x15
+        RenderInline {span} at (0,0) size 312x15
+          RenderInline {span} at (0,0) size 312x15
+            RenderInline {span} at (0,0) size 32x15
+              RenderText {#text} at (0,15) size 32x15
+                text run at (0,15) width 32: "PASS"
+            RenderText {#text} at (32,15) size 280x15
+              text run at (32,15) width 280: " t.getStartPositionOfChar(1).x is 0"
+          RenderBR {br} at (312,15) size 0x15
+        RenderInline {span} at (0,0) size 352x15
+          RenderInline {span} at (0,0) size 352x15
+            RenderInline {span} at (0,0) size 32x15
+              RenderText {#text} at (0,30) size 32x15
+                text run at (0,30) width 32: "PASS"
+            RenderText {#text} at (32,30) size 320x15
+              text run at (32,30) width 320: " t.getStartPositionOfChar(2).x is 0 + 70"
+          RenderBR {br} at (352,30) size 0x15
+        RenderInline {span} at (0,0) size 400x15
+          RenderInline {span} at (0,0) size 400x15
+            RenderInline {span} at (0,0) size 32x15
+              RenderText {#text} at (0,45) size 32x15
+                text run at (0,45) width 32: "PASS"
+            RenderText {#text} at (32,45) size 368x15
+              text run at (32,45) width 368: " t.getStartPositionOfChar(3).x is 0 + 70 + 100"
+          RenderBR {br} at (400,45) size 0x15
+        RenderInline {span} at (0,0) size 400x15
+          RenderInline {span} at (0,0) size 400x15
+            RenderInline {span} at (0,0) size 32x15
+              RenderText {#text} at (0,60) size 32x15
+                text run at (0,60) width 32: "PASS"
+            RenderText {#text} at (32,60) size 368x15
+              text run at (32,60) width 368: " t.getStartPositionOfChar(4).x is 0 + 70 + 100"
+          RenderBR {br} at (400,60) size 0x15
+        RenderInline {span} at (0,0) size 440x15
+          RenderInline {span} at (0,0) size 440x15
+            RenderInline {span} at (0,0) size 32x15
+              RenderText {#text} at (0,75) size 32x15
+                text run at (0,75) width 32: "PASS"
+            RenderText {#text} at (32,75) size 408x15
+              text run at (32,75) width 408: " t.getStartPositionOfChar(5).x is 0 + 70 + 100 + 70"
+          RenderBR {br} at (440,75) size 0x15
+        RenderInline {span} at (0,0) size 440x15
+          RenderInline {span} at (0,0) size 440x15
+            RenderInline {span} at (0,0) size 32x15
+              RenderText {#text} at (0,90) size 32x15
+                text run at (0,90) width 32: "PASS"
+            RenderText {#text} at (32,90) size 408x15
+              text run at (32,90) width 408: " t.getStartPositionOfChar(6).x is 0 + 70 + 100 + 70"
+          RenderBR {br} at (440,90) size 0x15
+        RenderInline {span} at (0,0) size 480x15
+          RenderInline {span} at (0,0) size 480x15
+            RenderInline {span} at (0,0) size 32x15
+              RenderText {#text} at (0,105) size 32x15
+                text run at (0,105) width 32: "PASS"
+            RenderText {#text} at (32,105) size 448x15
+              text run at (32,105) width 448: " t.getStartPositionOfChar(7).x is 0 + 70 + 100 + 70 + 70"
+          RenderBR {br} at (480,105) size 0x15
+        RenderInline {span} at (0,0) size 480x15
+          RenderInline {span} at (0,0) size 480x15
+            RenderInline {span} at (0,0) size 32x15
+              RenderText {#text} at (0,120) size 32x15
+                text run at (0,120) width 32: "PASS"
+            RenderText {#text} at (32,120) size 448x15
+              text run at (32,120) width 448: " t.getStartPositionOfChar(8).x is 0 + 70 + 100 + 70 + 70"
+          RenderBR {br} at (480,120) size 0x15
+        RenderInline {span} at (0,0) size 520x15
+          RenderInline {span} at (0,0) size 520x15
+            RenderInline {span} at (0,0) size 32x15
+              RenderText {#text} at (0,135) size 32x15
+                text run at (0,135) width 32: "PASS"
+            RenderText {#text} at (32,135) size 488x15
+              text run at (32,135) width 488: " t.getStartPositionOfChar(9).x is 0 + 70 + 100 + 70 + 70 + 80"
+          RenderBR {br} at (520,135) size 0x15
index 15df5f3355bf924fb7eef28bda9c88c52ba5a870..549398a6c8937f07d5d9d9fc567fb49224ee5b0c 100644 (file)
@@ -2,7 +2,7 @@ layer at (0,0) size 800x600
   RenderView at (0,0) size 800x600
 layer at (0,0) size 800x600
   RenderSVGRoot {svg} at (0.83,0.83) size 798.33x598.33
-    RenderSVGContainer {g} at (8.33,23.33) size 772.78x452.78
+    RenderSVGContainer {g} at (8.33,23.33) size 771.67x452.78
       RenderSVGText {text} at (5,50) size 403x44 contains 1 chunk(s)
         RenderSVGInlineText {#text} at (0,-36) size 403x44
           chunk 1 text run 1 at (5.00,50.00) startOffset 0 endOffset 26 width 403.00: "Test 'altGlyph' facilities"
@@ -10,7 +10,7 @@ layer at (0,0) size 800x600
         RenderSVGInlineText {#text} at (0,-27) size 463x33
           chunk 1 text run 1 at (5.00,90.00) startOffset 0 endOffset 32 width 463.00: "and many-to-many chars to glyphs"
       RenderSVGHiddenContainer {defs} at (0,0) size 0x0
-      RenderSVGContainer {g} at (82.22,228.89) size 698.89x247.22
+      RenderSVGContainer {g} at (82.22,228.89) size 648.89x247.22
         RenderSVGText {text} at (140,190) size 188x67 contains 1 chunk(s)
           RenderSVGTSpan {altGlyph} at (0,0) size 38x67
             RenderSVGInlineText {#text} at (0,-52) size 38x67
@@ -41,8 +41,8 @@ layer at (0,0) size 800x600
               chunk 1 text run 2 at (87.50,270.00) startOffset 0 endOffset 1 width 37.50: "A"
           RenderSVGInlineText {#text} at (75,-52) size 38x67
             chunk 1 text run 3 at (125.00,270.00) startOffset 0 endOffset 1 width 37.50: "D"
-        RenderSVGText {text} at (280,270) size 188x67 contains 1 chunk(s)
-          RenderSVGInlineText {#text} at (0,-52) size 188x67
+        RenderSVGText {text} at (280,270) size 158x67 contains 1 chunk(s)
+          RenderSVGInlineText {#text} at (0,-52) size 158x67
             chunk 1 text run 1 at (280.00,270.00) startOffset 0 endOffset 5 width 157.50: "SASSY"
     RenderSVGText {text} at (10,340) size 264x46 contains 1 chunk(s)
       RenderSVGInlineText {#text} at (0,-36) size 264x46
index 161b1394e265689dce245727b86f63494310e25f..fc9d72349422200e1bdb4f16e3ac9edc75647961 100644 (file)
@@ -2,13 +2,13 @@ layer at (0,0) size 800x600
   RenderView at (0,0) size 800x600
 layer at (0,0) size 800x600
   RenderSVGRoot {svg} at (0.83,0.83) size 798.33x598.33
-    RenderSVGContainer {g} at (50,91.67) size 463.33x348.33
+    RenderSVGContainer {g} at (50,91.67) size 456.67x348.33
       RenderSVGHiddenContainer {defs} at (0,0) size 0x0
       RenderSVGHiddenContainer {defs} at (0,0) size 0x0
         RenderSVGContainer {g} at (-4,-15) size 8x19
           RenderPath {line} at (-0.50,-15) size 1x15 [stroke={[type=SOLID] [color=#FF0000]}] [fill={[type=SOLID] [color=#000000]}] [data="M0.00,0.00L0.00,-15.00"]
           RenderPath {rect} at (-4,-4) size 8x8 [fill={[type=SOLID] [color=#000000]}] [data="M-4.00,-4.00L4.00,-4.00L4.00,4.00L-4.00,4.00"]
-      RenderSVGContainer {g} at (50,91.67) size 463.33x348.33 [transform={m=((1.00,0.00)(0.00,1.00)) t=(20.00,30.00)}]
+      RenderSVGContainer {g} at (50,91.67) size 456.67x348.33 [transform={m=((1.00,0.00)(0.00,1.00)) t=(20.00,30.00)}]
         RenderSVGContainer {g} at (50,98.33) size 118.33x256.67 [transform={m=((1.00,0.00)(0.00,1.00)) t=(10.00,40.00)}]
           RenderSVGText {text} at (0,0) size 62x14 contains 1 chunk(s)
             RenderSVGInlineText {#text} at (0,-11) size 62x14
@@ -19,7 +19,7 @@ layer at (0,0) size 800x600
           RenderSVGText {text} at (0,140) size 71x14 contains 1 chunk(s)
             RenderSVGInlineText {#text} at (0,-11) size 71x14
               chunk 1 text run 1 at (0.00,140.00) startOffset 0 endOffset 15 width 71.00: "x/y positioning"
-        RenderSVGContainer {g} at (210,91.67) size 303.33x31.67 [transform={m=((1.00,0.00)(0.00,1.00)) t=(100.00,40.00)}]
+        RenderSVGContainer {g} at (210,91.67) size 296.67x31.67 [transform={m=((1.00,0.00)(0.00,1.00)) t=(100.00,40.00)}]
           RenderSVGContainer {use} at (210,91.67) size 13.33x31.67
             RenderSVGContainer {g} at (210,91.67) size 13.33x31.67 [transform={m=((1.00,0.00)(0.00,1.00)) t=(10.00,0.00)}]
               RenderSVGContainer {g} at (210,91.67) size 13.33x31.67
@@ -50,15 +50,14 @@ layer at (0,0) size 800x600
               RenderSVGContainer {g} at (410,91.67) size 13.33x31.67
                 RenderPath {line} at (415.83,91.67) size 1.67x25 [stroke={[type=SOLID] [color=#FF0000]}] [fill={[type=SOLID] [color=#8888FF]}] [data="M0.00,0.00L0.00,-15.00"]
                 RenderPath {rect} at (410,110) size 13.33x13.33 [fill={[type=SOLID] [color=#8888FF]}] [data="M-4.00,-4.00L4.00,-4.00L4.00,4.00L-4.00,4.00"]
-          RenderSVGText {text} at (10,0) size 178x10 contains 6 chunk(s)
-            RenderSVGInlineText {#text} at (0,-8) size 178x10
-              chunk 1 text run 1 at (10.00,0.00) startOffset 0 endOffset 1 width 8.00: "f"
-              chunk 2 text run 1 at (180.00,0.00) startOffset 1 endOffset 2 width 8.00: "i"
-              chunk 3 text run 1 at (40.00,0.00) startOffset 2 endOffset 3 width 15.00: "1"
-              chunk 4 text run 1 at (70.00,0.00) startOffset 3 endOffset 4 width 15.00: "2"
-              chunk 5 text run 1 at (100.00,0.00) startOffset 4 endOffset 5 width 15.00: "3"
-              chunk 6 text run 1 at (130.00,0.00) startOffset 5 endOffset 6 width 15.00: "4"
-        RenderSVGContainer {g} at (193.33,141.67) size 133.33x131.67 [transform={m=((1.00,0.00)(0.00,1.00)) t=(100.00,80.00)}]
+          RenderSVGText {text} at (10,0) size 135x10 contains 5 chunk(s)
+            RenderSVGInlineText {#text} at (0,-8) size 135x10
+              chunk 1 text run 1 at (10.00,0.00) startOffset 0 endOffset 2 width 15.00: "fi"
+              chunk 2 text run 1 at (40.00,0.00) startOffset 2 endOffset 3 width 15.00: "1"
+              chunk 3 text run 1 at (70.00,0.00) startOffset 3 endOffset 4 width 15.00: "2"
+              chunk 4 text run 1 at (100.00,0.00) startOffset 4 endOffset 5 width 15.00: "3"
+              chunk 5 text run 1 at (130.00,0.00) startOffset 5 endOffset 6 width 15.00: "4"
+        RenderSVGContainer {g} at (193.33,141.67) size 131.67x131.67 [transform={m=((1.00,0.00)(0.00,1.00)) t=(100.00,80.00)}]
           RenderSVGContainer {use} at (193.33,141.67) size 13.33x31.67
             RenderSVGContainer {g} at (193.33,141.67) size 13.33x31.67 [transform={m=((1.00,0.00)(0.00,1.00)) t=(0.00,-10.00)}]
               RenderSVGContainer {g} at (193.33,141.67) size 13.33x31.67
@@ -89,10 +88,10 @@ layer at (0,0) size 800x600
               RenderSVGContainer {g} at (293.33,208.33) size 13.33x31.67
                 RenderPath {line} at (299.17,208.33) size 1.67x25 [stroke={[type=SOLID] [color=#FF0000]}] [fill={[type=SOLID] [color=#8888FF]}] [data="M0.00,0.00L0.00,-15.00"]
                 RenderPath {rect} at (293.33,226.67) size 13.33x13.33 [fill={[type=SOLID] [color=#8888FF]}] [data="M-4.00,-4.00L4.00,-4.00L4.00,4.00L-4.00,4.00"]
-          RenderSVGText {text} at (0,-10) size 76x70 contains 1 chunk(s)
-            RenderSVGInlineText {#text} at (0,-8) size 76x70
+          RenderSVGText {text} at (0,-10) size 75x50 contains 1 chunk(s)
+            RenderSVGInlineText {#text} at (0,-8) size 75x50
               chunk 1 text run 1 at (0.00,-10.00) startOffset 0 endOffset 6 width 75.00: "fi1234"
-        RenderSVGContainer {g} at (210,308.33) size 303.33x131.67 [transform={m=((1.00,0.00)(0.00,1.00)) t=(100.00,180.00)}]
+        RenderSVGContainer {g} at (210,308.33) size 296.67x131.67 [transform={m=((1.00,0.00)(0.00,1.00)) t=(100.00,180.00)}]
           RenderSVGContainer {use} at (210,308.33) size 13.33x31.67
             RenderSVGContainer {g} at (210,308.33) size 13.33x31.67 [transform={m=((1.00,0.00)(0.00,1.00)) t=(10.00,-10.00)}]
               RenderSVGContainer {g} at (210,308.33) size 13.33x31.67
@@ -123,14 +122,13 @@ layer at (0,0) size 800x600
               RenderSVGContainer {g} at (410,375) size 13.33x31.67
                 RenderPath {line} at (415.83,375) size 1.67x25 [stroke={[type=SOLID] [color=#FF0000]}] [fill={[type=SOLID] [color=#8888FF]}] [data="M0.00,0.00L0.00,-15.00"]
                 RenderPath {rect} at (410,393.33) size 13.33x13.33 [fill={[type=SOLID] [color=#8888FF]}] [data="M-4.00,-4.00L4.00,-4.00L4.00,4.00L-4.00,4.00"]
-          RenderSVGText {text} at (10,-10) size 178x70 contains 6 chunk(s)
-            RenderSVGInlineText {#text} at (0,-8) size 178x70
-              chunk 1 text run 1 at (10.00,-10.00) startOffset 0 endOffset 1 width 8.00: "f"
-              chunk 2 text run 1 at (180.00,50.00) startOffset 1 endOffset 2 width 8.00: "i"
-              chunk 3 text run 1 at (40.00,0.00) startOffset 2 endOffset 3 width 15.00: "1"
-              chunk 4 text run 1 at (70.00,10.00) startOffset 3 endOffset 4 width 15.00: "2"
-              chunk 5 text run 1 at (100.00,20.00) startOffset 4 endOffset 5 width 15.00: "3"
-              chunk 6 text run 1 at (130.00,30.00) startOffset 5 endOffset 6 width 15.00: "4"
+          RenderSVGText {text} at (10,-10) size 135x50 contains 5 chunk(s)
+            RenderSVGInlineText {#text} at (0,-8) size 135x50
+              chunk 1 text run 1 at (10.00,-10.00) startOffset 0 endOffset 2 width 15.00: "fi"
+              chunk 2 text run 1 at (40.00,0.00) startOffset 2 endOffset 3 width 15.00: "1"
+              chunk 3 text run 1 at (70.00,10.00) startOffset 3 endOffset 4 width 15.00: "2"
+              chunk 4 text run 1 at (100.00,20.00) startOffset 4 endOffset 5 width 15.00: "3"
+              chunk 5 text run 1 at (130.00,30.00) startOffset 5 endOffset 6 width 15.00: "4"
     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.9 $"
diff --git a/LayoutTests/svg/text/multichar-glyph.svg b/LayoutTests/svg/text/multichar-glyph.svg
new file mode 100644 (file)
index 0000000..13b14ba
--- /dev/null
@@ -0,0 +1,119 @@
+<html xmlns="http://www.w3.org/1999/xhtml" style="width: 100%; height: 100%;">
+<body>
+<p>The left edges of the black boxes below should line up with the
+left edges of their containing red or green boxes. In addition, all
+the assertions below should pass.</p>
+
+<div style="width: 800px; height: 200px;">
+<svg xmlns="http://www.w3.org/2000/svg">
+<font>
+<font-face font-family="xyzzy" units-per-em="100" ascent="100" descent="500">
+</font-face>
+<glyph unicode="BD" d="M0,0 h40 v-80 h-40 z" horiz-adv-x="80">
+</glyph>
+<glyph unicode="GG" d="M0,0 h20 v-60 h-20 z" horiz-adv-x="70">
+</glyph>
+<glyph unicode="BB" d="M0,0 h20 v-70 h-20 z" horiz-adv-x="70">
+</glyph>
+<glyph unicode="B" d="M0,0 h30 v-40 h-30 z" horiz-adv-x="60">
+</glyph>
+<glyph unicode="D" d="M0,0 h30 v-40 h-30 z" horiz-adv-x="100">
+</glyph>
+<glyph unicode="G" d="M0,0 h30 v-40 h-30 z" horiz-adv-x="60">
+</glyph>
+</font>
+<rect x="0" y="10" width="70" height="160" fill="red"/>
+<rect x="70" y="10" width="100" height="150" fill="green"/>
+<rect x="170" y="10" width="70" height="140" fill="red"/>
+<rect x="240" y="10" width="70" height="130" fill="green"/>
+<rect x="310" y="10" width="80" height="120" fill="red"/>
+<rect x="390" y="10" width="60" height="110" fill="green"/>
+<text id="foo" y="10" font-family="xyzzy" font-size="100px" letter-spacing="0px" word-spacing="0px">GGDGGBBBDB</text>
+</svg>
+</div>
+<pre id="console" />
+<script>
+<![CDATA[
+
+function debug(msg)
+{
+    var span = document.createElementNS("http://www.w3.org/1999/xhtml", "span");
+    document.getElementById("console").appendChild(span); // insert it first so XHTML knows the namespace
+    span.innerHTML = msg + '<br />';
+}
+
+function escapeHTML(text)
+{
+    return text.replace(/&/g, "&amp;").replace(/</g, "&lt;");
+}
+
+function testPassed(msg)
+{
+    debug('<span><span class="pass">PASS</span> ' + escapeHTML(msg) + '</span>');
+}
+
+function testFailed(msg)
+{
+    debug('<span><span class="fail">FAIL</span> ' + escapeHTML(msg) + '</span>');
+}
+
+function areArraysEqual(_a, _b)
+{
+    if (_a.length !== _b.length)
+        return false;
+    for (var i = 0; i < _a.length; i++)
+        if (_a[i] !== _b[i])
+            return false;
+    return true;
+}
+
+function isResultCorrect(_actual, _expected)
+{
+    if (_actual === _expected)
+        return true;
+    if (typeof(_expected) == "number" && isNaN(_expected))
+        return typeof(_actual) == "number" && isNaN(_actual);
+    if (Object.prototype.toString.call(_expected) == Object.prototype.toString.call([]))
+        return areArraysEqual(_actual, _expected);
+    return false;
+}
+
+function shouldBe(_a, _b)
+{
+  if (typeof _a != "string" || typeof _b != "string")
+    debug("WARN: shouldBe() expects string arguments");
+  var exception;
+  var _av;
+  try {
+     _av = eval(_a);
+  } catch (e) {
+     exception = e;
+  }
+  var _bv = eval(_b);
+
+  if (exception)
+    testFailed(_a + " should be " + _bv + ". Threw exception " + exception);
+  else if (isResultCorrect(_av, _bv))
+    testPassed(_a + " is " + _b);
+  else if (typeof(_av) == typeof(_bv))
+    testFailed(_a + " should be " + _bv + ". Was " + _av + ".");
+  else
+    testFailed(_a + " should be " + _bv + " (of type " + typeof _bv + "). Was " + _av + " (of type " + typeof _av + ").");
+}
+
+var t = document.getElementById("foo");
+shouldBe("t.getStartPositionOfChar(0).x", '0');
+shouldBe("t.getStartPositionOfChar(1).x", '0');
+shouldBe("t.getStartPositionOfChar(2).x", '0 + 70');
+shouldBe("t.getStartPositionOfChar(3).x", '0 + 70 + 100');
+shouldBe("t.getStartPositionOfChar(4).x", '0 + 70 + 100');
+shouldBe("t.getStartPositionOfChar(5).x", '0 + 70 + 100 + 70');
+shouldBe("t.getStartPositionOfChar(6).x", '0 + 70 + 100 + 70');
+shouldBe("t.getStartPositionOfChar(7).x", '0 + 70 + 100 + 70 + 70');
+shouldBe("t.getStartPositionOfChar(8).x", '0 + 70 + 100 + 70 + 70');
+shouldBe("t.getStartPositionOfChar(9).x", '0 + 70 + 100 + 70 + 70 + 80');
+]]>
+</script>
+</body>
+</html>
+
index e3ce65587f9ba149dc7d71fb943e25f76d8e01b5..b7e037ea1902a45f843152972df7bb3e2f4fd27e 100644 (file)
@@ -1,3 +1,39 @@
+2008-03-24  Maciej Stachowiak  <mjs@apple.com>
+
+        Reviewed by Maciej.
+
+        - fixed "SVGTextElement.getStartPositionOfChar does not correctly account for multichar glyphs"
+        http://bugs.webkit.org/show_bug.cgi?id=18046
+
+        * platform/graphics/Font.cpp:
+        (WebCore::Font::floatWidth): Allow expressing a run that has extra "context" characters beyond the end,
+        and reporting of how many characters were actually consumed, to support multichar glyphs in SVG fonts.
+        * platform/graphics/Font.h:
+        * rendering/SVGInlineTextBox.cpp:
+        (WebCore::SVGInlineTextBox::calculateGlyphWidth): Pass along extra chars in argument and chars consumed out
+        argument.
+        (WebCore::SVGInlineTextBox::calculateGlyphHeight): Pass along extra chars in argument.
+        (WebCore::SVGInlineTextBox::calculateGlyphBoundaries): Add boilerplate; may not handle multichar glyphs
+        right but I don't know what effects this would have.
+        * rendering/SVGInlineTextBox.h:
+        * rendering/SVGRootInlineBox.cpp:
+        (WebCore::cummulatedWidthOrHeightOfTextChunk): Add boilerplate; may not handle multichar glyphs right
+        but again I am not sure what effect this would have.
+        (WebCore::SVGRootInlineBox::buildLayoutInformationForTextBox): Account for multichar glyphs - let glyph
+        selection consider extra chars, and account for the fact that a glyph may have consumed multiple chars.
+        * rendering/SVGRootInlineBox.h:
+        * svg/SVGFont.cpp:
+        (WebCore::SVGTextRunWalker::walk): This is the place where glyph selection happens, so this is where
+        we accout for multichar glyphs (both looking at extra chars past the end of the run, and reporting how
+        many chars were consumed).
+        (WebCore::floatWidthOfSubStringUsingSVGFont): Pass aforementioned info through the layers.
+        (WebCore::Font::floatWidthUsingSVGFont): ditto
+        (WebCore::Font::drawTextUsingSVGFont): ditto
+        (WebCore::Font::selectionRectForTextUsingSVGFont): ditto
+        * svg/SVGTextContentElement.cpp:
+        (WebCore::cummulatedCharacterRangeLength): ditto
+        (WebCore::SVGInlineTextBoxQueryWalker::chunkPortionCallback): ditto
+
 2008-03-25  Beth Dakin  <bdakin@apple.com>
 
         Reviewed by Oliver.
index 05704d3083ee485bb3dc36fdc10b523d0fcf811e..3dc7e370f39275472b3bea398d258651039b11a8 100644 (file)
@@ -708,6 +708,19 @@ float Font::floatWidth(const TextRun& run) const
     return floatWidthForComplexText(run);
 }
 
+float Font::floatWidth(const TextRun& run, int extraCharsAvailable, int& charsConsumed) const
+{
+#if ENABLE(SVG_FONTS)
+    if (primaryFont()->isSVGFont())
+        return floatWidthUsingSVGFont(run, extraCharsAvailable, charsConsumed);
+#endif
+
+    charsConsumed = run.length();
+    if (canUseGlyphCache(run))
+        return floatWidthForSimpleText(run, 0);
+    return floatWidthForComplexText(run);
+}
+
 float Font::floatWidthForSimpleText(const TextRun& run, GlyphBuffer* glyphBuffer) const
 {
     WidthIterator it(this, run);
index 0ea04eb4ff171b806d745699611fa3aa12a7e167..35a9674028315a24ac367e6b4581d9251c94be42 100644 (file)
@@ -170,6 +170,7 @@ public:
 
     int width(const TextRun&) const;
     float floatWidth(const TextRun&) const;
+    float floatWidth(const TextRun& run, int extraCharsAvailable, int& charsConsumed) const;
 
     int offsetForPosition(const TextRun&, int position, bool includePartialGlyphs) const;
     FloatRect selectionRectForText(const TextRun&, const IntPoint&, int h, int from = 0, int to = -1) const;
@@ -234,6 +235,7 @@ private:
 #if ENABLE(SVG_FONTS)
     void drawTextUsingSVGFont(GraphicsContext*, const TextRun&, const FloatPoint&, int from, int to) const;
     float floatWidthUsingSVGFont(const TextRun&) const;
+    float floatWidthUsingSVGFont(const TextRun&, int extraCharsAvailable, int& charsConsumed) const;
     FloatRect selectionRectForTextUsingSVGFont(const TextRun&, const IntPoint&, int h, int from, int to) const;
     int offsetForPositionForTextUsingSVGFont(const TextRun&, int position, bool includePartialGlyphs) const;
 #endif
index eb1baeca430e4a92cc3cc4a646ba139625740aba..94c57be5e671b1faa0b7f299c6cb7751d298cea8 100644 (file)
@@ -74,13 +74,13 @@ SVGRootInlineBox* SVGInlineTextBox::svgRootInlineBox() const
     return static_cast<SVGRootInlineBox*>(parentBox);
 }
 
-float SVGInlineTextBox::calculateGlyphWidth(RenderStyle* style, int offset) const
+float SVGInlineTextBox::calculateGlyphWidth(RenderStyle* style, int offset, int extraCharsAvailable, int& charsConsumed) const
 {
     ASSERT(style);
-    return style->font().floatWidth(svgTextRunForInlineTextBox(textObject()->text()->characters() + offset, 1, style, this, 0));
+    return style->font().floatWidth(svgTextRunForInlineTextBox(textObject()->text()->characters() + offset, 1, style, this, 0), extraCharsAvailable, charsConsumed);
 }
 
-float SVGInlineTextBox::calculateGlyphHeight(RenderStyle* style, int offset) const
+float SVGInlineTextBox::calculateGlyphHeight(RenderStyle* style, int offset, int extraCharsAvailable) const
 {
     ASSERT(style);
 
@@ -96,10 +96,12 @@ FloatRect SVGInlineTextBox::calculateGlyphBoundaries(RenderStyle* style, int off
     // Take RTL text into account and pick right glyph width/height.
     float glyphWidth = 0.0f;
 
+    // FIXME: account for multi-character glyphs
+    int charsConsumed;
     if (!m_reversed)
-        glyphWidth = calculateGlyphWidth(style, offset);
+        glyphWidth = calculateGlyphWidth(style, offset, 0, charsConsumed);
     else
-        glyphWidth = calculateGlyphWidth(style, start() + end() - offset);
+        glyphWidth = calculateGlyphWidth(style, start() + end() - offset, 0, charsConsumed);
 
     float x1 = svgChar.x;
     float x2 = svgChar.x + glyphWidth;
index 099cfee9167ca0ddbed14aebbee9c473c5173088..6aaacabe8bc3d08af49ef2e45a1b216b269ff1b3 100644 (file)
@@ -58,8 +58,8 @@ namespace WebCore {
         SVGRootInlineBox* svgRootInlineBox() const;
 
         // Helper functions shared with SVGRootInlineBox     
-        float calculateGlyphWidth(RenderStyle*, int offset) const;
-        float calculateGlyphHeight(RenderStyle*, int offset) const;
+        float calculateGlyphWidth(RenderStyle* style, int offset, int extraCharsAvailable, int& charsConsumed) const;
+        float calculateGlyphHeight(RenderStyle*, int offset, int extraCharsAvailable) const;
 
         FloatRect calculateGlyphBoundaries(RenderStyle*, int offset, const SVGChar&) const;
         SVGChar* closestCharacterToPosition(int x, int y, int& offset) const;
index d609687e5db4f5660b36abf656b4ee03a89c5291..e706ab26957f37a9c78467fbf3aedfa8556c9e84 100644 (file)
@@ -710,11 +710,13 @@ static float cummulatedWidthOrHeightOfTextChunk(SVGTextChunk& chunk, bool calcWi
 
                 int offset = box->m_reversed ? box->end() - i - positionOffset + 1 : box->start() + i + positionOffset - 1;
 
+                // FIXME: does this need to change to handle multichar glyphs?
+                int charsConsumed = 1;
                 if (calcWidthOnly) {
-                    float lastGlyphWidth = box->calculateGlyphWidth(style, offset);
+                    float lastGlyphWidth = box->calculateGlyphWidth(style, offset, 0, charsConsumed);
                     length += currentCharacter.x - lastCharacter.x - lastGlyphWidth;
                 } else {
-                    float lastGlyphHeight = box->calculateGlyphHeight(style, offset);
+                    float lastGlyphHeight = box->calculateGlyphHeight(style, offset, 0);
                     length += currentCharacter.y - lastCharacter.y - lastGlyphHeight;
                 }
             }
@@ -1110,7 +1112,8 @@ void SVGRootInlineBox::buildLayoutInformationForTextBox(SVGCharacterLayoutInfo&
     const SVGRenderStyle* svgStyle = style->svgStyle();
     bool isVerticalText = isVerticalWritingMode(svgStyle);
 
-    for (unsigned i = 0; i < length; ++i) {
+    int charsConsumed = 0;
+    for (unsigned i = 0; i < length; i += charsConsumed) {
         SVGChar svgChar;
 
         if (info.inPathLayout())
@@ -1119,12 +1122,14 @@ void SVGRootInlineBox::buildLayoutInformationForTextBox(SVGCharacterLayoutInfo&
         float glyphWidth = 0.0f;
         float glyphHeight = 0.0f;
 
+        int extraCharsAvailable = length - i - 1;
+
         if (textBox->m_reversed) {
-            glyphWidth = svgTextBox->calculateGlyphWidth(style, textBox->end() - i);
-            glyphHeight = svgTextBox->calculateGlyphHeight(style, textBox->end() - i);
+            glyphWidth = svgTextBox->calculateGlyphWidth(style, textBox->end() - i, extraCharsAvailable, charsConsumed);
+            glyphHeight = svgTextBox->calculateGlyphHeight(style, textBox->end() - i, extraCharsAvailable);
         } else {
-            glyphWidth = svgTextBox->calculateGlyphWidth(style, textBox->start() + i);
-            glyphHeight = svgTextBox->calculateGlyphHeight(style, textBox->start() + i);
+            glyphWidth = svgTextBox->calculateGlyphWidth(style, textBox->start() + i, extraCharsAvailable, charsConsumed);
+            glyphHeight = svgTextBox->calculateGlyphHeight(style, textBox->start() + i, extraCharsAvailable);
         }
 
         bool assignedX = false;
@@ -1299,9 +1304,13 @@ void SVGRootInlineBox::buildLayoutInformationForTextBox(SVGCharacterLayoutInfo&
         } else
             info.curx += glyphAdvance + spacing;
 
-        // Advance to next character
-        info.svgChars.append(svgChar);
-        info.processedSingleCharacter();
+        // Advance to next character group
+        for (int k = 0; k < charsConsumed; ++k) {
+            info.svgChars.append(svgChar);
+            info.processedSingleCharacter();
+            svgChar.drawnSeperated = false;
+            svgChar.newTextChunk = false;
+        }
     }
 }
 
index 0511acbc263f3b3920c55d8e11989f1039d58b2b..e1974b09f35f3fc9a978c3f3f4e2360432b90dd4 100644 (file)
@@ -249,13 +249,16 @@ struct SVGTextRunWalker {
         SVGGlyphIdentifier identifier;
         bool foundGlyph = false;
         int characterLookupRange;
+        int endOfScanRange = to + m_walkerData.extraCharsAvailable;
 
         for (int i = from; i < to; ++i) {
             // If characterLookupRange is > 0, then the font defined ligatures (length of unicode property value > 1).
             // We have to check wheter the current character & the next character define a ligature. This needs to be
             // extended to the n-th next character (where n is 'characterLookupRange'), to check for any possible ligature.
-            characterLookupRange = maximumHashKeyLength + i >= to ? to - i : maximumHashKeyLength;
+            characterLookupRange = maximumHashKeyLength + i >= endOfScanRange ? endOfScanRange - i : maximumHashKeyLength;
 
+            // FIXME: instead of checking from longest string to shortest, this should really scan in order
+            // of the glyphs and pick the first match
             while (characterLookupRange > 0 && !foundGlyph) {
                 String lookupString(run.data(run.rtl() ? run.length() - (i + characterLookupRange) : i), characterLookupRange);
 
@@ -272,6 +275,7 @@ struct SVGTextRunWalker {
                     if (identifier.isValid && isCompatibleGlyph(identifier, isVerticalText, language, chars, startPosition, endPosition)) {
                         ASSERT(characterLookupRange > 0);
                         i += characterLookupRange - 1;
+                        m_walkerData.charsConsumed += characterLookupRange;
 
                         foundGlyph = true;
                         SVGGlyphElement::inheritUnspecifiedAttributes(identifier, m_fontData);
@@ -283,6 +287,7 @@ struct SVGTextRunWalker {
             }
 
             if (!foundGlyph) {
+                ++m_walkerData.charsConsumed;
                 if (SVGMissingGlyphElement* element = m_fontElement->firstMissingGlyphElement()) {
                     // <missing-glyph> element support
                     identifier = SVGGlyphElement::buildGenericGlyphIdentifier(element);
@@ -317,6 +322,8 @@ struct SVGTextRunWalkerMeasuredLengthData {
     int at;
     int from;
     int to;
+    int extraCharsAvailable;
+    int charsConsumed;
 
     float scale;
     float length;
@@ -343,7 +350,7 @@ void floatWidthMissingGlyphCallback(const TextRun& run, SVGTextRunWalkerMeasured
     data.length += font.floatWidth(run);
 }
 
-static float floatWidthOfSubStringUsingSVGFont(const Font* font, const TextRun& run, int from, int to)
+static float floatWidthOfSubStringUsingSVGFont(const Font* font, const TextRun& run, int extraCharsAvailable, int from, int to, int& charsConsumed)
 {
     int newFrom = to > from ? from : to;
     int newTo = to > from ? to : from;
@@ -364,6 +371,8 @@ static float floatWidthOfSubStringUsingSVGFont(const Font* font, const TextRun&
         data.at = from;
         data.from = from;
         data.to = to;
+        data.extraCharsAvailable = extraCharsAvailable;
+        data.charsConsumed = 0;
         data.scale = convertEmUnitToPixel(font->size(), fontFaceElement->unitsPerEm(), 1.0f);
         data.length = 0.0f;
 
@@ -380,6 +389,7 @@ static float floatWidthOfSubStringUsingSVGFont(const Font* font, const TextRun&
 
         SVGTextRunWalker<SVGTextRunWalkerMeasuredLengthData> runWalker(fontData, fontElement, data, floatWidthUsingSVGFontCallback, floatWidthMissingGlyphCallback);
         runWalker.walk(run, isVerticalText, language, 0, run.length());
+        charsConsumed = data.charsConsumed;
         return data.length;
     }
 
@@ -388,13 +398,21 @@ static float floatWidthOfSubStringUsingSVGFont(const Font* font, const TextRun&
 
 float Font::floatWidthUsingSVGFont(const TextRun& run) const
 {
-    return floatWidthOfSubStringUsingSVGFont(this, run, 0, run.length());
+    int charsConsumed;
+    return floatWidthOfSubStringUsingSVGFont(this, run, 0, 0, run.length(), charsConsumed);
+}
+
+float Font::floatWidthUsingSVGFont(const TextRun& run, int extraCharsAvailable, int& charsConsumed) const
+{
+    return floatWidthOfSubStringUsingSVGFont(this, run, extraCharsAvailable, 0, run.length(), charsConsumed);
 }
 
 // Callback & data structures to draw text using SVG Fonts
 struct SVGTextRunWalkerDrawTextData {
     float scale;
     bool isVerticalText;
+    int extraCharsAvailable;
+    int charsConsumed;
 
     float xStartOffset;
     FloatPoint currentPoint;
@@ -493,8 +511,9 @@ void Font::drawTextUsingSVGFont(GraphicsContext* context, const TextRun& run,
 
         ASSERT(data.activePaintServer);
 
+        int charsConsumed;
         data.isVerticalText = false;
-        data.xStartOffset = floatWidthOfSubStringUsingSVGFont(this, run, run.rtl() ? to : 0, run.rtl() ? run.length() : from);
+        data.xStartOffset = floatWidthOfSubStringUsingSVGFont(this, run, 0, run.rtl() ? to : 0, run.rtl() ? run.length() : from, charsConsumed);
         data.glyphOrigin = FloatPoint();
         data.context = context;
 
@@ -513,6 +532,8 @@ void Font::drawTextUsingSVGFont(GraphicsContext* context, const TextRun& run,
             data.glyphOrigin.setY(fontData->horizontalOriginY() * data.scale);
         }
 
+        data.extraCharsAvailable = 0;
+
         SVGTextRunWalker<SVGTextRunWalkerDrawTextData> runWalker(fontData, fontElement, data, drawTextUsingSVGFontCallback, drawTextMissingGlyphCallback);
         runWalker.walk(run, data.isVerticalText, language, from, to);
     }
@@ -520,8 +541,9 @@ void Font::drawTextUsingSVGFont(GraphicsContext* context, const TextRun& run,
 
 FloatRect Font::selectionRectForTextUsingSVGFont(const TextRun& run, const IntPoint& point, int height, int from, int to) const
 {
-    return FloatRect(point.x() + floatWidthOfSubStringUsingSVGFont(this, run, run.rtl() ? to : 0, run.rtl() ? run.length() : from),
-                     point.y(), floatWidthOfSubStringUsingSVGFont(this, run, from, to), height);
+    int charsConsumed;
+    return FloatRect(point.x() + floatWidthOfSubStringUsingSVGFont(this, run, 0, run.rtl() ? to : 0, run.rtl() ? run.length() : from, charsConsumed),
+                     point.y(), floatWidthOfSubStringUsingSVGFont(this, run, 0, from, to, charsConsumed), height);
 }
 
 int Font::offsetForPositionForTextUsingSVGFont(const TextRun&, int position, bool includePartialGlyphs) const
index 54069bd7d2348c10f728624cbb90a0dcaf8a8379..e05f2845de9b42edb451f96b6da755ade0c6fd21 100644 (file)
@@ -51,6 +51,7 @@ namespace WebCore {
 
         SVGGlyphIdentifier()
             : isValid(false)
+            , priority(0)
             , orientation(Both)
             , arabicForm(None)
             , horizontalAdvanceX(0.0f)
@@ -82,6 +83,7 @@ namespace WebCore {
         }
 
         bool isValid : 1;
+        int priority;
 
         Orientation orientation : 2;
         ArabicForm arabicForm : 3;
index b0730187b4de598415f0abd89cd98e066e5dfa8e..f03fe78f68eefade0ba64996cdc500799aec04f9 100644 (file)
@@ -79,10 +79,12 @@ static inline float cummulatedCharacterRangeLength(const Vector<SVGChar>::iterat
             if (textBox->m_reversed)
                 newOffset = textBox->start() + textBox->end() - newOffset;
 
+            // FIXME: does this handle multichar glyphs ok? not sure
+            int charsConsumed = 0;
             if (isVerticalText)
-                textLength += textBox->calculateGlyphHeight(style, newOffset);
+                textLength += textBox->calculateGlyphHeight(style, newOffset, 0);
             else
-                textLength += textBox->calculateGlyphWidth(style, newOffset);
+                textLength += textBox->calculateGlyphWidth(style, newOffset, 0, charsConsumed);
         }
 
         if (!usesFullRange) {
@@ -193,10 +195,11 @@ struct SVGInlineTextBoxQueryWalker {
                     if (textBox->m_reversed)
                         newOffset = textBox->start() + textBox->end() - newOffset;
 
+                    int charsConsumed;
                     if (isVerticalText)
-                        m_queryPointResult.move(it->x, it->y + textBox->calculateGlyphHeight(style, newOffset));
+                        m_queryPointResult.move(it->x, it->y + textBox->calculateGlyphHeight(style, newOffset, end - it));
                     else
-                        m_queryPointResult.move(it->x + textBox->calculateGlyphWidth(style, newOffset), it->y);
+                        m_queryPointResult.move(it->x + textBox->calculateGlyphWidth(style, newOffset, end - it, charsConsumed), it->y);
 
                     m_stopProcessing = true;
                     return;