Changeset 82411 in webkit


Ignore:
Timestamp:
Mar 30, 2011 1:36:42 AM (13 years ago)
Author:
Nikolas Zimmermann
Message:

2011-03-29 Nikolas Zimmermann <nzimmermann@rim.com>

Reviewed by Eric Seidel.

REGRESSION (r68976): Incorrect bidi rendering in SVG text
https://bugs.webkit.org/show_bug.cgi?id=53980

Deconvolute SVGTextLayoutEngine code, which was confusing due to the simultaneous processing of the rendered text
in visual and logical order. Added several helper methods to make the code more readable.

Fix Unicode directional formatting characters support, now works as expected.

Test: svg/text/bidi-embedded-direction.svg

  • editing/visible_units.cpp: Refactor getLeafBoxesInLogicalOrder(), move to InlineFlowBox. (WebCore::getLogicalStartBoxAndNode): Use new collectLeafBoxesInLogicalOrder() method in InlineFlowBox. (WebCore::getLogicalEndBoxAndNode): Ditto.
  • rendering/InlineFlowBox.cpp: Add new helper function, that returns a list of all leaf boxes in logical order. (WebCore::InlineFlowBox::collectLeafBoxesInLogicalOrder):
  • rendering/InlineFlowBox.h:
  • rendering/svg/RenderSVGText.cpp: Actually trigger reordering the x/y/dx/dy/rotate value lists, if needed. (WebCore::RenderSVGText::RenderSVGText): (WebCore::RenderSVGText::layout):
  • rendering/svg/RenderSVGText.h: Ditto. (WebCore::RenderSVGText::layoutAttributes): (WebCore::RenderSVGText::needsReordering):
  • rendering/svg/SVGRootInlineBox.cpp: Use new InlineFlowBox::collectLeafBoxesINLogicalOrder(), with a custom "inline box reverse" implementation,

which not only reverses the order of InlineBoxes, but also the order of the x/y/dx/dy/rotate value lists, if needed.

(WebCore::SVGRootInlineBox::computePerCharacterLayoutInformation):
(WebCore::SVGRootInlineBox::layoutCharactersInTextBoxes):
(WebCore::swapItems):
(WebCore::reverseInlineBoxRangeAndValueListsIfNeeded):
(WebCore::SVGRootInlineBox::reorderValueLists):

  • rendering/svg/SVGRootInlineBox.h:
  • rendering/svg/SVGTextLayoutAttributes.cpp: Store RenderSVGInlineText* pointer, where we belong to. (WebCore::SVGTextLayoutAttributes::SVGTextLayoutAttributes): (WebCore::SVGTextLayoutAttributes::dump):
  • rendering/svg/SVGTextLayoutAttributes.h: (WebCore::SVGTextLayoutAttributes::context):
  • rendering/svg/SVGTextLayoutAttributesBuilder.cpp: Pass RenderSVGInlineText* object when creating SVGTextLayoutAttributes. (WebCore::SVGTextLayoutAttributesBuilder::buildLayoutAttributesForTextSubtree): (WebCore::SVGTextLayoutAttributesBuilder::propagateLayoutAttributes):
  • rendering/svg/SVGTextLayoutAttributesBuilder.h:
  • rendering/svg/SVGTextLayoutEngine.cpp: Rewrite & cleanup the main layout algorithm, to be less confusing. (WebCore::SVGTextLayoutEngine::SVGTextLayoutEngine): (WebCore::SVGTextLayoutEngine::updateRelativePositionAdjustmentsIfNeeded): (WebCore::SVGTextLayoutEngine::recordTextFragment): (WebCore::SVGTextLayoutEngine::currentLogicalCharacterAttributes): (WebCore::SVGTextLayoutEngine::currentLogicalCharacterMetrics): (WebCore::SVGTextLayoutEngine::currentVisualCharacterMetrics): (WebCore::SVGTextLayoutEngine::advanceToNextLogicalCharacter): (WebCore::SVGTextLayoutEngine::advanceToNextVisualCharacter): (WebCore::SVGTextLayoutEngine::layoutTextOnLineOrPath):
  • rendering/svg/SVGTextLayoutEngine.h:

2011-03-29 Nikolas Zimmermann <nzimmermann@rim.com>

Reviewed by Eric Seidel.

REGRESSION (r68976): Incorrect bidi rendering in SVG text
https://bugs.webkit.org/show_bug.cgi?id=53980

Add testcase from bug 53980, assuring that BiDi works as well, when using the Unicode directional formatting characters.

  • platform/mac/svg/text/bidi-embedded-direction-expected.checksum: Added.
  • platform/mac/svg/text/bidi-embedded-direction-expected.png: Added.
  • platform/mac/svg/text/bidi-embedded-direction-expected.txt: Added.
  • platform/mac/svg/text/bidi-reorder-value-lists-expected.checksum:
  • platform/mac/svg/text/bidi-reorder-value-lists-expected.png:
  • platform/mac/svg/text/bidi-reorder-value-lists-expected.txt:
  • platform/mac/svg/text/font-size-below-point-five-expected.txt: Update result, as text runs aren't created anymore for empty text.
  • svg/text/bidi-embedded-direction.svg: Added.
  • svg/text/bidi-reorder-value-lists.svg: Extend testcase, to cover more reordering cases.
Location:
trunk
Files:
4 added
20 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r82410 r82411  
     12011-03-29  Nikolas Zimmermann  <nzimmermann@rim.com>
     2
     3        Reviewed by Eric Seidel.
     4
     5        REGRESSION (r68976): Incorrect bidi rendering in SVG text
     6        https://bugs.webkit.org/show_bug.cgi?id=53980
     7
     8        Add testcase from bug 53980, assuring that BiDi works as well, when using the Unicode directional formatting characters.
     9
     10        * platform/mac/svg/text/bidi-embedded-direction-expected.checksum: Added.
     11        * platform/mac/svg/text/bidi-embedded-direction-expected.png: Added.
     12        * platform/mac/svg/text/bidi-embedded-direction-expected.txt: Added.
     13        * platform/mac/svg/text/bidi-reorder-value-lists-expected.checksum:
     14        * platform/mac/svg/text/bidi-reorder-value-lists-expected.png:
     15        * platform/mac/svg/text/bidi-reorder-value-lists-expected.txt:
     16        * platform/mac/svg/text/font-size-below-point-five-expected.txt: Update result, as text runs aren't created anymore for empty text.
     17        * svg/text/bidi-embedded-direction.svg: Added.
     18        * svg/text/bidi-reorder-value-lists.svg: Extend testcase, to cover more reordering cases.
     19
    1202011-03-30  Yuta Kitamura  <yutak@chromium.org>
    221
  • trunk/LayoutTests/platform/mac/svg/text/bidi-reorder-value-lists-expected.checksum

    r81168 r82411  
    1 b5700b4960426f2c6994d4d54f163f7f
     1dcef2f4c8ed6fdd9483bd4070cf5864b
  • trunk/LayoutTests/platform/mac/svg/text/bidi-reorder-value-lists-expected.txt

    r81168 r82411  
    22  RenderView at (0,0) size 800x600
    33layer at (0,0) size 400x400
    4   RenderSVGRoot {svg} at (40,60) size 360x196
    5     RenderSVGContainer {g} at (40,60) size 360x196 [transform={m=((4.00,0.00)(0.00,4.00)) t=(0.00,0.00)}]
    6       RenderSVGText {text} at (10,15) size 90x19 contains 1 chunk(s)
     4  RenderSVGRoot {svg} at (30,15) size 270x237
     5    RenderSVGContainer {g} at (30,15) size 270x237 [transform={m=((3.00,0.00)(0.00,3.00)) t=(0.00,0.00)}]
     6      RenderSVGText {text} at (10,5) size 90x19 contains 1 chunk(s)
    77        RenderSVGInlineText {#text} at (0,0) size 90x19
    8           chunk 1 text run 1 at (10.00,30.00) startOffset 0 endOffset 1 width 9.75: "T"
    9           chunk 1 text run 1 at (20.00,30.00) startOffset 0 endOffset 1 width 7.00: "e"
    10           chunk 1 text run 1 at (30.00,30.00) startOffset 0 endOffset 1 width 6.25: "s"
    11           chunk 1 text run 1 at (40.00,30.00) startOffset 0 endOffset 1 width 4.50: "t"
    12           chunk 1 text run 1 at (50.00,30.00) startOffset 0 endOffset 1 width 4.00: " "
    13           chunk 1 text run 1 at (54.00,30.00) startOffset 0 endOffset 5 width 45.57 RTL: "\x{5D0}\x{5D1}\x{5D2}\x{5D3}\x{5D4}"
     8          chunk 1 text run 1 at (10.00,20.00) startOffset 0 endOffset 1 width 9.67: "T"
     9          chunk 1 text run 1 at (20.00,20.00) startOffset 0 endOffset 1 width 7.00: "e"
     10          chunk 1 text run 1 at (30.00,20.00) startOffset 0 endOffset 1 width 6.33: "s"
     11          chunk 1 text run 1 at (40.00,20.00) startOffset 0 endOffset 1 width 4.33: "t"
     12          chunk 1 text run 1 at (50.00,20.00) startOffset 0 endOffset 1 width 4.00: " "
     13          chunk 1 text run 1 at (54.00,20.00) startOffset 0 endOffset 5 width 45.57 RTL: "\x{5D0}\x{5D1}\x{5D2}\x{5D3}\x{5D4}"
     14      RenderSVGText {text} at (10,25) size 89x19 contains 1 chunk(s)
     15        RenderSVGTSpan {tspan} at (0,0) size 89x19
     16          RenderSVGInlineText {#text} at (0,0) size 89x19
     17            chunk 1 text run 1 at (10.00,40.00) startOffset 0 endOffset 1 width 9.67: "T"
     18            chunk 1 text run 1 at (20.00,40.00) startOffset 0 endOffset 1 width 7.00: "e"
     19            chunk 1 text run 1 at (30.00,40.00) startOffset 0 endOffset 1 width 6.33: "s"
     20            chunk 1 text run 1 at (40.00,40.00) startOffset 0 endOffset 1 width 4.33: "t"
     21            chunk 1 text run 1 at (50.00,40.00) startOffset 0 endOffset 1 width 4.00: " "
     22            chunk 1 text run 1 at (55.00,40.00) startOffset 0 endOffset 1 width 11.39 RTL: "\x{5D4}"
     23            chunk 1 text run 1 at (64.00,40.00) startOffset 0 endOffset 1 width 8.02 RTL: "\x{5D3}"
     24            chunk 1 text run 1 at (72.00,40.00) startOffset 0 endOffset 1 width 6.84 RTL: "\x{5D2}"
     25            chunk 1 text run 1 at (79.00,40.00) startOffset 0 endOffset 1 width 9.01 RTL: "\x{5D1}"
     26            chunk 1 text run 1 at (88.00,40.00) startOffset 0 endOffset 1 width 10.32 RTL: "\x{5D0}"
    1427      RenderSVGText {text} at (10,45) size 89x19 contains 1 chunk(s)
     28        RenderSVGInlineText {#text} at (0,0) size 44x19
     29          chunk 1 text run 1 at (10.00,60.00) startOffset 0 endOffset 1 width 9.67: "T"
     30          chunk 1 text run 1 at (20.00,60.00) startOffset 0 endOffset 1 width 7.00: "e"
     31          chunk 1 text run 1 at (30.00,60.00) startOffset 0 endOffset 1 width 6.33: "s"
     32          chunk 1 text run 1 at (40.00,60.00) startOffset 0 endOffset 1 width 4.33: "t"
     33          chunk 1 text run 1 at (50.00,60.00) startOffset 0 endOffset 1 width 4.00: " "
     34        RenderSVGTSpan {tspan} at (0,0) size 44x19
     35          RenderSVGInlineText {#text} at (45,0) size 44x19
     36            chunk 1 text run 1 at (55.00,60.00) startOffset 0 endOffset 1 width 11.39 RTL: "\x{5D4}"
     37            chunk 1 text run 1 at (64.00,60.00) startOffset 0 endOffset 1 width 8.02 RTL: "\x{5D3}"
     38            chunk 1 text run 1 at (72.00,60.00) startOffset 0 endOffset 1 width 6.84 RTL: "\x{5D2}"
     39            chunk 1 text run 1 at (79.00,60.00) startOffset 0 endOffset 1 width 9.01 RTL: "\x{5D1}"
     40            chunk 1 text run 1 at (88.00,60.00) startOffset 0 endOffset 1 width 10.32 RTL: "\x{5D0}"
     41      RenderSVGText {text} at (10,65) size 89x19 contains 1 chunk(s)
    1542        RenderSVGInlineText {#text} at (0,0) size 89x19
    16           chunk 1 text run 1 at (10.00,60.00) startOffset 0 endOffset 1 width 9.75: "T"
    17           chunk 1 text run 1 at (20.00,60.00) startOffset 0 endOffset 1 width 7.00: "e"
    18           chunk 1 text run 1 at (30.00,60.00) startOffset 0 endOffset 1 width 6.25: "s"
    19           chunk 1 text run 1 at (40.00,60.00) startOffset 0 endOffset 1 width 4.50: "t"
    20           chunk 1 text run 1 at (50.00,60.00) startOffset 0 endOffset 1 width 4.00: " "
    21           chunk 1 text run 1 at (55.00,60.00) startOffset 0 endOffset 1 width 11.39 RTL: "\x{5D4}"
    22           chunk 1 text run 1 at (64.00,60.00) startOffset 0 endOffset 1 width 8.02 RTL: "\x{5D3}"
    23           chunk 1 text run 1 at (72.00,60.00) startOffset 0 endOffset 1 width 6.84 RTL: "\x{5D2}"
    24           chunk 1 text run 1 at (79.00,60.00) startOffset 0 endOffset 1 width 9.01 RTL: "\x{5D1}"
    25           chunk 1 text run 1 at (88.00,60.00) startOffset 0 endOffset 1 width 10.32 RTL: "\x{5D0}"
     43          chunk 1 text run 1 at (10.00,80.00) startOffset 0 endOffset 1 width 9.67: "T"
     44          chunk 1 text run 1 at (20.00,80.00) startOffset 0 endOffset 1 width 7.00: "e"
     45          chunk 1 text run 1 at (30.00,80.00) startOffset 0 endOffset 1 width 6.33: "s"
     46          chunk 1 text run 1 at (40.00,80.00) startOffset 0 endOffset 1 width 4.33: "t"
     47          chunk 1 text run 1 at (50.00,80.00) startOffset 0 endOffset 1 width 4.00: " "
     48          chunk 1 text run 1 at (55.00,80.00) startOffset 0 endOffset 1 width 11.39 RTL: "\x{5D4}"
     49          chunk 1 text run 1 at (64.00,80.00) startOffset 0 endOffset 1 width 8.02 RTL: "\x{5D3}"
     50          chunk 1 text run 1 at (72.00,80.00) startOffset 0 endOffset 1 width 6.84 RTL: "\x{5D2}"
     51          chunk 1 text run 1 at (79.00,80.00) startOffset 0 endOffset 1 width 9.01 RTL: "\x{5D1}"
     52          chunk 1 text run 1 at (88.00,80.00) startOffset 0 endOffset 1 width 10.32 RTL: "\x{5D0}"
  • trunk/LayoutTests/platform/mac/svg/text/font-size-below-point-five-expected.txt

    r77554 r82411  
    3131      RenderSVGTSpan {tspan} at (0,0) size 0x0
    3232        RenderSVGInlineText {#text} at (-10,5) size 0x0
    33           chunk 1 text run 1 at (39.53,10.00) startOffset 0 endOffset 1 width 0.00: "6"
    3433      RenderSVGInlineText {#text} at (0,0) size 0x0
    3534    RenderSVGText {text} at (63,42) size 124x11 contains 1 chunk(s)
  • trunk/LayoutTests/svg/text/bidi-reorder-value-lists.svg

    r81168 r82411  
    11<svg width="400" height="400" xmlns="http://www.w3.org/2000/svg">
    2     <g font-size="16" transform="scale(4,4)">
     2    <g font-size="16" transform="scale(3,3)">
    33        <!-- The order of all characters in both lines should be the same, the spacing is different due the absolute positioning in the second line -->
    4         <text x="10 20 30 40 50" y="30">Test &#x5d0;&#x5d1;&#x5d2;&#x5d3;&#x5d4;</text>
     4        <text y="20" x="10 20 30 40 50">Test &#x5d0;&#x5d1;&#x5d2;&#x5d3;&#x5d4;</text>
    55
    66        <!--
     
    2222          The Hebrew string is reordered, and the x/y/dx/dy/rotate lists as well to maintain correspondence.
    2323         -->
    24         <text x="10 20 30 40 50 88 79 72 64 55" y="60">Test &#x5d0;&#x5d1;&#x5d2;&#x5d3;&#x5d4;</text>
     24        <text y="40"><tspan x="10 20 30 40 50 88 79 72 64 55">Test &#x5d0;&#x5d1;&#x5d2;&#x5d3;&#x5d4;</tspan></text>
     25
     26        <text y="60" x="10 20 30 40 50">Test <tspan x="88 79 72 64 55">&#x5d0;&#x5d1;&#x5d2;&#x5d3;&#x5d4;</tspan></text>
     27
     28        <text y="80" x="10 20 30 40 50 88 79 72 64 55">Test &#x5d0;&#x5d1;&#x5d2;&#x5d3;&#x5d4;</text>
    2529    </g>
    2630</svg>
  • trunk/Source/WebCore/ChangeLog

    r82403 r82411  
     12011-03-29  Nikolas Zimmermann  <nzimmermann@rim.com>
     2
     3        Reviewed by Eric Seidel.
     4
     5        REGRESSION (r68976): Incorrect bidi rendering in SVG text
     6        https://bugs.webkit.org/show_bug.cgi?id=53980
     7
     8        Deconvolute SVGTextLayoutEngine code, which was confusing due to the simultaneous processing of the rendered text
     9        in visual and logical order. Added several helper methods to make the code more readable.
     10
     11        Fix Unicode directional formatting characters support, now works as expected.
     12
     13        Test: svg/text/bidi-embedded-direction.svg
     14
     15        * editing/visible_units.cpp: Refactor getLeafBoxesInLogicalOrder(), move to InlineFlowBox.
     16        (WebCore::getLogicalStartBoxAndNode): Use new collectLeafBoxesInLogicalOrder() method in InlineFlowBox.
     17        (WebCore::getLogicalEndBoxAndNode): Ditto.
     18        * rendering/InlineFlowBox.cpp: Add new helper function, that returns a list of all leaf boxes in logical order.
     19        (WebCore::InlineFlowBox::collectLeafBoxesInLogicalOrder):
     20        * rendering/InlineFlowBox.h:
     21        * rendering/svg/RenderSVGText.cpp: Actually trigger reordering the x/y/dx/dy/rotate value lists, if needed.
     22        (WebCore::RenderSVGText::RenderSVGText):
     23        (WebCore::RenderSVGText::layout):
     24        * rendering/svg/RenderSVGText.h: Ditto.
     25        (WebCore::RenderSVGText::layoutAttributes):
     26        (WebCore::RenderSVGText::needsReordering):
     27        * rendering/svg/SVGRootInlineBox.cpp: Use new InlineFlowBox::collectLeafBoxesINLogicalOrder(), with a custom "inline box reverse" implementation,
     28                                              which not only reverses the order of InlineBoxes, but also the order of the x/y/dx/dy/rotate value lists, if needed.
     29        (WebCore::SVGRootInlineBox::computePerCharacterLayoutInformation):
     30        (WebCore::SVGRootInlineBox::layoutCharactersInTextBoxes):
     31        (WebCore::swapItems):
     32        (WebCore::reverseInlineBoxRangeAndValueListsIfNeeded):
     33        (WebCore::SVGRootInlineBox::reorderValueLists):
     34        * rendering/svg/SVGRootInlineBox.h:
     35        * rendering/svg/SVGTextLayoutAttributes.cpp: Store RenderSVGInlineText* pointer, where we belong to.
     36        (WebCore::SVGTextLayoutAttributes::SVGTextLayoutAttributes):
     37        (WebCore::SVGTextLayoutAttributes::dump):
     38        * rendering/svg/SVGTextLayoutAttributes.h:
     39        (WebCore::SVGTextLayoutAttributes::context):
     40        * rendering/svg/SVGTextLayoutAttributesBuilder.cpp: Pass RenderSVGInlineText* object when creating SVGTextLayoutAttributes.
     41        (WebCore::SVGTextLayoutAttributesBuilder::buildLayoutAttributesForTextSubtree):
     42        (WebCore::SVGTextLayoutAttributesBuilder::propagateLayoutAttributes):
     43        * rendering/svg/SVGTextLayoutAttributesBuilder.h:
     44        * rendering/svg/SVGTextLayoutEngine.cpp: Rewrite & cleanup the main layout algorithm, to be less confusing.
     45        (WebCore::SVGTextLayoutEngine::SVGTextLayoutEngine):
     46        (WebCore::SVGTextLayoutEngine::updateRelativePositionAdjustmentsIfNeeded):
     47        (WebCore::SVGTextLayoutEngine::recordTextFragment):
     48        (WebCore::SVGTextLayoutEngine::currentLogicalCharacterAttributes):
     49        (WebCore::SVGTextLayoutEngine::currentLogicalCharacterMetrics):
     50        (WebCore::SVGTextLayoutEngine::currentVisualCharacterMetrics):
     51        (WebCore::SVGTextLayoutEngine::advanceToNextLogicalCharacter):
     52        (WebCore::SVGTextLayoutEngine::advanceToNextVisualCharacter):
     53        (WebCore::SVGTextLayoutEngine::layoutTextOnLineOrPath):
     54        * rendering/svg/SVGTextLayoutEngine.h:
     55
    1562011-03-30  Ilya Tikhonovsky  <loislo@chromium.org>
    257
  • trunk/Source/WebCore/editing/visible_units.cpp

    r81965 r82411  
    10421042}
    10431043
    1044 static void getLeafBoxesInLogicalOrder(RootInlineBox* rootBox, Vector<InlineBox*>& leafBoxesInLogicalOrder)
    1045 {
    1046     unsigned char minLevel = 128;
    1047     unsigned char maxLevel = 0;
    1048     unsigned count = 0;
    1049     InlineBox* r = rootBox->firstLeafChild();
    1050     // First find highest and lowest levels,
    1051     // and initialize leafBoxesInLogicalOrder with the leaf boxes in visual order.
    1052     while (r) {
    1053         if (r->bidiLevel() > maxLevel)
    1054             maxLevel = r->bidiLevel();
    1055         if (r->bidiLevel() < minLevel)
    1056             minLevel = r->bidiLevel();
    1057         leafBoxesInLogicalOrder.append(r);
    1058         r = r->nextLeafChild();
    1059         ++count;
    1060     }
    1061 
    1062     if (rootBox->renderer()->style()->visuallyOrdered())
    1063         return;
    1064     // Reverse of reordering of the line (L2 according to Bidi spec):
    1065     // L2. From the highest level found in the text to the lowest odd level on each line,
    1066     // reverse any contiguous sequence of characters that are at that level or higher.
    1067 
    1068     // Reversing the reordering of the line is only done up to the lowest odd level.
    1069     if (!(minLevel % 2))
    1070         minLevel++;
    1071    
    1072     InlineBox** end = leafBoxesInLogicalOrder.end();
    1073     while (minLevel <= maxLevel) {
    1074         InlineBox** iter = leafBoxesInLogicalOrder.begin();
    1075         while (iter != end) {
    1076             while (iter != end) {
    1077                 if ((*iter)->bidiLevel() >= minLevel)
    1078                     break;
    1079                 ++iter;
    1080             }
    1081             InlineBox** first = iter;
    1082             while (iter != end) {
    1083                 if ((*iter)->bidiLevel() < minLevel)
    1084                     break;
    1085                 ++iter;
    1086             }
    1087             InlineBox** last = iter;
    1088             std::reverse(first, last);
    1089         }               
    1090         ++minLevel;
    1091     }
    1092 }
    1093 
    10941044static void getLogicalStartBoxAndNode(RootInlineBox* rootBox, InlineBox*& startBox, Node*& startNode)
    10951045{
    10961046    Vector<InlineBox*> leafBoxesInLogicalOrder;
    1097     getLeafBoxesInLogicalOrder(rootBox, leafBoxesInLogicalOrder);
     1047    rootBox->collectLeafBoxesInLogicalOrder(leafBoxesInLogicalOrder);
    10981048    startBox = 0;
    10991049    startNode = 0;
     
    11091059{
    11101060    Vector<InlineBox*> leafBoxesInLogicalOrder;
    1111     getLeafBoxesInLogicalOrder(rootBox, leafBoxesInLogicalOrder);
     1061    rootBox->collectLeafBoxesInLogicalOrder(leafBoxesInLogicalOrder);
    11121062    endBox = 0;
    11131063    endNode = 0;
  • trunk/Source/WebCore/rendering/InlineFlowBox.cpp

    r82280 r82411  
    13351335}
    13361336
     1337void InlineFlowBox::collectLeafBoxesInLogicalOrder(Vector<InlineBox*>& leafBoxesInLogicalOrder, CustomInlineBoxRangeReverse customReverseImplementation, void* userData) const
     1338{
     1339    InlineBox* leaf = firstLeafChild();
     1340
     1341    // FIXME: The reordering code is a copy of parts from BidiResolver::createBidiRunsForLine, operating directly on InlineBoxes, instead of BidiRuns.
     1342    // Investigate on how this code could possibly be shared.
     1343    unsigned char minLevel = 128;
     1344    unsigned char maxLevel = 0;
     1345
     1346    // First find highest and lowest levels, and initialize leafBoxesInLogicalOrder with the leaf boxes in visual order.
     1347    for (; leaf; leaf = leaf->nextLeafChild()) {
     1348        minLevel = min(minLevel, leaf->bidiLevel());
     1349        maxLevel = max(maxLevel, leaf->bidiLevel());
     1350        leafBoxesInLogicalOrder.append(leaf);
     1351    }
     1352
     1353    if (renderer()->style()->visuallyOrdered())
     1354        return;
     1355
     1356    // Reverse of reordering of the line (L2 according to Bidi spec):
     1357    // L2. From the highest level found in the text to the lowest odd level on each line,
     1358    // reverse any contiguous sequence of characters that are at that level or higher.
     1359
     1360    // Reversing the reordering of the line is only done up to the lowest odd level.
     1361    if (!(minLevel % 2))
     1362        ++minLevel;
     1363
     1364    Vector<InlineBox*>::iterator end = leafBoxesInLogicalOrder.end();
     1365    while (minLevel <= maxLevel) {
     1366        Vector<InlineBox*>::iterator it = leafBoxesInLogicalOrder.begin();
     1367        while (it != end) {
     1368            while (it != end) {
     1369                if ((*it)->bidiLevel() >= minLevel)
     1370                    break;
     1371                ++it;
     1372            }
     1373            Vector<InlineBox*>::iterator first = it;
     1374            while (it != end) {
     1375                if ((*it)->bidiLevel() < minLevel)
     1376                    break;
     1377                ++it;
     1378            }
     1379            Vector<InlineBox*>::iterator last = it;
     1380            if (customReverseImplementation) {
     1381                ASSERT(userData);
     1382                (*customReverseImplementation)(userData, first, last);
     1383            } else
     1384                std::reverse(first, last);
     1385        }               
     1386        ++minLevel;
     1387    }
     1388}
     1389
    13371390#ifndef NDEBUG
    13381391
  • trunk/Source/WebCore/rendering/InlineFlowBox.h

    r82280 r82411  
    7676    InlineBox* firstLeafChild() const;
    7777    InlineBox* lastLeafChild() const;
     78
     79    typedef void (*CustomInlineBoxRangeReverse)(void* userData, Vector<InlineBox*>::iterator first, Vector<InlineBox*>::iterator last);
     80    void collectLeafBoxesInLogicalOrder(Vector<InlineBox*>&, CustomInlineBoxRangeReverse customReverseImplementation = 0, void* userData = 0) const;
    7881
    7982    virtual void setConstructed()
  • trunk/Source/WebCore/rendering/svg/RenderSVGText.cpp

    r81992 r82411  
    5252RenderSVGText::RenderSVGText(SVGTextElement* node)
    5353    : RenderSVGBlock(node)
     54    , m_needsReordering(false)
    5455    , m_needsPositioningValuesUpdate(true)
    5556    , m_needsTransformUpdate(true)
     
    128129        SVGTextLayoutAttributesBuilder layoutAttributesBuilder;
    129130        layoutAttributesBuilder.buildLayoutAttributesForTextSubtree(this);
     131        m_needsReordering = true;
    130132        m_needsPositioningValuesUpdate = false;
    131133        updateCachedBoundariesInParents = true;
     
    151153    forceLayoutInlineChildren();
    152154
     155    if (m_needsReordering)
     156        m_needsReordering = false;
     157
    153158    if (!updateCachedBoundariesInParents)
    154159        updateCachedBoundariesInParents = oldBoundaries != objectBoundingBox();
  • trunk/Source/WebCore/rendering/svg/RenderSVGText.h

    r75325 r82411  
    2727#include "AffineTransform.h"
    2828#include "RenderSVGBlock.h"
     29#include "SVGTextLayoutAttributes.h"
    2930
    3031namespace WebCore {
     
    3435class RenderSVGText : public RenderSVGBlock {
    3536public:
    36     RenderSVGText(SVGTextElement* node);
     37    RenderSVGText(SVGTextElement*);
    3738
    3839    void setNeedsPositioningValuesUpdate() { m_needsPositioningValuesUpdate = true; }
     
    4243    static RenderSVGText* locateRenderSVGTextAncestor(RenderObject*);
    4344    static const RenderSVGText* locateRenderSVGTextAncestor(const RenderObject*);
     45
     46    Vector<SVGTextLayoutAttributes>& layoutAttributes() { return m_layoutAttributes; }
     47    bool needsReordering() const { return m_needsReordering; }
    4448
    4549private:
     
    7276    virtual void updateFirstLetter();
    7377
     78    bool m_needsReordering : 1;
    7479    bool m_needsPositioningValuesUpdate : 1;
    7580    bool m_needsTransformUpdate : 1;
    7681    AffineTransform m_localTransform;
     82    Vector<SVGTextLayoutAttributes> m_layoutAttributes;
    7783};
    7884
  • trunk/Source/WebCore/rendering/svg/SVGRootInlineBox.cpp

    r81168 r82411  
    2626#if ENABLE(SVG)
    2727#include "GraphicsContext.h"
    28 #include "RenderBlock.h"
    2928#include "RenderSVGInlineText.h"
     29#include "RenderSVGText.h"
    3030#include "SVGInlineFlowBox.h"
    3131#include "SVGInlineTextBox.h"
     
    7474void SVGRootInlineBox::computePerCharacterLayoutInformation()
    7575{
    76     RenderBlock* parentBlock = block();
     76    RenderSVGText* parentBlock = toRenderSVGText(block());
    7777    ASSERT(parentBlock);
    7878
    79     // Build list of all text boxes which belong to our root renderer, in logical order,
    80     // aka. the order of the characters as they appear in the original document.
    81     // This is needed to maintain correspondence between the x/y/dx/dy/rotate value
    82     // lists and the potentially reordered characters in the inline box tree.
    83     Vector<SVGInlineTextBox*> boxesInLogicalOrder;
    84     buildTextBoxListInLogicalOrder(parentBlock, boxesInLogicalOrder);
     79    Vector<SVGTextLayoutAttributes>& attributes = parentBlock->layoutAttributes();
     80    if (parentBlock->needsReordering())
     81        reorderValueLists(attributes);
    8582
    8683    // Perform SVG text layout phase two (see SVGTextLayoutEngine for details).
    87     SVGTextLayoutEngine characterLayout(boxesInLogicalOrder);
     84    SVGTextLayoutEngine characterLayout(attributes);
    8885    layoutCharactersInTextBoxes(this, characterLayout);
    8986
     
    9592    layoutChildBoxes(this);
    9693    layoutRootBox();
    97 }
    98 
    99 void SVGRootInlineBox::buildTextBoxListInLogicalOrder(RenderObject* start, Vector<SVGInlineTextBox*>& boxes)
    100 {
    101     bool ltr = start->style()->isLeftToRightDirection();
    102     for (RenderObject* child = start->firstChild(); child; child = child->nextSibling()) {
    103         if (child->isSVGInline()) {
    104             buildTextBoxListInLogicalOrder(child, boxes);
    105             continue;
    106         }
    107 
    108         if (!child->isSVGInlineText())
    109             continue;
    110 
    111         RenderSVGInlineText* text = toRenderSVGInlineText(child);
    112         for (InlineTextBox* textBox = ltr ? text->firstTextBox() : text->lastTextBox(); textBox; textBox = ltr ? textBox->nextTextBox() : textBox->prevTextBox()) {
    113             if (!textBox->isSVGInlineTextBox())
    114                 continue;
    115             boxes.append(static_cast<SVGInlineTextBox*>(textBox));
    116         }
    117     }
    11894}
    11995
     
    140116                // Build text chunks for all <textPath> children, using the line layout algorithm.
    141117                // This is needeed as text-anchor is just an additional startOffset for text paths.
    142                 Vector<SVGInlineTextBox*> boxesInLogicalOrder;
    143                 buildTextBoxListInLogicalOrder(flowBox->renderer(), boxesInLogicalOrder);
    144 
    145                 SVGTextLayoutEngine lineLayout(boxesInLogicalOrder);
     118                RenderSVGText* parentBlock = toRenderSVGText(block());
     119                ASSERT(parentBlock);
     120
     121                SVGTextLayoutEngine lineLayout(parentBlock->layoutAttributes());
    146122                layoutCharactersInTextBoxes(flowBox, lineLayout);
    147123
     
    251227    return closestLeaf ? closestLeaf : lastLeaf;
    252228}
     229 
     230static inline void swapItemsInVector(Vector<float>& firstVector, Vector<float>& lastVector, unsigned first, unsigned last)
     231{
     232    float temp = firstVector.at(first);
     233    firstVector.at(first) = lastVector.at(last);
     234    lastVector.at(last) = temp;
     235}
     236
     237static inline void swapItemsInLayoutAttributes(SVGTextLayoutAttributes& firstAttributes, SVGTextLayoutAttributes& lastAttributes, unsigned firstPosition, unsigned lastPosition)
     238{
     239    swapItemsInVector(firstAttributes.xValues(), lastAttributes.xValues(), firstPosition, lastPosition);
     240    swapItemsInVector(firstAttributes.yValues(), lastAttributes.yValues(), firstPosition, lastPosition);
     241    swapItemsInVector(firstAttributes.dxValues(), lastAttributes.dxValues(), firstPosition, lastPosition);
     242    swapItemsInVector(firstAttributes.dyValues(), lastAttributes.dyValues(), firstPosition, lastPosition);
     243    swapItemsInVector(firstAttributes.rotateValues(), lastAttributes.rotateValues(), firstPosition, lastPosition);
     244}
     245
     246static inline void findFirstAndLastAttributesInVector(Vector<SVGTextLayoutAttributes>& attributes, RenderSVGInlineText* firstContext, RenderSVGInlineText* lastContext,
     247                                                      SVGTextLayoutAttributes*& first, SVGTextLayoutAttributes*& last)
     248{
     249    first = 0;
     250    last = 0;
     251
     252    unsigned attributesSize = attributes.size();
     253    for (unsigned i = 0; i < attributesSize; ++i) {
     254        SVGTextLayoutAttributes& current = attributes.at(i);
     255        if (!first && firstContext == current.context())
     256            first = &current;
     257        if (!last && lastContext == current.context())
     258            last = &current;
     259        if (first && last)
     260            break;
     261    }
     262
     263    ASSERT(first);
     264    ASSERT(last);
     265}
     266
     267static inline void reverseInlineBoxRangeAndValueListsIfNeeded(void* userData, Vector<InlineBox*>::iterator first, Vector<InlineBox*>::iterator last)
     268{
     269    ASSERT(userData);
     270    Vector<SVGTextLayoutAttributes>& attributes = *reinterpret_cast<Vector<SVGTextLayoutAttributes>*>(userData);
     271
     272    // This is a copy of std::reverse(first, last). It additionally assure that the value lists within the InlineBoxes are reordered as well.
     273    while (true)  {
     274        if (first == last || first == --last)
     275            return;
     276
     277        ASSERT((*first)->isSVGInlineTextBox());
     278        ASSERT((*last)->isSVGInlineTextBox());
     279
     280        SVGInlineTextBox* firstTextBox = static_cast<SVGInlineTextBox*>(*first);
     281        SVGInlineTextBox* lastTextBox = static_cast<SVGInlineTextBox*>(*last);
     282
     283        // Reordering is only necessary for BiDi text that is _absolutely_ positioned.
     284        if (firstTextBox->len() == 1 && firstTextBox->len() == lastTextBox->len()) {
     285            RenderSVGInlineText* firstContext = toRenderSVGInlineText(firstTextBox->textRenderer());
     286            RenderSVGInlineText* lastContext = toRenderSVGInlineText(lastTextBox->textRenderer());
     287
     288            SVGTextLayoutAttributes* firstAttributes = 0;
     289            SVGTextLayoutAttributes* lastAttributes = 0;
     290            findFirstAndLastAttributesInVector(attributes, firstContext, lastContext, firstAttributes, lastAttributes);
     291
     292            unsigned firstBoxPosition = firstTextBox->start();
     293            unsigned firstBoxEnd = firstTextBox->end();
     294
     295            unsigned lastBoxPosition = lastTextBox->start();
     296            unsigned lastBoxEnd = lastTextBox->end();
     297            for (; firstBoxPosition <= firstBoxEnd && lastBoxPosition <= lastBoxEnd; ++lastBoxPosition, ++firstBoxPosition)
     298                swapItemsInLayoutAttributes(*firstAttributes, *lastAttributes, firstBoxPosition, lastBoxPosition);
     299        }
     300
     301        InlineBox* temp = *first;
     302        *first = *last;
     303        *last = temp;
     304
     305        ++first;
     306    }
     307}
     308
     309void SVGRootInlineBox::reorderValueLists(Vector<SVGTextLayoutAttributes>& attributes)
     310{
     311    Vector<InlineBox*> leafBoxesInLogicalOrder;
     312    collectLeafBoxesInLogicalOrder(leafBoxesInLogicalOrder, reverseInlineBoxRangeAndValueListsIfNeeded, &attributes);
     313}
    253314
    254315} // namespace WebCore
  • trunk/Source/WebCore/rendering/svg/SVGRootInlineBox.h

    r81168 r82411  
    5656
    5757private:
    58     void buildTextBoxListInLogicalOrder(RenderObject*, Vector<SVGInlineTextBox*>&);
     58    void reorderValueLists(Vector<SVGTextLayoutAttributes>&);
    5959    void layoutCharactersInTextBoxes(InlineFlowBox*, SVGTextLayoutEngine&);
    6060    void layoutChildBoxes(InlineFlowBox*);
  • trunk/Source/WebCore/rendering/svg/SVGTextLayoutAttributes.cpp

    r68976 r82411  
    2828namespace WebCore {
    2929
    30 SVGTextLayoutAttributes::SVGTextLayoutAttributes()
     30SVGTextLayoutAttributes::SVGTextLayoutAttributes(RenderSVGInlineText* context)
     31    : m_context(context)
    3132{
    3233}
     
    6667void SVGTextLayoutAttributes::dump() const
    6768{
     69    fprintf(stderr, "context: %p\n", m_context);
     70
    6871    fprintf(stderr, "x values: ");
    6972    dumpLayoutVector(m_xValues);
  • trunk/Source/WebCore/rendering/svg/SVGTextLayoutAttributes.h

    r68976 r82411  
    2828namespace WebCore {
    2929
     30class RenderSVGInlineText;
     31
    3032class SVGTextLayoutAttributes {
    3133public:
    32     SVGTextLayoutAttributes();
     34    SVGTextLayoutAttributes(RenderSVGInlineText* context = 0);
    3335
    3436    void reserveCapacity(unsigned length);
     
    3638
    3739    static float emptyValue();
     40
     41    RenderSVGInlineText* context() const { return m_context; }
    3842
    3943    Vector<float>& xValues() { return m_xValues; }
     
    5660
    5761private:
     62    RenderSVGInlineText* m_context;
    5863    Vector<float> m_xValues;
    5964    Vector<float> m_yValues;
  • trunk/Source/WebCore/rendering/svg/SVGTextLayoutAttributesBuilder.cpp

    r81168 r82411  
    5353
    5454    // Propagate layout attributes to each RenderSVGInlineText object.
     55    Vector<SVGTextLayoutAttributes>& allAttributes = textRoot->layoutAttributes();
     56    allAttributes.clear();
    5557    atCharacter = 0;
    5658    lastCharacter = '\0';
    57     propagateLayoutAttributes(textRoot, atCharacter, lastCharacter);
     59    propagateLayoutAttributes(textRoot, allAttributes, atCharacter, lastCharacter);
    5860}
    5961
     
    187189}
    188190
    189 void SVGTextLayoutAttributesBuilder::propagateLayoutAttributes(RenderObject* start, unsigned& atCharacter, UChar& lastCharacter) const
     191void SVGTextLayoutAttributesBuilder::propagateLayoutAttributes(RenderObject* start, Vector<SVGTextLayoutAttributes>& allAttributes, unsigned& atCharacter, UChar& lastCharacter) const
    190192{
    191193    for (RenderObject* child = start->firstChild(); child; child = child->nextSibling()) {
     
    196198            bool preserveWhiteSpace = shouldPreserveAllWhiteSpace(text->style());
    197199
    198             SVGTextLayoutAttributes attributes;
     200            SVGTextLayoutAttributes attributes(text);
    199201            attributes.reserveCapacity(textLength);
    200202   
     
    244246
    245247            text->storeLayoutAttributes(attributes);
     248            allAttributes.append(attributes);
    246249            atCharacter = valueListPosition;
    247250            continue;
     
    251254            continue;
    252255
    253         propagateLayoutAttributes(child, atCharacter, lastCharacter);
     256        propagateLayoutAttributes(child, allAttributes, atCharacter, lastCharacter);
    254257    }
    255258}
  • trunk/Source/WebCore/rendering/svg/SVGTextLayoutAttributesBuilder.h

    r76248 r82411  
    6161    void buildLayoutScopes(RenderObject*, unsigned& atCharacter, UChar& lastCharacter);
    6262    void buildOutermostLayoutScope(RenderSVGText*, unsigned textLength);
    63     void propagateLayoutAttributes(RenderObject*, unsigned& atCharacter, UChar& lastCharacter) const;
     63    void propagateLayoutAttributes(RenderObject*, Vector<SVGTextLayoutAttributes>& allAttributes, unsigned& atCharacter, UChar& lastCharacter) const;
    6464
    6565    enum LayoutValueType {
  • trunk/Source/WebCore/rendering/svg/SVGTextLayoutEngine.cpp

    r81168 r82411  
    3535namespace WebCore {
    3636
    37 SVGTextLayoutEngine::SVGTextLayoutEngine(Vector<SVGInlineTextBox*>& boxesInLogicalOrder)
    38     : m_x(0)
     37SVGTextLayoutEngine::SVGTextLayoutEngine(Vector<SVGTextLayoutAttributes>& layoutAttributes)
     38    : m_layoutAttributes(layoutAttributes)
     39    , m_logicalCharacterOffset(0)
     40    , m_logicalMetricsListOffset(0)
     41    , m_visualCharacterOffset(0)
     42    , m_visualMetricsListOffset(0)
     43    , m_x(0)
    3944    , m_y(0)
    4045    , m_dx(0)
     
    4752    , m_textPathScaling(1)
    4853{
    49     unsigned size = boxesInLogicalOrder.size();
    50     for (unsigned i = 0; i < size; ++i) {
    51         SVGInlineTextBox* textBox = boxesInLogicalOrder.at(i);
    52         m_ranges.append(CharacterRange(textBox->start(), textBox->end(), textBox));
    53     }
    54 
    55     ASSERT(!m_ranges.isEmpty());
     54    ASSERT(!m_layoutAttributes.isEmpty());
    5655}
    5756
     
    8584}
    8685
    87 void SVGTextLayoutEngine::updateRelativePositionAdjustmentsIfNeeded(Vector<float>& dxValues, Vector<float>& dyValues, unsigned positionListOffset)
     86void SVGTextLayoutEngine::updateRelativePositionAdjustmentsIfNeeded(Vector<float>& dxValues, Vector<float>& dyValues)
    8887{
    8988    // Update relative positioning information.
     
    9392    float dx = 0;
    9493    if (!dxValues.isEmpty()) {
    95         float& dxCurrent = dxValues.at(positionListOffset);
     94        float& dxCurrent = dxValues.at(m_logicalCharacterOffset);
    9695        if (dxCurrent != SVGTextLayoutAttributes::emptyValue())
    9796            dx = dxCurrent;
     
    10099    float dy = 0;
    101100    if (!dyValues.isEmpty()) {
    102         float& dyCurrent = dyValues.at(positionListOffset);
     101        float& dyCurrent = dyValues.at(m_logicalCharacterOffset);
    103102        if (dyCurrent != SVGTextLayoutAttributes::emptyValue())
    104103            dy = dyCurrent;
     
    121120}
    122121
    123 void SVGTextLayoutEngine::recordTextFragment(SVGInlineTextBox* textBox, Vector<SVGTextMetrics>& textMetricsValues, unsigned characterOffset, unsigned metricsListOffset)
     122void SVGTextLayoutEngine::recordTextFragment(SVGInlineTextBox* textBox, Vector<SVGTextMetrics>& textMetricsValues)
    124123{
    125124    ASSERT(!m_currentTextFragment.length);
    126     ASSERT(metricsListOffset > 0);
     125    ASSERT(m_visualMetricsListOffset > 0);
    127126
    128127    // Figure out length of fragment.
    129     m_currentTextFragment.length = characterOffset - m_currentTextFragment.characterOffset;
     128    m_currentTextFragment.length = m_visualCharacterOffset - m_currentTextFragment.characterOffset;
    130129
    131130    // Figure out fragment metrics.
    132     SVGTextMetrics& lastCharacterMetrics = textMetricsValues.at(metricsListOffset - 1);
     131    SVGTextMetrics& lastCharacterMetrics = textMetricsValues.at(m_visualMetricsListOffset - 1);
    133132    m_currentTextFragment.width = lastCharacterMetrics.width();
    134133    m_currentTextFragment.height = lastCharacterMetrics.height();
     
    138137        float length = 0;
    139138        if (m_isVerticalText) {
    140             for (unsigned i = m_currentTextFragment.metricsListOffset; i < metricsListOffset; ++i)
     139            for (unsigned i = m_currentTextFragment.metricsListOffset; i < m_visualMetricsListOffset; ++i)
    141140                length += textMetricsValues.at(i).height();
    142141            m_currentTextFragment.height = length;
    143142        } else {
    144             for (unsigned i = m_currentTextFragment.metricsListOffset; i < metricsListOffset; ++i)
     143            for (unsigned i = m_currentTextFragment.metricsListOffset; i < m_visualMetricsListOffset; ++i)
    145144                length += textMetricsValues.at(i).width();
    146145            m_currentTextFragment.width = length;
     
    344343}
    345344
    346 void SVGTextLayoutEngine::nextLogicalBoxAndOffset(unsigned consumeCharacters, unsigned& positionListOffset, SVGInlineTextBox*& box)
    347 {
    348     ASSERT(!m_ranges.isEmpty());
    349 
    350     unsigned consumed = 0;
    351     do {
    352         CharacterRange& firstRange = m_ranges.first();
    353         if (!consumed) {
    354             positionListOffset = firstRange.start;
    355             box = firstRange.box;
    356         } else
    357             ASSERT(firstRange.box == box);
    358 
    359         ++consumed;
    360         if (firstRange.start == firstRange.end) {
    361             m_ranges.remove(0);
     345bool SVGTextLayoutEngine::currentLogicalCharacterAttributes(SVGTextLayoutAttributes& logicalAttributes)
     346{
     347    logicalAttributes = m_layoutAttributes.first();
     348    if (m_logicalCharacterOffset != logicalAttributes.xValues().size())
     349        return true;
     350
     351    m_layoutAttributes.remove(0);
     352    if (m_layoutAttributes.isEmpty())
     353        return false;
     354
     355    logicalAttributes = m_layoutAttributes.first();
     356    m_logicalMetricsListOffset = 0;
     357    m_logicalCharacterOffset = 0;
     358    return true;
     359}
     360
     361bool SVGTextLayoutEngine::currentLogicalCharacterMetrics(SVGTextLayoutAttributes& logicalAttributes, SVGTextMetrics& logicalMetrics)
     362{
     363    logicalMetrics = SVGTextMetrics::emptyMetrics();
     364
     365    Vector<SVGTextMetrics>& textMetricsValues = logicalAttributes.textMetricsValues();
     366    unsigned textMetricsSize = textMetricsValues.size();
     367    while (true) {
     368        if (m_logicalMetricsListOffset == textMetricsSize) {
     369            if (!currentLogicalCharacterAttributes(logicalAttributes))
     370                return false;
     371
     372            textMetricsValues = logicalAttributes.textMetricsValues();
     373            textMetricsSize = textMetricsValues.size();
    362374            continue;
    363375        }
    364376
    365         ++firstRange.start;
    366     } while (consumed < consumeCharacters);
     377        logicalMetrics = textMetricsValues.at(m_logicalMetricsListOffset);
     378        if (logicalMetrics == SVGTextMetrics::emptyMetrics() || (!logicalMetrics.width() && !logicalMetrics.height())) {
     379            advanceToNextLogicalCharacter(logicalMetrics);
     380            continue;
     381        }
     382
     383        // Stop if we found the next valid logical text metrics object.
     384        return true;
     385    }
     386
     387    ASSERT_NOT_REACHED();
     388    return true;
     389}
     390
     391bool SVGTextLayoutEngine::currentVisualCharacterMetrics(SVGInlineTextBox* textBox, RenderSVGInlineText* text, SVGTextMetrics& metrics)
     392{
     393    SVGTextLayoutAttributes& attributes = text->layoutAttributes();
     394    Vector<SVGTextMetrics>& textMetricsValues = attributes.textMetricsValues();
     395    ASSERT(!textMetricsValues.isEmpty());
     396
     397    unsigned textMetricsSize = textMetricsValues.size();
     398    unsigned boxStart = textBox->start();
     399    unsigned boxLength = textBox->len();
     400
     401    if (m_visualMetricsListOffset == textMetricsSize)
     402        return false;
     403
     404    while (m_visualMetricsListOffset < textMetricsSize) {
     405        SVGTextMetrics& visualMetrics = textMetricsValues.at(m_visualMetricsListOffset);
     406
     407        // Advance to text box start location.
     408        if (m_visualCharacterOffset < boxStart) {
     409            advanceToNextVisualCharacter(visualMetrics);
     410            continue;
     411        }
     412
     413        // Stop if we've finished processing this text box.
     414        if (m_visualCharacterOffset >= boxStart + boxLength)
     415            return false;
     416
     417        metrics = visualMetrics;
     418        return true;
     419    }
     420
     421    return false;
     422}
     423
     424void SVGTextLayoutEngine::advanceToNextLogicalCharacter(const SVGTextMetrics& logicalMetrics)
     425{
     426    ++m_logicalMetricsListOffset;
     427    m_logicalCharacterOffset += logicalMetrics.length();
     428}
     429
     430void SVGTextLayoutEngine::advanceToNextVisualCharacter(const SVGTextMetrics& visualMetrics)
     431{
     432    ++m_visualMetricsListOffset;
     433    m_visualCharacterOffset += visualMetrics.length();
    367434}
    368435
     
    377444    ASSERT(svgStyle);
    378445
    379     SVGTextLayoutAttributes& attributes = text->layoutAttributes();
    380     Vector<SVGTextMetrics>& textMetricsValues = attributes.textMetricsValues();
    381 
    382     unsigned boxStart = textBox->start();
    383     unsigned boxLength = textBox->len();
    384     unsigned textMetricsSize = textMetricsValues.size();
    385 
    386     unsigned positionListOffset = 0;
    387     unsigned metricsListOffset = 0;
    388     unsigned characterOffset = 0;
     446    m_visualMetricsListOffset = 0;
     447    m_visualCharacterOffset = 0;
     448
     449    Vector<SVGTextMetrics>& textMetricsValues = text->layoutAttributes().textMetricsValues();
    389450    const UChar* characters = text->characters();
    390451
     
    401462
    402463    // Main layout algorithm.
    403     // Find the start of the current text box in this list, respecting ligatures.
    404     for (; metricsListOffset < textMetricsSize; ++metricsListOffset) {
    405         SVGTextMetrics& metrics = textMetricsValues.at(metricsListOffset);
    406 
    407         // Advance to text box start location.
    408         if (characterOffset < boxStart) {
    409             characterOffset += metrics.length();
     464    while (true) {
     465        // Find the start of the current text box in this list, respecting ligatures.
     466        SVGTextMetrics visualMetrics = SVGTextMetrics::emptyMetrics();
     467        if (!currentVisualCharacterMetrics(textBox, text, visualMetrics))
     468            break;
     469
     470        if (visualMetrics == SVGTextMetrics::emptyMetrics()) {
     471            advanceToNextVisualCharacter(visualMetrics);
    410472            continue;
    411473        }
    412    
    413         // Stop if we've finished processing this text box.
    414         if (characterOffset >= boxStart + boxLength)
     474
     475        SVGTextLayoutAttributes logicalAttributes;
     476        if (!currentLogicalCharacterAttributes(logicalAttributes))
    415477            break;
    416  
    417         SVGInlineTextBox* ownerBox = 0;
    418         nextLogicalBoxAndOffset(metrics.length(), positionListOffset, ownerBox);
    419 
    420         SVGTextLayoutAttributes& currentBoxAttributes = toRenderSVGInlineText(ownerBox->textRenderer())->layoutAttributes();
    421         Vector<float>& xValues = currentBoxAttributes.xValues();
    422         Vector<float>& yValues = currentBoxAttributes.yValues();
    423 
    424         float x = xValues.at(positionListOffset);
    425         float y = yValues.at(positionListOffset);
     478
     479        SVGTextMetrics logicalMetrics = SVGTextMetrics::emptyMetrics();
     480        if (!currentLogicalCharacterMetrics(logicalAttributes, logicalMetrics))
     481            break;
     482
     483        Vector<float>& xValues = logicalAttributes.xValues();
     484        Vector<float>& yValues = logicalAttributes.yValues();
     485        Vector<float>& dxValues = logicalAttributes.dxValues();
     486        Vector<float>& dyValues = logicalAttributes.dyValues();
     487        Vector<float>& rotateValues = logicalAttributes.rotateValues();
     488
     489        float x = xValues.at(m_logicalCharacterOffset);
     490        float y = yValues.at(m_logicalCharacterOffset);
    426491
    427492        // When we've advanced to the box start offset, determine using the original x/y values,
    428493        // whether this character starts a new text chunk, before doing any further processing.
    429         if (characterOffset == boxStart)
    430             textBox->setStartsNewTextChunk(toRenderSVGInlineText(ownerBox->textRenderer())->characterStartsNewTextChunk(positionListOffset));
    431 
    432         if (metrics == SVGTextMetrics::emptyMetrics()) {
    433             characterOffset += metrics.length();
    434             continue;
    435         }
    436 
    437         const UChar* currentCharacter = characters + characterOffset;
     494        if (m_visualCharacterOffset == textBox->start())
     495            textBox->setStartsNewTextChunk(logicalAttributes.context()->characterStartsNewTextChunk(m_logicalCharacterOffset));
     496
    438497        float angle = 0;
    439         Vector<float>& rotateValues = currentBoxAttributes.rotateValues();
    440498        if (!rotateValues.isEmpty()) {
    441             float newAngle = rotateValues.at(positionListOffset);
     499            float newAngle = rotateValues.at(m_logicalCharacterOffset);
    442500            if (newAngle != SVGTextLayoutAttributes::emptyValue())
    443501                angle = newAngle;
     
    445503
    446504        // Calculate glyph orientation angle.
     505        const UChar* currentCharacter = characters + m_visualCharacterOffset;
    447506        float orientationAngle = baselineLayout.calculateGlyphOrientationAngle(m_isVerticalText, svgStyle, *currentCharacter);
    448507
     
    450509        float xOrientationShift = 0;
    451510        float yOrientationShift = 0;
    452         float glyphAdvance = baselineLayout.calculateGlyphAdvanceAndOrientation(m_isVerticalText, metrics, orientationAngle, xOrientationShift, yOrientationShift);
     511        float glyphAdvance = baselineLayout.calculateGlyphAdvanceAndOrientation(m_isVerticalText, visualMetrics, orientationAngle, xOrientationShift, yOrientationShift);
    453512
    454513        // Assign current text position to x/y values, if needed.
     
    456515
    457516        // Apply dx/dy value adjustments to current text position, if needed.
    458         updateRelativePositionAdjustmentsIfNeeded(currentBoxAttributes.dxValues(), currentBoxAttributes.dyValues(), positionListOffset);
     517        updateRelativePositionAdjustmentsIfNeeded(dxValues, dyValues);
    459518
    460519        // Calculate SVG Fonts kerning, if needed.
    461         float kerning = spacingLayout.calculateSVGKerning(m_isVerticalText, metrics.glyph());
     520        float kerning = spacingLayout.calculateSVGKerning(m_isVerticalText, visualMetrics.glyph());
    462521
    463522        // Calculate CSS 'kerning', 'letter-spacing' and 'word-spacing' for next character, if needed.
     
    499558            // Skip character, if we're before the path.
    500559            if (textPathOffset < 0) {
    501                 characterOffset += metrics.length();
     560                advanceToNextLogicalCharacter(logicalMetrics);
     561                advanceToNextVisualCharacter(visualMetrics);
    502562                continue;
    503563            }
     
    551611        if (didStartTextFragment && shouldStartNewFragment) {
    552612            applySpacingToNextCharacter = false;
    553             recordTextFragment(textBox, textMetricsValues, characterOffset, metricsListOffset);
     613            recordTextFragment(textBox, textMetricsValues);
    554614        }
    555615
     
    560620
    561621            didStartTextFragment = true;
    562             m_currentTextFragment.characterOffset = characterOffset;
    563             m_currentTextFragment.metricsListOffset = metricsListOffset;
     622            m_currentTextFragment.characterOffset = m_visualCharacterOffset;
     623            m_currentTextFragment.metricsListOffset = m_visualMetricsListOffset;
    564624            m_currentTextFragment.x = x;
    565625            m_currentTextFragment.y = y;
     
    602662        }
    603663
    604         characterOffset += metrics.length();
     664        advanceToNextLogicalCharacter(logicalMetrics);
     665        advanceToNextVisualCharacter(visualMetrics);
    605666        lastAngle = angle;
    606667    }
     
    610671
    611672    // Close last open fragment, if needed.
    612     recordTextFragment(textBox, textMetricsValues, characterOffset, metricsListOffset);
     673    recordTextFragment(textBox, textMetricsValues);
    613674}
    614675
  • trunk/Source/WebCore/rendering/svg/SVGTextLayoutEngine.h

    r81168 r82411  
    2525#include "SVGTextChunkBuilder.h"
    2626#include "SVGTextFragment.h"
     27#include "SVGTextLayoutAttributes.h"
    2728#include "SVGTextMetrics.h"
    2829#include <wtf/Vector.h>
     
    4849    WTF_MAKE_NONCOPYABLE(SVGTextLayoutEngine);
    4950public:
    50     SVGTextLayoutEngine(Vector<SVGInlineTextBox*>& boxesInLogicalOrder);
     51    SVGTextLayoutEngine(Vector<SVGTextLayoutAttributes>&);
    5152    SVGTextChunkBuilder& chunkLayoutBuilder() { return m_chunkLayoutBuilder; }
    5253
     
    5859
    5960private:
    60     struct CharacterRange {
    61         CharacterRange(unsigned newStart = 0, unsigned newEnd = 0, SVGInlineTextBox* newBox = 0)
    62             : start(newStart)
    63             , end(newEnd)
    64             , box(newBox)
    65         {
    66         }
    67 
    68         unsigned start;
    69         unsigned end;
    70         SVGInlineTextBox* box;
    71     };
    72 
    73     typedef Vector<CharacterRange> CharacterRanges;
    74 
    7561    void updateCharacerPositionIfNeeded(float& x, float& y);
    7662    void updateCurrentTextPosition(float x, float y, float glyphAdvance);
    77     void updateRelativePositionAdjustmentsIfNeeded(Vector<float>& dxValues, Vector<float>& dyValues, unsigned valueListPosition);
     63    void updateRelativePositionAdjustmentsIfNeeded(Vector<float>& dxValues, Vector<float>& dyValues);
    7864
    79     void recordTextFragment(SVGInlineTextBox*, Vector<SVGTextMetrics>& textMetricValues, unsigned characterOffset, unsigned metricsListOffset);
     65    void recordTextFragment(SVGInlineTextBox*, Vector<SVGTextMetrics>& textMetricValues);
    8066    bool parentDefinesTextLength(RenderObject*) const;
    8167
     
    8369    void finalizeTransformMatrices(Vector<SVGInlineTextBox*>&);
    8470
    85     void nextLogicalBoxAndOffset(unsigned consumeCharacters, unsigned& positionListOffset, SVGInlineTextBox*&);
     71    bool currentLogicalCharacterAttributes(SVGTextLayoutAttributes&);
     72    bool currentLogicalCharacterMetrics(SVGTextLayoutAttributes&, SVGTextMetrics&);
     73    bool currentVisualCharacterMetrics(SVGInlineTextBox*, RenderSVGInlineText*, SVGTextMetrics&);
     74
     75    void advanceToNextLogicalCharacter(const SVGTextMetrics&);
     76    void advanceToNextVisualCharacter(const SVGTextMetrics&);
    8677
    8778private:
    88     CharacterRanges m_ranges;
     79    Vector<SVGTextLayoutAttributes> m_layoutAttributes;
    8980    Vector<SVGInlineTextBox*> m_lineLayoutBoxes;
    9081    Vector<SVGInlineTextBox*> m_pathLayoutBoxes;
     
    9283
    9384    SVGTextFragment m_currentTextFragment;
     85    unsigned m_logicalCharacterOffset;
     86    unsigned m_logicalMetricsListOffset;
     87    unsigned m_visualCharacterOffset;
     88    unsigned m_visualMetricsListOffset;
    9489    float m_x;
    9590    float m_y;
Note: See TracChangeset for help on using the changeset viewer.