Changeset 105143 in webkit


Ignore:
Timestamp:
Jan 17, 2012 4:42:25 AM (12 years ago)
Author:
Nikolas Zimmermann
Message:

Large SVG text layout performance regression in r81168
https://bugs.webkit.org/show_bug.cgi?id=65711

Reviewed by Zoltan Herczeg.

Source/WebCore:

Final patch fixing the performance regression from r81168 plus giving us more performance we ever had.
The testcase attached to bug 65711 creates 200 tspans as <text> children, and modifies just the first <tspan>s
content periodically using a timer. It ran with <3 FPS in release builds before, and now at around 60 FPS,
where the most dominant code path remaining is CG painting text. Still theres room to optimize further, as
Intruments shows.

Historically we rebuilt all SVGTextLayoutAttributes stored in the RenderSVGInlineText, whenever any
children of the <text> subtree changed, in any way. This lead to a recomputation of the x/y/dx/dy/rotate
value lists, for the whole tree, a recreation of the line box tree and finally a measurement of all characters
in the subtree.

This patch, and its previous patches preparing this, introduces progressive relayout for the SVG text subtree.
DOM tree mutations, x/y/dx/dy/rotate value lists changes, and measuring-all-characters are now strictly decoupled.

#1) x/y/dx/dy/rotate list changes:
The x/y/dx/dy/rotate lists are only ever rebuilt, if they change or upon the initial RenderSVGText layout.
This information is now cached in the so-called SVGCharacterDataMap, in each of the SVGTextLayoutAttributes,
associated with a specific RenderSVGInlineText.

#2) DOM tree mutations:
If a new RenderSVGInlineText gets added to the tree, we have to create SVGTextLayoutAttributes for the new
renderer, measure its characters, and cache the information in the attributes. Adding a new renderer to
a SVG <text> subtree can affect the positioning of the previous and next sibling in the tree, due the
whitespace merging logic. Example:

<text y="50" x="50 100 150">A<tspan></tspan> C</text>:
RenderSVGText {text} at (50,36) size 111x18 contains 1 chunk(s)

RenderSVGInlineText {#text} at (0,0) size 12x18

chunk 1 text run 1 at (50.00,50.00) startOffset 0 endOffset 1 width 12.00: "A"

RenderSVGTSpan {tspan} at (0,0) size 0x0
RenderSVGInlineText {#text} at (50,0) size 61x18

chunk 1 text run 1 at (100.00,50.00) startOffset 0 endOffset 1 width 4.00: " "
chunk 1 text run 1 at (150.00,50.00) startOffset 0 endOffset 1 width 11.00: "C"

<text y="50" x="50 100 150">A<tspan>B</tspan> C</text>:
RenderSVGText {text} at (50,36) size 115x18 contains 1 chunk(s)

RenderSVGInlineText {#text} at (0,0) size 12x18

chunk 1 text run 1 at (50.00,50.00) startOffset 0 endOffset 1 width 12.00: "A"

RenderSVGTSpan {tspan} at (0,0) size 11x18

RenderSVGInlineText {#text} at (50,0) size 11x18

chunk 1 text run 1 at (100.00,50.00) startOffset 0 endOffset 1 width 11.00: "B"

RenderSVGInlineText {#text} at (100,0) size 15x18

chunk 1 text run 1 at (150.00,50.00) startOffset 0 endOffset 2 width 15.00: " C"

Its obvious that adding a #text node as child to the <tspan> potentially affects the next & previous
siblings in the DOM tree. Take extra care of these possibilities, by properly remeasuring not only
the newly added renderer, but also the previous & next siblings layout attributes.

Mutation of text nodes, or removal of text/tspan elements from the tree is handled in the same way.

#3) Measuring the text subtree:
Don't cache the metrics information in the SVGRootInlineBox, as it doesn't survive relayouts (RenderSVGText::layout).
They're stored in the SVGTextLayoutAttributes, and will be updated if the underlying text content changes.

Tests: svg/text/append-text-node-to-tspan.html

svg/text/modify-text-node-in-tspan.html
svg/text/remove-text-node-from-tspan.html

  • rendering/svg/RenderSVGInline.cpp:

(WebCore::RenderSVGInline::addChild):

  • rendering/svg/RenderSVGInline.h:
  • rendering/svg/RenderSVGInlineText.cpp:

(WebCore::RenderSVGInlineText::willBeDestroyed):
(WebCore::RenderSVGInlineText::setTextInternal):
(WebCore::RenderSVGInlineText::styleDidChange):

  • rendering/svg/RenderSVGInlineText.h:

(WebCore::RenderSVGInlineText::layoutAttributes):

  • rendering/svg/RenderSVGText.cpp:

(WebCore::recursiveUpdateLayoutAttributes):
(WebCore::RenderSVGText::layoutAttributesChanged):
(WebCore::findPreviousAndNextAttributes):
(WebCore::RenderSVGText::layoutAttributesWillBeDestroyed):
(WebCore::RenderSVGText::textDOMChanged):
(WebCore::RenderSVGText::layout):
(WebCore::RenderSVGText::addChild):
(WebCore::recursiveCollectLayoutAttributes):
(WebCore::RenderSVGText::rebuildLayoutAttributes):

  • rendering/svg/RenderSVGText.h:

(WebCore::RenderSVGText::layoutAttributes):

  • rendering/svg/SVGRootInlineBox.cpp:

(WebCore::SVGRootInlineBox::computePerCharacterLayoutInformation):
(WebCore::findFirstAndLastAttributesInVector):
(WebCore::reverseInlineBoxRangeAndValueListsIfNeeded):
(WebCore::SVGRootInlineBox::reorderValueLists):

  • rendering/svg/SVGRootInlineBox.h:
  • rendering/svg/SVGTextLayoutAttributes.h:
  • rendering/svg/SVGTextLayoutAttributesBuilder.cpp:

(WebCore::SVGTextLayoutAttributesBuilder::rebuildMetricsForWholeTree):

  • rendering/svg/SVGTextLayoutEngine.cpp:

(WebCore::SVGTextLayoutEngine::SVGTextLayoutEngine):
(WebCore::SVGTextLayoutEngine::currentLogicalCharacterAttributes):
(WebCore::SVGTextLayoutEngine::currentLogicalCharacterMetrics):
(WebCore::SVGTextLayoutEngine::currentVisualCharacterMetrics):
(WebCore::SVGTextLayoutEngine::layoutTextOnLineOrPath):

  • rendering/svg/SVGTextLayoutEngine.h:

(WebCore::SVGTextLayoutEngine::layoutAttributes):

  • rendering/svg/SVGTextMetrics.h:
  • rendering/svg/SVGTextMetricsBuilder.cpp:

(WebCore::SVGTextMetricsBuilder::measureTextRenderer):

  • rendering/svg/SVGTextQuery.cpp:

(WebCore::SVGTextQuery::modifyStartEndPositionsRespectingLigatures):

  • svg/SVGTextContentElement.cpp:

(WebCore::SVGTextContentElement::childrenChanged):

LayoutTests:

Update some results, that changed again slightly. Land new tests covering partial SVG <text> subtree updating.

  • platform/chromium/test_expectations.txt:
  • platform/mac/svg/carto.net/window-expected.png:
  • platform/mac/svg/carto.net/window-expected.txt:
  • platform/mac/svg/custom/js-late-clipPath-and-object-creation-expected.png:
  • platform/mac/svg/custom/js-late-clipPath-and-object-creation-expected.txt:
  • platform/mac/svg/custom/js-late-gradient-and-object-creation-expected.png:
  • platform/mac/svg/custom/js-late-gradient-and-object-creation-expected.txt:
  • platform/mac/svg/custom/js-late-pattern-and-object-creation-expected.png:
  • platform/mac/svg/custom/js-late-pattern-and-object-creation-expected.txt:
  • platform/mac/svg/custom/use-detach-expected.png:
  • platform/mac/svg/custom/use-detach-expected.txt:
  • platform/mac/svg/text/append-text-node-to-tspan-expected.png: Added.
  • platform/mac/svg/text/append-text-node-to-tspan-expected.txt: Added.
  • platform/mac/svg/text/modify-text-node-in-tspan-expected.png: Added.
  • platform/mac/svg/text/modify-text-node-in-tspan-expected.txt: Added.
  • platform/mac/svg/text/remove-text-node-from-tspan-expected.png: Added.
  • platform/mac/svg/text/remove-text-node-from-tspan-expected.txt: Added.
  • svg/text/append-text-node-to-tspan.html: Added.
  • svg/text/modify-text-node-in-tspan.html: Added.
  • svg/text/remove-text-node-from-tspan.html: Added.
Location:
trunk
Files:
12 added
29 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r105141 r105143  
     12012-01-17  Nikolas Zimmermann  <nzimmermann@rim.com>
     2
     3        Large SVG text layout performance regression in r81168
     4        https://bugs.webkit.org/show_bug.cgi?id=65711
     5
     6        Reviewed by Zoltan Herczeg.
     7
     8        Update some results, that changed again slightly. Land new tests covering partial SVG <text> subtree updating.
     9
     10        * platform/chromium/test_expectations.txt:
     11        * platform/mac/svg/carto.net/window-expected.png:
     12        * platform/mac/svg/carto.net/window-expected.txt:
     13        * platform/mac/svg/custom/js-late-clipPath-and-object-creation-expected.png:
     14        * platform/mac/svg/custom/js-late-clipPath-and-object-creation-expected.txt:
     15        * platform/mac/svg/custom/js-late-gradient-and-object-creation-expected.png:
     16        * platform/mac/svg/custom/js-late-gradient-and-object-creation-expected.txt:
     17        * platform/mac/svg/custom/js-late-pattern-and-object-creation-expected.png:
     18        * platform/mac/svg/custom/js-late-pattern-and-object-creation-expected.txt:
     19        * platform/mac/svg/custom/use-detach-expected.png:
     20        * platform/mac/svg/custom/use-detach-expected.txt:
     21        * platform/mac/svg/text/append-text-node-to-tspan-expected.png: Added.
     22        * platform/mac/svg/text/append-text-node-to-tspan-expected.txt: Added.
     23        * platform/mac/svg/text/modify-text-node-in-tspan-expected.png: Added.
     24        * platform/mac/svg/text/modify-text-node-in-tspan-expected.txt: Added.
     25        * platform/mac/svg/text/remove-text-node-from-tspan-expected.png: Added.
     26        * platform/mac/svg/text/remove-text-node-from-tspan-expected.txt: Added.
     27        * svg/text/append-text-node-to-tspan.html: Added.
     28        * svg/text/modify-text-node-in-tspan.html: Added.
     29        * svg/text/remove-text-node-from-tspan.html: Added.
     30
    1312012-01-17  Alexander Pavlov  <apavlov@chromium.org>
    232
  • trunk/LayoutTests/platform/chromium/test_expectations.txt

    r105085 r105143  
    38443844// Started failing at http://trac.webkit.org/changeset/105007
    38453845BUGCR110365 WIN : webaudio/gain.html = PASS AUDIO
     3846
     3847// SVG text layout optimizations: probably just need a rebaseline for chromium.
     3848BUGWK65711 : svg/carto.net/window.svg = IMAGE+TEXT IMAGE
     3849BUGWK65711 : svg/text/remove-tspan-from-text.html = IMAGE+TEXT IMAGE
     3850BUGWK65711 : svg/custom/use-detach.svg = IMAGE+TEXT IMAGE
     3851BUGWK65711 : svg/custom/js-late-clipPath-and-object-creation.svg = IMAGE+TEXT IMAGE
     3852BUGWK65711 : svg/custom/js-late-gradient-and-object-creation.svg = IMAGE+TEXT IMAGE
     3853BUGWK65711 : svg/text/modify-text-node-in-tspan.html = IMAGE+TEXT IMAGE
     3854BUGWK65711 : svg/text/remove-text-node-from-tspan.html = IMAGE+TEXT IMAGE
     3855BUGWK65711 : svg/custom/js-late-pattern-and-object-creation.svg = IMAGE+TEXT IMAGE
     3856BUGWK65711 : svg/text/append-text-node-to-tspan.html = IMAGE+TEXT IMAGE
  • trunk/LayoutTests/platform/mac/svg/carto.net/window-expected.txt

    r105061 r105143  
    9191            RenderSVGRect {rect} at (613,81) size 16x159 [fill={[type=SOLID] [color=#B0C4DE]}] [x=-15.00] [y=-15.00] [width=20.00] [height=202.00]
    9292            RenderSVGRect {rect} at (613,81) size 185x16 [fill={[type=SOLID] [color=#B0C4DE]}] [x=-15.00] [y=-15.00] [width=236.00] [height=20.00]
    93             RenderSVGText {text} at (0,169) size 99x13 contains 1 chunk(s)
    94               RenderSVGInlineText {#text} at (0,0) size 99x13
    95                 chunk 1 text run 1 at (0.00,180.00) startOffset 0 endOffset 17 width 98.56: "Navigation Window"
     93            RenderSVGText {text} at (0,169) size 106x14 contains 1 chunk(s)
     94              RenderSVGInlineText {#text} at (0,0) size 106x14
     95                chunk 1 text run 1 at (0.00,180.00) startOffset 0 endOffset 17 width 106.00: "Navigation Window"
    9696          RenderSVGContainer {use} at (616,84) size 10x10
    9797            RenderSVGContainer {g} at (616,84) size 10x10 [transform={m=((1.00,0.00)(0.00,1.00)) t=(-5.00,-5.00)}]
  • trunk/LayoutTests/platform/mac/svg/custom/js-late-clipPath-and-object-creation-expected.txt

    r101342 r105143  
    44  RenderSVGRoot {svg} at (16,40) size 318x173
    55    RenderSVGContainer {g} at (16,40) size 318x173 [transform={m=((1.00,0.00)(0.00,1.50)) t=(0.00,0.00)}]
    6       RenderSVGText {text} at (10,16) size 528x69 contains 1 chunk(s)
     6      RenderSVGText {text} at (10,16) size 529x69 contains 1 chunk(s)
    77        [clipPath="dynClip"] RenderSVGResourceClipper {clipPath} at (0,0) size 200x200
    8         RenderSVGInlineText {#text} at (0,0) size 528x69
     8        RenderSVGInlineText {#text} at (0,0) size 529x69
    99          [clipPath="dynClip"] RenderSVGResourceClipper {clipPath} at (0,0) size 200x200
    10           chunk 1 text run 1 at (10.00,70.00) startOffset 0 endOffset 19 width 527.63: "Clipped. INVISIBLE."
     10          chunk 1 text run 1 at (10.00,70.00) startOffset 0 endOffset 19 width 529.00: "Clipped. INVISIBLE."
    1111      RenderSVGResourceClipper {clipPath} [id="dynClip"] [clipPathUnits=userSpaceOnUse]
    1212        RenderSVGPath {path} at (0,0) size 334x500 [fill={[type=SOLID] [color=#000000]}] [data="M 0 0 L 200 0 L 200 200 L 0 200 Z"]
  • trunk/LayoutTests/platform/mac/svg/custom/js-late-gradient-and-object-creation-expected.txt

    r101342 r105143  
    22  RenderView at (0,0) size 800x600
    33layer at (0,0) size 800x600
    4   RenderSVGRoot {svg} at (0,13) size 757x367
    5     RenderSVGContainer {g} at (0,13) size 757x367
     4  RenderSVGRoot {svg} at (0,15) size 760x365
     5    RenderSVGContainer {g} at (0,15) size 760x365
    66      RenderSVGResourceLinearGradient {linearGradient} [id="fillLinearGradient"] [gradientUnits=objectBoundingBox] [start=(0,0)] [end=(1,0)]
    77        RenderSVGGradientStop {stop} [offset=0.00] [color=#0000FF]
     
    99      RenderSVGResourceLinearGradient {linearGradient} [id="strokeLinearGradient"] [gradientUnits=objectBoundingBox] [start=(0,0)] [end=(1,0)]
    1010        RenderSVGGradientStop {stop} [offset=1.00] [color=#008000]
    11       RenderSVGText {text} at (-150,8) size 419x78 contains 1 chunk(s)
    12         RenderSVGInlineText {#text} at (0,0) size 419x78
    13           chunk 1 text run 1 at (-150.00,70.00) startOffset 0 endOffset 16 width 418.20: "Gradient on fill"
    14       RenderSVGText {text} at (-150,78) size 506x78 contains 1 chunk(s)
     11      RenderSVGText {text} at (-150,9) size 420x78 contains 1 chunk(s)
     12        RenderSVGInlineText {#text} at (0,0) size 420x78
     13          chunk 1 text run 1 at (-150.00,70.00) startOffset 0 endOffset 16 width 420.00: "Gradient on fill"
     14      RenderSVGText {text} at (-150,79) size 506x78 contains 1 chunk(s)
    1515        RenderSVGInlineText {#text} at (0,0) size 506x78
    16           chunk 1 text run 1 at (-150.00,140.00) startOffset 0 endOffset 18 width 505.80: "Gradient on stroke"
    17       RenderSVGText {text} at (-150,148) size 603x78 contains 1 chunk(s)
    18         RenderSVGInlineText {#text} at (0,0) size 603x78
    19           chunk 1 text run 1 at (-150.00,210.00) startOffset 0 endOffset 23 width 603.00: "Gradient on fill/stroke"
     16          chunk 1 text run 1 at (-150.00,140.00) startOffset 0 endOffset 18 width 506.00: "Gradient on stroke"
     17      RenderSVGText {text} at (-150,149) size 605x78 contains 1 chunk(s)
     18        RenderSVGInlineText {#text} at (0,0) size 605x78
     19          chunk 1 text run 1 at (-150.00,210.00) startOffset 0 endOffset 23 width 605.00: "Gradient on fill/stroke"
  • trunk/LayoutTests/platform/mac/svg/custom/js-late-pattern-and-object-creation-expected.txt

    r103407 r105143  
    22  RenderView at (0,0) size 800x600
    33layer at (0,0) size 800x600
    4   RenderSVGRoot {svg} at (0,13) size 682x367
    5     RenderSVGContainer {g} at (0,13) size 682x367
     4  RenderSVGRoot {svg} at (0,15) size 685x365
     5    RenderSVGContainer {g} at (0,15) size 685x365
    66      RenderSVGResourcePattern {pattern} [id="fillPattern"] [patternUnits=userSpaceOnUse] [patternContentUnits=userSpaceOnUse]
    77        RenderSVGRect {rect} at (8,8) size 17x17 [fill={[type=SOLID] [color=#FF0000]}] [x=5.00] [y=5.00] [width=10.00] [height=10.00]
     
    1010        RenderSVGRect {rect} at (8,8) size 17x17 [fill={[type=SOLID] [color=#FFFF00]}] [x=5.00] [y=5.00] [width=10.00] [height=10.00]
    1111        RenderSVGRect {rect} at (16,16) size 18x18 [fill={[type=SOLID] [color=#0000FF]}] [x=10.00] [y=10.00] [width=10.00] [height=10.00]
    12       RenderSVGText {text} at (-150,8) size 373x78 contains 1 chunk(s)
    13         RenderSVGInlineText {#text} at (0,0) size 373x78
    14           chunk 1 text run 1 at (-150.00,70.00) startOffset 0 endOffset 15 width 372.60: "Pattern on fill"
    15       RenderSVGText {text} at (-150,78) size 461x78 contains 1 chunk(s)
     12      RenderSVGText {text} at (-150,9) size 375x78 contains 1 chunk(s)
     13        RenderSVGInlineText {#text} at (0,0) size 375x78
     14          chunk 1 text run 1 at (-150.00,70.00) startOffset 0 endOffset 15 width 375.00: "Pattern on fill"
     15      RenderSVGText {text} at (-150,79) size 461x78 contains 1 chunk(s)
    1616        RenderSVGInlineText {#text} at (0,0) size 461x78
    17           chunk 1 text run 1 at (-150.00,140.00) startOffset 0 endOffset 17 width 460.20: "Pattern on stroke"
    18       RenderSVGText {text} at (-150,148) size 558x78 contains 1 chunk(s)
    19         RenderSVGInlineText {#text} at (0,0) size 558x78
    20           chunk 1 text run 1 at (-150.00,210.00) startOffset 0 endOffset 22 width 557.40: "Pattern on fill/stroke"
     17          chunk 1 text run 1 at (-150.00,140.00) startOffset 0 endOffset 17 width 461.00: "Pattern on stroke"
     18      RenderSVGText {text} at (-150,149) size 560x78 contains 1 chunk(s)
     19        RenderSVGInlineText {#text} at (0,0) size 560x78
     20          chunk 1 text run 1 at (-150.00,210.00) startOffset 0 endOffset 22 width 560.00: "Pattern on fill/stroke"
  • trunk/LayoutTests/platform/mac/svg/custom/use-detach-expected.txt

    r103407 r105143  
    99            chunk 1 (middle anchor) text run 1 at (41.88,31.00) startOffset 0 endOffset 3 width 16.25: "use"
    1010        RenderSVGPath {circle} at (220,96) size 24x24 [fill={[type=SOLID] [color=#FF0000]}] [cx=50.00] [cy=40.00] [r=5.00]
    11       RenderSVGContainer {g} at (208,57) size 48x65
    12         RenderSVGContainer {use} at (208,57) size 48x42
    13           RenderSVGContainer {g} at (208,57) size 48x42
    14             RenderSVGText {text} at (41,20) size 17x14 contains 1 chunk(s)
    15               RenderSVGInlineText {#text} at (0,0) size 17x14
    16                 chunk 1 (middle anchor) text run 1 at (41.88,31.00) startOffset 0 endOffset 3 width 16.25: "use"
     11      RenderSVGContainer {g} at (210,57) size 44x65
     12        RenderSVGContainer {use} at (210,57) size 44x39
     13          RenderSVGContainer {g} at (210,57) size 44x39
     14            RenderSVGText {text} at (42,20) size 16x14 contains 1 chunk(s)
     15              RenderSVGInlineText {#text} at (0,0) size 16x14
     16                chunk 1 (middle anchor) text run 1 at (42.00,31.00) startOffset 0 endOffset 3 width 16.00: "use"
    1717        RenderSVGContainer {use} at (218,94) size 28x28
    1818          RenderSVGContainer {g} at (218,94) size 28x28
  • trunk/Source/WebCore/ChangeLog

    r105140 r105143  
     12012-01-17  Nikolas Zimmermann  <nzimmermann@rim.com>
     2
     3        Large SVG text layout performance regression in r81168
     4        https://bugs.webkit.org/show_bug.cgi?id=65711
     5
     6        Reviewed by Zoltan Herczeg.
     7
     8        Final patch fixing the performance regression from r81168 plus giving us more performance we ever had.
     9        The testcase attached to bug 65711 creates 200 tspans as <text> children, and modifies just the first <tspan>s
     10        content periodically using a timer. It ran with <3 FPS in release builds before, and now at around 60 FPS,
     11        where the most dominant code path remaining is CG painting text. Still theres room to optimize further, as
     12        Intruments shows.
     13
     14        Historically we rebuilt all SVGTextLayoutAttributes stored in the RenderSVGInlineText, whenever any
     15        children of the <text> subtree changed, in any way. This lead to a recomputation of the x/y/dx/dy/rotate
     16        value lists, for the whole tree, a recreation of the line box tree and finally a measurement of all characters
     17        in the subtree.
     18
     19        This patch, and its previous patches preparing this, introduces progressive relayout for the SVG text subtree.
     20        DOM tree mutations, x/y/dx/dy/rotate value lists changes, and measuring-all-characters are now strictly decoupled.
     21
     22        #1) x/y/dx/dy/rotate list changes:
     23        The x/y/dx/dy/rotate lists are only ever rebuilt, if they change or upon the initial RenderSVGText layout.
     24        This information is now cached in the so-called SVGCharacterDataMap, in each of the SVGTextLayoutAttributes,
     25        associated with a specific RenderSVGInlineText.
     26
     27        #2) DOM tree mutations:
     28        If a new RenderSVGInlineText gets added to the tree, we have to create SVGTextLayoutAttributes for the new
     29        renderer, measure its characters, and cache the information in the attributes. Adding a new renderer to
     30        a SVG <text> subtree can affect the positioning of the previous and next sibling in the tree, due the
     31        whitespace merging logic. Example:
     32
     33        <text y="50" x="50 100 150">A<tspan></tspan> C</text>:
     34        RenderSVGText {text} at (50,36) size 111x18 contains 1 chunk(s)
     35          RenderSVGInlineText {#text} at (0,0) size 12x18
     36            chunk 1 text run 1 at (50.00,50.00) startOffset 0 endOffset 1 width 12.00: "A"
     37          RenderSVGTSpan {tspan} at (0,0) size 0x0
     38          RenderSVGInlineText {#text} at (50,0) size 61x18
     39            chunk 1 text run 1 at (100.00,50.00) startOffset 0 endOffset 1 width 4.00: " "
     40            chunk 1 text run 1 at (150.00,50.00) startOffset 0 endOffset 1 width 11.00: "C"
     41
     42        <text y="50" x="50 100 150">A<tspan>B</tspan> C</text>:
     43        RenderSVGText {text} at (50,36) size 115x18 contains 1 chunk(s)
     44          RenderSVGInlineText {#text} at (0,0) size 12x18
     45            chunk 1 text run 1 at (50.00,50.00) startOffset 0 endOffset 1 width 12.00: "A"
     46          RenderSVGTSpan {tspan} at (0,0) size 11x18
     47            RenderSVGInlineText {#text} at (50,0) size 11x18
     48              chunk 1 text run 1 at (100.00,50.00) startOffset 0 endOffset 1 width 11.00: "B"
     49          RenderSVGInlineText {#text} at (100,0) size 15x18
     50            chunk 1 text run 1 at (150.00,50.00) startOffset 0 endOffset 2 width 15.00: " C"
     51
     52        Its obvious that adding a #text node as child to the <tspan> potentially affects the next & previous
     53        siblings in the DOM tree. Take extra care of these possibilities, by properly remeasuring not only
     54        the newly added renderer, but also the previous & next siblings layout attributes.
     55
     56        Mutation of text nodes, or removal of text/tspan elements from the tree is handled in the same way.
     57
     58        #3) Measuring the text subtree:
     59        Don't cache the metrics information in the SVGRootInlineBox, as it doesn't survive relayouts (RenderSVGText::layout).
     60        They're stored in the SVGTextLayoutAttributes, and will be updated if the underlying text content changes.
     61
     62        Tests: svg/text/append-text-node-to-tspan.html
     63               svg/text/modify-text-node-in-tspan.html
     64               svg/text/remove-text-node-from-tspan.html
     65
     66        * rendering/svg/RenderSVGInline.cpp:
     67        (WebCore::RenderSVGInline::addChild):
     68        * rendering/svg/RenderSVGInline.h:
     69        * rendering/svg/RenderSVGInlineText.cpp:
     70        (WebCore::RenderSVGInlineText::willBeDestroyed):
     71        (WebCore::RenderSVGInlineText::setTextInternal):
     72        (WebCore::RenderSVGInlineText::styleDidChange):
     73        * rendering/svg/RenderSVGInlineText.h:
     74        (WebCore::RenderSVGInlineText::layoutAttributes):
     75        * rendering/svg/RenderSVGText.cpp:
     76        (WebCore::recursiveUpdateLayoutAttributes):
     77        (WebCore::RenderSVGText::layoutAttributesChanged):
     78        (WebCore::findPreviousAndNextAttributes):
     79        (WebCore::RenderSVGText::layoutAttributesWillBeDestroyed):
     80        (WebCore::RenderSVGText::textDOMChanged):
     81        (WebCore::RenderSVGText::layout):
     82        (WebCore::RenderSVGText::addChild):
     83        (WebCore::recursiveCollectLayoutAttributes):
     84        (WebCore::RenderSVGText::rebuildLayoutAttributes):
     85        * rendering/svg/RenderSVGText.h:
     86        (WebCore::RenderSVGText::layoutAttributes):
     87        * rendering/svg/SVGRootInlineBox.cpp:
     88        (WebCore::SVGRootInlineBox::computePerCharacterLayoutInformation):
     89        (WebCore::findFirstAndLastAttributesInVector):
     90        (WebCore::reverseInlineBoxRangeAndValueListsIfNeeded):
     91        (WebCore::SVGRootInlineBox::reorderValueLists):
     92        * rendering/svg/SVGRootInlineBox.h:
     93        * rendering/svg/SVGTextLayoutAttributes.h:
     94        * rendering/svg/SVGTextLayoutAttributesBuilder.cpp:
     95        (WebCore::SVGTextLayoutAttributesBuilder::rebuildMetricsForWholeTree):
     96        * rendering/svg/SVGTextLayoutEngine.cpp:
     97        (WebCore::SVGTextLayoutEngine::SVGTextLayoutEngine):
     98        (WebCore::SVGTextLayoutEngine::currentLogicalCharacterAttributes):
     99        (WebCore::SVGTextLayoutEngine::currentLogicalCharacterMetrics):
     100        (WebCore::SVGTextLayoutEngine::currentVisualCharacterMetrics):
     101        (WebCore::SVGTextLayoutEngine::layoutTextOnLineOrPath):
     102        * rendering/svg/SVGTextLayoutEngine.h:
     103        (WebCore::SVGTextLayoutEngine::layoutAttributes):
     104        * rendering/svg/SVGTextMetrics.h:
     105        * rendering/svg/SVGTextMetricsBuilder.cpp:
     106        (WebCore::SVGTextMetricsBuilder::measureTextRenderer):
     107        * rendering/svg/SVGTextQuery.cpp:
     108        (WebCore::SVGTextQuery::modifyStartEndPositionsRespectingLigatures):
     109        * svg/SVGTextContentElement.cpp:
     110        (WebCore::SVGTextContentElement::childrenChanged):
     111
    11122012-01-11  Alexander Pavlov  <apavlov@chromium.org>
    2113
  • trunk/Source/WebCore/rendering/svg/RenderSVGInline.cpp

    r101342 r105143  
    2525#include "RenderSVGInline.h"
    2626
     27#include "RenderSVGInlineText.h"
    2728#include "RenderSVGResource.h"
    2829#include "RenderSVGText.h"
     
    9596}
    9697
    97 void RenderSVGInline::willBeDestroyed()
    98 {
    99     if (RenderSVGText* textRenderer = RenderSVGText::locateRenderSVGTextAncestor(this))
    100         textRenderer->setNeedsPositioningValuesUpdate();
    101 
    102     SVGResourcesCache::clientDestroyed(this);
    103     RenderInline::willBeDestroyed();
    104 }
    105 
    10698void RenderSVGInline::styleWillChange(StyleDifference diff, const RenderStyle* newStyle)
    10799{
     
    123115}
    124116
     117void RenderSVGInline::addChild(RenderObject* child, RenderObject* beforeChild)
     118{
     119    RenderInline::addChild(child, beforeChild);
     120    if (RenderSVGText* textRenderer = RenderSVGText::locateRenderSVGTextAncestor(this))
     121        textRenderer->layoutAttributesChanged(child);
     122}
    125123
    126124}
  • trunk/Source/WebCore/rendering/svg/RenderSVGInline.h

    r101342 r105143  
    5454    virtual InlineFlowBox* createInlineFlowBox();
    5555
    56     virtual void willBeDestroyed();
    5756    virtual void styleWillChange(StyleDifference, const RenderStyle* newStyle);
    5857    virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle);
    5958    virtual void updateFromElement();
     59    virtual void addChild(RenderObject* child, RenderObject* beforeChild = 0);
    6060};
    6161
  • trunk/Source/WebCore/rendering/svg/RenderSVGInlineText.cpp

    r105057 r105143  
    7575void RenderSVGInlineText::willBeDestroyed()
    7676{
     77    RenderSVGText* textRenderer = RenderSVGText::locateRenderSVGTextAncestor(this);
     78    if (!textRenderer) {
     79        RenderText::willBeDestroyed();
     80        return;
     81    }
     82
     83    Vector<SVGTextLayoutAttributes*> affectedAttributes;
     84    textRenderer->layoutAttributesWillBeDestroyed(this, affectedAttributes);
     85
     86    RenderText::willBeDestroyed();
     87    if (affectedAttributes.isEmpty())
     88        return;
     89
     90    textRenderer->rebuildLayoutAttributes(affectedAttributes);
     91}
     92
     93void RenderSVGInlineText::setTextInternal(PassRefPtr<StringImpl> text)
     94{
     95    RenderText::setTextInternal(text);
     96
     97    // When the underlying text content changes, call both textDOMChanged() & layoutAttributesChanged()
     98    // The former will clear the SVGTextPositioningElement cache, which depends on the textLength() of
     99    // the RenderSVGInlineText objects, and thus needs to be rebuild. The latter will assure that the
     100    // SVGTextLayoutAttributes associated with the RenderSVGInlineText will be updated.
     101    if (RenderSVGText* textRenderer = RenderSVGText::locateRenderSVGTextAncestor(this)) {
     102        textRenderer->textDOMChanged();
     103        textRenderer->layoutAttributesChanged(this);
     104    }
     105}
     106
     107void RenderSVGInlineText::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
     108{
     109    RenderText::styleDidChange(diff, oldStyle);
     110    updateScaledFont();
     111
     112    bool newPreserves = style() ? style()->whiteSpace() == PRE : false;
     113    bool oldPreserves = oldStyle ? oldStyle->whiteSpace() == PRE : false;
     114    if (oldPreserves && !newPreserves) {
     115        setText(applySVGWhitespaceRules(originalText(), false), true);
     116        return;
     117    }
     118
     119    if (!oldPreserves && newPreserves) {
     120        setText(applySVGWhitespaceRules(originalText(), true), true);
     121        return;
     122    }
     123
     124    if (diff != StyleDifferenceLayout)
     125        return;
     126
     127    // The text metrics may be influenced by style changes.
    77128    if (RenderSVGText* textRenderer = RenderSVGText::locateRenderSVGTextAncestor(this))
    78         textRenderer->setNeedsPositioningValuesUpdate();
    79 
    80     RenderText::willBeDestroyed();
    81 }
    82 
    83 void RenderSVGInlineText::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
    84 {
    85     RenderText::styleDidChange(diff, oldStyle);
    86 
    87     if (diff == StyleDifferenceLayout) {
    88         // The text metrics may be influenced by style changes.
    89         if (RenderSVGText* textRenderer = RenderSVGText::locateRenderSVGTextAncestor(this))
    90             textRenderer->setNeedsPositioningValuesUpdate();
    91     }
    92 
    93     const RenderStyle* newStyle = style();
    94     if (!newStyle || newStyle->whiteSpace() != PRE)
    95         return;
    96 
    97     if (!oldStyle || oldStyle->whiteSpace() != PRE)
    98         setText(applySVGWhitespaceRules(originalText(), true), true);
     129        textRenderer->layoutAttributesChanged(this);
    99130}
    100131
     
    210241}
    211242
    212 void RenderSVGInlineText::setStyle(PassRefPtr<RenderStyle> style)
    213 {
    214     RenderText::setStyle(style);
    215 
    216     // The cached scaledFont needs to be updated on every style set call. It
    217     // is not similar to m_style which can get derived from parent's style and
    218     // hence will get automatically updated on ancestor's style change. This is
    219     // required, otherwise we will maintain stale font list in cached scaledFont
    220     // when custom fonts are retired on Document::recalcStyle. See webkit bug
    221     // https://bugs.webkit.org/show_bug.cgi?id=68060.
    222     updateScaledFont();
    223 }
    224 
    225243void RenderSVGInlineText::updateScaledFont()
    226244{
  • trunk/Source/WebCore/rendering/svg/RenderSVGInlineText.h

    r105057 r105143  
    3636
    3737    bool characterStartsNewTextChunk(int position) const;
    38     SVGTextLayoutAttributes& layoutAttributes() { return m_layoutAttributes; }
     38    SVGTextLayoutAttributes* layoutAttributes() { return &m_layoutAttributes; }
    3939
    4040    float scalingFactor() const { return m_scalingFactor; }
     
    5050
    5151    virtual void willBeDestroyed();
    52    
    53     virtual void setStyle(PassRefPtr<RenderStyle>);
     52    virtual void setTextInternal(PassRefPtr<StringImpl>);
    5453    virtual void styleDidChange(StyleDifference, const RenderStyle*);
    5554
  • trunk/Source/WebCore/rendering/svg/RenderSVGText.cpp

    r105057 r105143  
    3131#include "FloatConversion.h"
    3232#include "FloatQuad.h"
     33#include "FontCache.h"
    3334#include "GraphicsContext.h"
    3435#include "HitTestRequest.h"
     
    108109}
    109110
     111static inline void recursiveUpdateLayoutAttributes(RenderObject* start, SVGTextLayoutAttributesBuilder& builder)
     112{
     113    if (start->isSVGInlineText()) {
     114        builder.buildLayoutAttributesForTextRenderer(toRenderSVGInlineText(start));
     115        return;
     116    }
     117
     118    for (RenderObject* child = start->firstChild(); child; child = child->nextSibling())
     119        recursiveUpdateLayoutAttributes(child, builder);
     120}
     121
     122void RenderSVGText::layoutAttributesChanged(RenderObject* child)
     123{
     124    ASSERT(child);
     125    if (m_needsPositioningValuesUpdate)
     126        return;
     127    FontCachePurgePreventer fontCachePurgePreventer;
     128    recursiveUpdateLayoutAttributes(child, m_layoutAttributesBuilder);
     129    rebuildLayoutAttributes();
     130}
     131
     132static inline bool findPreviousAndNextAttributes(RenderObject* start, RenderSVGInlineText* locateElement, bool& stopAfterNext, SVGTextLayoutAttributes*& previous, SVGTextLayoutAttributes*& next)
     133{
     134    ASSERT(start);
     135    ASSERT(locateElement);
     136    for (RenderObject* child = start->firstChild(); child; child = child->nextSibling()) {
     137        if (child->isSVGInlineText()) {
     138            RenderSVGInlineText* text = toRenderSVGInlineText(child);
     139            if (locateElement != text) {
     140                if (stopAfterNext) {
     141                    next = text->layoutAttributes();
     142                    return true;
     143                }
     144
     145                previous = text->layoutAttributes();
     146                continue;
     147            }
     148
     149            stopAfterNext = true;
     150            continue;
     151        }
     152
     153        if (!child->isSVGInline())
     154            continue;
     155
     156        if (findPreviousAndNextAttributes(child, locateElement, stopAfterNext, previous, next))
     157            return true;
     158    }
     159
     160    return false;
     161}
     162
     163void RenderSVGText::layoutAttributesWillBeDestroyed(RenderSVGInlineText* text, Vector<SVGTextLayoutAttributes*>& affectedAttributes)
     164{
     165    ASSERT(text);
     166    if (m_needsPositioningValuesUpdate)
     167        return;
     168
     169    bool stopAfterNext = false;
     170    SVGTextLayoutAttributes* previous = 0;
     171    SVGTextLayoutAttributes* next = 0;
     172    findPreviousAndNextAttributes(this, text, stopAfterNext, previous, next);
     173    if (previous)
     174        affectedAttributes.append(previous);
     175    if (next)
     176        affectedAttributes.append(next);
     177}
     178
     179void RenderSVGText::textDOMChanged()
     180{
     181    if (m_needsPositioningValuesUpdate)
     182        return;
     183    m_layoutAttributesBuilder.clearTextPositioningElements();
     184}
     185
    110186static inline void recursiveUpdateScaledFont(RenderObject* start)
    111187{
     
    134210
    135211    // If the root layout size changed (eg. window size changes) or the positioning values change, recompute the on-screen font size.
    136     if (m_needsPositioningValuesUpdate || SVGRenderSupport::findTreeRootObject(this)->isLayoutSizeChanged()) {
     212    if (SVGRenderSupport::findTreeRootObject(this)->isLayoutSizeChanged()) {
    137213        recursiveUpdateScaledFont(this);
    138         m_needsPositioningValuesUpdate = true;
     214        rebuildLayoutAttributes(true);
    139215        updateCachedBoundariesInParents = true;
    140216    }
     
    280356}
    281357
     358void RenderSVGText::addChild(RenderObject* child, RenderObject* beforeChild)
     359{
     360    RenderSVGBlock::addChild(child, beforeChild);
     361    layoutAttributesChanged(child);
     362}
     363
    282364// Fix for <rdar://problem/8048875>. We should not render :first-line CSS Style
    283365// in a SVG text element context.
     
    293375}
    294376
    295 static inline void recursiveCollectLayoutAttributes(RenderObject* start, Vector<SVGTextLayoutAttributes>& attributes)
     377static inline void recursiveCollectLayoutAttributes(RenderObject* start, Vector<SVGTextLayoutAttributes*>& attributes)
    296378{
    297379    for (RenderObject* child = start->firstChild(); child; child = child->nextSibling()) {
     
    307389void RenderSVGText::rebuildLayoutAttributes(bool performFullRebuild)
    308390{
    309     // FIXME: For now we always rebuild the whole tree, as it used to be.
    310     performFullRebuild = true;
    311391    if (performFullRebuild)
    312392        m_layoutAttributes.clear();
     
    321401    }
    322402
    323     /* FIXME: Enable this once we rebuild subtrees, instead of the full tree
    324403    Vector<SVGTextLayoutAttributes*> affectedAttributes;
    325404    rebuildLayoutAttributes(affectedAttributes);
    326     */
     405}
     406
     407void RenderSVGText::rebuildLayoutAttributes(Vector<SVGTextLayoutAttributes*>& affectedAttributes)
     408{
     409    // Detect changes in layout attributes and only measure those text parts that have changed!
     410    Vector<SVGTextLayoutAttributes*> newLayoutAttributes;
     411    recursiveCollectLayoutAttributes(this, newLayoutAttributes);
     412    if (newLayoutAttributes.isEmpty()) {
     413        m_layoutAttributes.clear();
     414        return;
     415    }
     416
     417    // Compare m_layoutAttributes with newLayoutAttributes to figure out which attributes got added/removed.
     418    size_t size = newLayoutAttributes.size();
     419    for (size_t i = 0; i < size; ++i) {
     420        SVGTextLayoutAttributes* attributes = newLayoutAttributes[i];
     421        if (m_layoutAttributes.find(attributes) == notFound)
     422            m_layoutAttributesBuilder.rebuildMetricsForTextRenderer(attributes->context());
     423    }
     424
     425    size = affectedAttributes.size();
     426    for (size_t i = 0; i < size; ++i)
     427        m_layoutAttributesBuilder.rebuildMetricsForTextRenderer(affectedAttributes[i]->context());
     428
     429    m_layoutAttributes = newLayoutAttributes;
    327430}
    328431
  • trunk/Source/WebCore/rendering/svg/RenderSVGText.h

    r105057 r105143  
    2424
    2525#if ENABLE(SVG)
    26 
    2726#include "AffineTransform.h"
    2827#include "RenderSVGBlock.h"
     
    3332class RenderSVGInlineText;
    3433class SVGTextElement;
     34class RenderSVGInlineText;
    3535
    3636class RenderSVGText : public RenderSVGBlock {
     
    4747    static const RenderSVGText* locateRenderSVGTextAncestor(const RenderObject*);
    4848
    49     Vector<SVGTextLayoutAttributes>& layoutAttributes() { return m_layoutAttributes; }
    5049    bool needsReordering() const { return m_needsReordering; }
    5150
     51    void textDOMChanged();
     52    void layoutAttributesChanged(RenderObject*);
     53    void layoutAttributesWillBeDestroyed(RenderSVGInlineText*, Vector<SVGTextLayoutAttributes*>& affectedAttributes);
    5254    void rebuildLayoutAttributes(bool performFullRebuild = false);
     55    void rebuildLayoutAttributes(Vector<SVGTextLayoutAttributes*>& affectedAttributes);
     56
     57    Vector<SVGTextLayoutAttributes*>& layoutAttributes() { return m_layoutAttributes; }
    5358
    5459private:
     
    7176
    7277    virtual void mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool useTransforms, bool fixed, TransformState&, bool* wasFixed = 0) const;
     78    virtual void addChild(RenderObject* child, RenderObject* beforeChild = 0);
    7379
    7480    virtual FloatRect objectBoundingBox() const { return frameRect(); }
     
    8793    AffineTransform m_localTransform;
    8894    SVGTextLayoutAttributesBuilder m_layoutAttributesBuilder;
    89     Vector<SVGTextLayoutAttributes> m_layoutAttributes;
     95    Vector<SVGTextLayoutAttributes*> m_layoutAttributes;
    9096};
    9197
  • trunk/Source/WebCore/rendering/svg/SVGRootInlineBox.cpp

    r105057 r105143  
    7878
    7979    textRoot->rebuildLayoutAttributes();
    80     Vector<SVGTextLayoutAttributes>& layoutAttributes = textRoot->layoutAttributes();
     80    Vector<SVGTextLayoutAttributes*>& layoutAttributes = textRoot->layoutAttributes();
    8181    if (layoutAttributes.isEmpty())
    8282        return;
     
    244244}
    245245
    246 static inline void findFirstAndLastAttributesInVector(Vector<SVGTextLayoutAttributes>& attributes, RenderSVGInlineText* firstContext, RenderSVGInlineText* lastContext,
     246static inline void findFirstAndLastAttributesInVector(Vector<SVGTextLayoutAttributes*>& attributes, RenderSVGInlineText* firstContext, RenderSVGInlineText* lastContext,
    247247                                                      SVGTextLayoutAttributes*& first, SVGTextLayoutAttributes*& last)
    248248{
     
    252252    unsigned attributesSize = attributes.size();
    253253    for (unsigned i = 0; i < attributesSize; ++i) {
    254         SVGTextLayoutAttributes& current = attributes[i];
    255         if (!first && firstContext == current.context())
    256             first = &current;
    257         if (!last && lastContext == current.context())
    258             last = &current;
     254        SVGTextLayoutAttributes* current = attributes[i];
     255        if (!first && firstContext == current->context())
     256            first = current;
     257        if (!last && lastContext == current->context())
     258            last = current;
    259259        if (first && last)
    260260            break;
     
    268268{
    269269    ASSERT(userData);
    270     Vector<SVGTextLayoutAttributes>& attributes = *reinterpret_cast<Vector<SVGTextLayoutAttributes>*>(userData);
     270    Vector<SVGTextLayoutAttributes*>& attributes = *reinterpret_cast<Vector<SVGTextLayoutAttributes*>*>(userData);
    271271
    272272    // This is a copy of std::reverse(first, last). It additionally assures that the metrics map within the renderers belonging to the InlineBoxes are reordered as well.
     
    305305}
    306306
    307 void SVGRootInlineBox::reorderValueLists(Vector<SVGTextLayoutAttributes>& attributes)
     307void SVGRootInlineBox::reorderValueLists(Vector<SVGTextLayoutAttributes*>& attributes)
    308308{
    309309    Vector<InlineBox*> leafBoxesInLogicalOrder;
  • trunk/Source/WebCore/rendering/svg/SVGRootInlineBox.h

    r101342 r105143  
    5656
    5757private:
    58     void reorderValueLists(Vector<SVGTextLayoutAttributes>&);
     58    void reorderValueLists(Vector<SVGTextLayoutAttributes*>&);
    5959    void layoutCharactersInTextBoxes(InlineFlowBox*, SVGTextLayoutEngine&);
    6060    void layoutChildBoxes(InlineFlowBox*, FloatRect* = 0);
  • trunk/Source/WebCore/rendering/svg/SVGTextLayoutAttributes.h

    r105057 r105143  
    2323#if ENABLE(SVG)
    2424#include "SVGTextMetrics.h"
     25#include <wtf/HashMap.h>
     26#include <wtf/Noncopyable.h>
    2527#include <wtf/Vector.h>
    2628#include <wtf/text/WTFString.h>
     
    4345
    4446class SVGTextLayoutAttributes {
     47    WTF_MAKE_NONCOPYABLE(SVGTextLayoutAttributes);
    4548public:
    4649    SVGTextLayoutAttributes(RenderSVGInlineText*);
  • trunk/Source/WebCore/rendering/svg/SVGTextLayoutAttributesBuilder.cpp

    r105057 r105143  
    7070{
    7171    ASSERT(textRoot);
    72     Vector<SVGTextLayoutAttributes>& layoutAttributes = textRoot->layoutAttributes();
     72    Vector<SVGTextLayoutAttributes*>& layoutAttributes = textRoot->layoutAttributes();
    7373
    7474    size_t layoutAttributesSize = layoutAttributes.size();
    7575    for (size_t i = 0; i < layoutAttributesSize; ++i)
    76         m_metricsBuilder.measureTextRenderer(layoutAttributes[i].context());
     76        m_metricsBuilder.measureTextRenderer(layoutAttributes[i]->context());
    7777}
    7878
  • trunk/Source/WebCore/rendering/svg/SVGTextLayoutEngine.cpp

    r105057 r105143  
    3636namespace WebCore {
    3737
    38 SVGTextLayoutEngine::SVGTextLayoutEngine(Vector<SVGTextLayoutAttributes>& layoutAttributes)
     38SVGTextLayoutEngine::SVGTextLayoutEngine(Vector<SVGTextLayoutAttributes*>& layoutAttributes)
    3939    : m_layoutAttributes(layoutAttributes)
     40    , m_layoutAttributesPosition(0)
    4041    , m_logicalCharacterOffset(0)
    4142    , m_logicalMetricsListOffset(0)
     
    330331}
    331332
    332 bool SVGTextLayoutEngine::currentLogicalCharacterAttributes(SVGTextLayoutAttributes& logicalAttributes)
    333 {
    334     if (m_layoutAttributes.isEmpty())
     333bool SVGTextLayoutEngine::currentLogicalCharacterAttributes(SVGTextLayoutAttributes*& logicalAttributes)
     334{
     335    if (m_layoutAttributesPosition == m_layoutAttributes.size())
    335336        return false;
    336337
    337     logicalAttributes = m_layoutAttributes.first();
    338     if (m_logicalCharacterOffset != logicalAttributes.context()->textLength())
     338    logicalAttributes = m_layoutAttributes[m_layoutAttributesPosition];
     339    ASSERT(logicalAttributes);
     340
     341    if (m_logicalCharacterOffset != logicalAttributes->context()->textLength())
    339342        return true;
    340343
    341     m_layoutAttributes.remove(0);
    342     if (m_layoutAttributes.isEmpty())
     344    ++m_layoutAttributesPosition;
     345    if (m_layoutAttributesPosition == m_layoutAttributes.size())
    343346        return false;
    344347
    345     logicalAttributes = m_layoutAttributes.first();
     348    logicalAttributes = m_layoutAttributes[m_layoutAttributesPosition];
    346349    m_logicalMetricsListOffset = 0;
    347350    m_logicalCharacterOffset = 0;
     
    349352}
    350353
    351 bool SVGTextLayoutEngine::currentLogicalCharacterMetrics(SVGTextLayoutAttributes& logicalAttributes, SVGTextMetrics& logicalMetrics)
    352 {
    353     logicalMetrics = SVGTextMetrics(SVGTextMetrics::SkippedSpaceMetrics);
    354     Vector<SVGTextMetrics>& textMetricsValues = logicalAttributes.textMetricsValues();
    355     unsigned textMetricsSize = textMetricsValues.size();
     354bool SVGTextLayoutEngine::currentLogicalCharacterMetrics(SVGTextLayoutAttributes*& logicalAttributes, SVGTextMetrics& logicalMetrics)
     355{
     356    Vector<SVGTextMetrics>* textMetricsValues = &logicalAttributes->textMetricsValues();
     357    unsigned textMetricsSize = textMetricsValues->size();
    356358    while (true) {
    357359        if (m_logicalMetricsListOffset == textMetricsSize) {
     
    359361                return false;
    360362
    361             textMetricsValues = logicalAttributes.textMetricsValues();
    362             textMetricsSize = textMetricsValues.size();
     363            textMetricsValues = &logicalAttributes->textMetricsValues();
     364            textMetricsSize = textMetricsValues->size();
    363365            continue;
    364366        }
     
    366368        ASSERT(textMetricsSize);
    367369        ASSERT(m_logicalMetricsListOffset < textMetricsSize);
    368         logicalMetrics = textMetricsValues.at(m_logicalMetricsListOffset);
     370        logicalMetrics = textMetricsValues->at(m_logicalMetricsListOffset);
    369371        if (logicalMetrics.isEmpty() || (!logicalMetrics.width() && !logicalMetrics.height())) {
    370372            advanceToNextLogicalCharacter(logicalMetrics);
     
    380382}
    381383
    382 bool SVGTextLayoutEngine::currentVisualCharacterMetrics(SVGInlineTextBox* textBox, RenderSVGInlineText* text, SVGTextMetrics& metrics)
    383 {
    384     SVGTextLayoutAttributes& attributes = text->layoutAttributes();
    385     Vector<SVGTextMetrics>& textMetricsValues = attributes.textMetricsValues();
    386     ASSERT(!textMetricsValues.isEmpty());
    387 
    388     unsigned textMetricsSize = textMetricsValues.size();
     384bool SVGTextLayoutEngine::currentVisualCharacterMetrics(SVGInlineTextBox* textBox, Vector<SVGTextMetrics>& visualMetricsValues, SVGTextMetrics& visualMetrics)
     385{
     386    ASSERT(!visualMetricsValues.isEmpty());
     387    unsigned textMetricsSize = visualMetricsValues.size();
    389388    unsigned boxStart = textBox->start();
    390389    unsigned boxLength = textBox->len();
     
    394393
    395394    while (m_visualMetricsListOffset < textMetricsSize) {
    396         SVGTextMetrics& visualMetrics = textMetricsValues.at(m_visualMetricsListOffset);
    397 
    398395        // Advance to text box start location.
    399396        if (m_visualCharacterOffset < boxStart) {
    400             advanceToNextVisualCharacter(visualMetrics);
     397            advanceToNextVisualCharacter(visualMetricsValues[m_visualMetricsListOffset]);
    401398            continue;
    402399        }
     
    406403            return false;
    407404
    408         metrics = visualMetrics;
     405        visualMetrics = visualMetricsValues[m_visualMetricsListOffset];
    409406        return true;
    410407    }
     
    438435    m_visualCharacterOffset = 0;
    439436
    440     Vector<SVGTextMetrics>& textMetricsValues = text->layoutAttributes().textMetricsValues();
     437    Vector<SVGTextMetrics>& visualMetricsValues = text->layoutAttributes()->textMetricsValues();
     438    ASSERT(!visualMetricsValues.isEmpty());
     439
    441440    const UChar* characters = text->characters();
    442 
    443441    const Font& font = style->font();
     442
    444443    SVGTextLayoutEngineSpacing spacingLayout(font);
    445444    SVGTextLayoutEngineBaseline baselineLayout(font);
     
    456455        // Find the start of the current text box in this list, respecting ligatures.
    457456        SVGTextMetrics visualMetrics(SVGTextMetrics::SkippedSpaceMetrics);
    458         if (!currentVisualCharacterMetrics(textBox, text, visualMetrics))
     457        if (!currentVisualCharacterMetrics(textBox, visualMetricsValues, visualMetrics))
    459458            break;
    460459
     
    464463        }
    465464
    466         SVGTextLayoutAttributes logicalAttributes(0);
     465        SVGTextLayoutAttributes* logicalAttributes = 0;
    467466        if (!currentLogicalCharacterAttributes(logicalAttributes))
    468467            break;
    469468
     469        ASSERT(logicalAttributes);
    470470        SVGTextMetrics logicalMetrics(SVGTextMetrics::SkippedSpaceMetrics);
    471471        if (!currentLogicalCharacterMetrics(logicalAttributes, logicalMetrics))
    472472            break;
    473473
    474         SVGCharacterDataMap& characterDataMap = logicalAttributes.characterDataMap();
     474        SVGCharacterDataMap& characterDataMap = logicalAttributes->characterDataMap();
    475475        SVGCharacterData data;
    476476        SVGCharacterDataMap::iterator it = characterDataMap.find(m_logicalCharacterOffset + 1);
     
    484484        // whether this character starts a new text chunk, before doing any further processing.
    485485        if (m_visualCharacterOffset == textBox->start())
    486             textBox->setStartsNewTextChunk(logicalAttributes.context()->characterStartsNewTextChunk(m_logicalCharacterOffset));
     486            textBox->setStartsNewTextChunk(logicalAttributes->context()->characterStartsNewTextChunk(m_logicalCharacterOffset));
    487487
    488488        float angle = data.rotate == SVGTextLayoutAttributes::emptyValue() ? 0 : data.rotate;
     
    597597        if (didStartTextFragment && shouldStartNewFragment) {
    598598            applySpacingToNextCharacter = false;
    599             recordTextFragment(textBox, textMetricsValues);
     599            recordTextFragment(textBox, visualMetricsValues);
    600600        }
    601601
     
    658658
    659659    // Close last open fragment, if needed.
    660     recordTextFragment(textBox, textMetricsValues);
     660    recordTextFragment(textBox, visualMetricsValues);
    661661}
    662662
  • trunk/Source/WebCore/rendering/svg/SVGTextLayoutEngine.h

    r105057 r105143  
    4949    WTF_MAKE_NONCOPYABLE(SVGTextLayoutEngine);
    5050public:
    51     SVGTextLayoutEngine(Vector<SVGTextLayoutAttributes>&);
     51    SVGTextLayoutEngine(Vector<SVGTextLayoutAttributes*>&);
     52
     53    Vector<SVGTextLayoutAttributes*>& layoutAttributes() { return m_layoutAttributes; }
    5254    SVGTextChunkBuilder& chunkLayoutBuilder() { return m_chunkLayoutBuilder; }
    5355
     
    5860    void finishLayout();
    5961
    60     Vector<SVGTextLayoutAttributes>& layoutAttributes() { return m_layoutAttributes; }
    61 
    6262private:
    6363    void updateCharacerPositionIfNeeded(float& x, float& y);
     
    6565    void updateRelativePositionAdjustmentsIfNeeded(float dx, float dy);
    6666
    67     void recordTextFragment(SVGInlineTextBox*, Vector<SVGTextMetrics>& textMetricValues);
     67    void recordTextFragment(SVGInlineTextBox*, Vector<SVGTextMetrics>&);
    6868    bool parentDefinesTextLength(RenderObject*) const;
    6969
     
    7171    void finalizeTransformMatrices(Vector<SVGInlineTextBox*>&);
    7272
    73     bool currentLogicalCharacterAttributes(SVGTextLayoutAttributes&);
    74     bool currentLogicalCharacterMetrics(SVGTextLayoutAttributes&, SVGTextMetrics&);
    75     bool currentVisualCharacterMetrics(SVGInlineTextBox*, RenderSVGInlineText*, SVGTextMetrics&);
     73    bool currentLogicalCharacterAttributes(SVGTextLayoutAttributes*&);
     74    bool currentLogicalCharacterMetrics(SVGTextLayoutAttributes*&, SVGTextMetrics&);
     75    bool currentVisualCharacterMetrics(SVGInlineTextBox*, Vector<SVGTextMetrics>&, SVGTextMetrics&);
    7676
    7777    void advanceToNextLogicalCharacter(const SVGTextMetrics&);
     
    7979
    8080private:
    81     Vector<SVGTextLayoutAttributes> m_layoutAttributes;
     81    Vector<SVGTextLayoutAttributes*>& m_layoutAttributes;
     82
    8283    Vector<SVGInlineTextBox*> m_lineLayoutBoxes;
    8384    Vector<SVGInlineTextBox*> m_pathLayoutBoxes;
     
    8586
    8687    SVGTextFragment m_currentTextFragment;
     88    unsigned m_layoutAttributesPosition;
    8789    unsigned m_logicalCharacterOffset;
    8890    unsigned m_logicalMetricsListOffset;
  • trunk/Source/WebCore/rendering/svg/SVGTextMetrics.h

    r104683 r105143  
    2222
    2323#if ENABLE(SVG)
    24 #include <wtf/HashMap.h>
    25 #include <wtf/PassOwnPtr.h>
    2624#include <wtf/text/WTFString.h>
    2725
  • trunk/Source/WebCore/rendering/svg/SVGTextMetricsBuilder.cpp

    r105061 r105143  
    145145    ASSERT(text);
    146146
    147     SVGTextLayoutAttributes* attributes = &text->layoutAttributes();
     147    SVGTextLayoutAttributes* attributes = text->layoutAttributes();
    148148    Vector<SVGTextMetrics>* textMetricsValues = &attributes->textMetricsValues();
    149149    if (data->processRenderer) {
  • trunk/Source/WebCore/rendering/svg/SVGTextQuery.cpp

    r105057 r105143  
    159159void SVGTextQuery::modifyStartEndPositionsRespectingLigatures(Data* queryData, int& startPosition, int& endPosition) const
    160160{
    161     SVGTextLayoutAttributes& layoutAttributes = queryData->textRenderer->layoutAttributes();
    162     Vector<SVGTextMetrics>& textMetricsValues = layoutAttributes.textMetricsValues();
     161    SVGTextLayoutAttributes* layoutAttributes = queryData->textRenderer->layoutAttributes();
     162    Vector<SVGTextMetrics>& textMetricsValues = layoutAttributes->textMetricsValues();
    163163    unsigned boxStart = queryData->textBox->start();
    164164    unsigned boxLength = queryData->textBox->len();
     
    168168
    169169    unsigned positionOffset = 0;
    170     unsigned positionSize = layoutAttributes.context()->textLength();
     170    unsigned positionSize = layoutAttributes->context()->textLength();
    171171
    172172    bool alterStartPosition = true;
  • trunk/Source/WebCore/svg/SVGTextContentElement.cpp

    r96307 r105143  
    316316        return;
    317317
     318    // Invalidate the TextPosition cache in SVGTextLayoutAttributesBuilder as it may now point
     319    // to no-longer existing SVGTextPositioningElements and thus needs to be rebuild.
    318320    if (RenderSVGText* textRenderer = RenderSVGText::locateRenderSVGTextAncestor(renderer()))
    319         textRenderer->setNeedsPositioningValuesUpdate();
     321        textRenderer->textDOMChanged();
    320322}
    321323
Note: See TracChangeset for help on using the changeset viewer.