Large SVG text layout performance regression in r81168
authorzimmermann@webkit.org <zimmermann@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 17 Jan 2012 12:42:25 +0000 (12:42 +0000)
committerzimmermann@webkit.org <zimmermann@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 17 Jan 2012 12:42:25 +0000 (12:42 +0000)
commitd7e9e059e9d70a5f6d65836ea23d03e78ae65e95
tree425a6e7217624161b7dd980dfa62d9e99b830746
parentd3e9467c4f5ad259d4ddd3c60dc7d921e6a87db6
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.

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@105143 268f45cc-cd09-0410-ab3c-d52691b4dbfc
41 files changed:
LayoutTests/ChangeLog
LayoutTests/platform/chromium/test_expectations.txt
LayoutTests/platform/mac/svg/carto.net/window-expected.png
LayoutTests/platform/mac/svg/carto.net/window-expected.txt
LayoutTests/platform/mac/svg/custom/js-late-clipPath-and-object-creation-expected.png
LayoutTests/platform/mac/svg/custom/js-late-clipPath-and-object-creation-expected.txt
LayoutTests/platform/mac/svg/custom/js-late-gradient-and-object-creation-expected.png
LayoutTests/platform/mac/svg/custom/js-late-gradient-and-object-creation-expected.txt
LayoutTests/platform/mac/svg/custom/js-late-pattern-and-object-creation-expected.png
LayoutTests/platform/mac/svg/custom/js-late-pattern-and-object-creation-expected.txt
LayoutTests/platform/mac/svg/custom/use-detach-expected.png
LayoutTests/platform/mac/svg/custom/use-detach-expected.txt
LayoutTests/platform/mac/svg/text/append-text-node-to-tspan-expected.png [new file with mode: 0644]
LayoutTests/platform/mac/svg/text/append-text-node-to-tspan-expected.txt [new file with mode: 0644]
LayoutTests/platform/mac/svg/text/modify-text-node-in-tspan-expected.png [new file with mode: 0644]
LayoutTests/platform/mac/svg/text/modify-text-node-in-tspan-expected.txt [new file with mode: 0644]
LayoutTests/platform/mac/svg/text/remove-text-node-from-tspan-expected.png [new file with mode: 0644]
LayoutTests/platform/mac/svg/text/remove-text-node-from-tspan-expected.txt [new file with mode: 0644]
LayoutTests/platform/mac/svg/text/remove-tspan-from-text-expected.png [new file with mode: 0644]
LayoutTests/platform/mac/svg/text/remove-tspan-from-text-expected.txt [new file with mode: 0644]
LayoutTests/svg/text/append-text-node-to-tspan.html [new file with mode: 0644]
LayoutTests/svg/text/modify-text-node-in-tspan.html [new file with mode: 0644]
LayoutTests/svg/text/remove-text-node-from-tspan.html [new file with mode: 0644]
LayoutTests/svg/text/remove-tspan-from-text.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/rendering/svg/RenderSVGInline.cpp
Source/WebCore/rendering/svg/RenderSVGInline.h
Source/WebCore/rendering/svg/RenderSVGInlineText.cpp
Source/WebCore/rendering/svg/RenderSVGInlineText.h
Source/WebCore/rendering/svg/RenderSVGText.cpp
Source/WebCore/rendering/svg/RenderSVGText.h
Source/WebCore/rendering/svg/SVGRootInlineBox.cpp
Source/WebCore/rendering/svg/SVGRootInlineBox.h
Source/WebCore/rendering/svg/SVGTextLayoutAttributes.h
Source/WebCore/rendering/svg/SVGTextLayoutAttributesBuilder.cpp
Source/WebCore/rendering/svg/SVGTextLayoutEngine.cpp
Source/WebCore/rendering/svg/SVGTextLayoutEngine.h
Source/WebCore/rendering/svg/SVGTextMetrics.h
Source/WebCore/rendering/svg/SVGTextMetricsBuilder.cpp
Source/WebCore/rendering/svg/SVGTextQuery.cpp
Source/WebCore/svg/SVGTextContentElement.cpp