https://bugs.webkit.org/show_bug.cgi?id=143554
Reviewed by Antti Koivisto.
Initialize render flow's segments only when the render flow changes in TextIterator.
The included performance test shows 6x speedup. (from ~10 runs/sec to ~60 runs/sec)
PerformanceTests:
* Layout/simple-line-layout-innertext.html: Added.
Source/WebCore:
Test: PerformanceTests/Layout/simple-line-layout-innertext.html.
* editing/TextIterator.cpp:
(WebCore::TextIterator::handleTextNode):
* editing/TextIterator.h:
* rendering/SimpleLineLayoutFlowContents.cpp: Instruments log shows that vector's expandCapacity could be expensive when flow has large amount of children.
(WebCore::SimpleLineLayout::initializeSegments):
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@182604
268f45cc-cd09-0410-ab3c-
d52691b4dbfc
+2015-04-09 Zalan Bujtas <zalan@apple.com>
+
+ Simple line layout(regression): Calling innerText on RenderFlow with multiple children is slow.
+ https://bugs.webkit.org/show_bug.cgi?id=143554
+
+ Reviewed by Antti Koivisto.
+
+ Initialize render flow's segments only when the render flow changes in TextIterator.
+ The included performance test shows 6x speedup. (from ~10 runs/sec to ~60 runs/sec)
+
+ * Layout/simple-line-layout-innertext.html: Added.
+
2015-03-09 Chris Dumez <cdumez@apple.com>
[CG] Have Canvas use the IOSurfacePool
--- /dev/null
+<!DOCTYPE html>
+<html>
+<head>
+ <title>innerText performance test with simple line layout.</title>
+ <script src="../resources/runner.js"></script>
+</head>
+<body>
+ <pre id="log"></pre>
+ <div id="target" style="width: 300px;"></div>
+ <div id="result"></div>
+ <script>
+ var target = document.getElementById("target");
+ var result = document.getElementById("result");
+ for (i = 0; i < 500; ++i)
+ target.appendChild(document.createTextNode("foobar"));
+
+ function test() {
+ for (i = 0; i < 10; ++i)
+ result.innerText += target.innerText;
+ result.innerText = "";
+ }
+ PerfTestRunner.measureRunsPerSecond({ run: test });
+ </script>
+</body>
+</html>
+2015-04-09 Zalan Bujtas <zalan@apple.com>
+
+ Simple line layout(regression): Calling innerText on RenderFlow with multiple children is slow.
+ https://bugs.webkit.org/show_bug.cgi?id=143554
+
+ Reviewed by Antti Koivisto.
+
+ Initialize render flow's segments only when the render flow changes in TextIterator.
+ The included performance test shows 6x speedup. (from ~10 runs/sec to ~60 runs/sec)
+
+ Test: PerformanceTests/Layout/simple-line-layout-innertext.html.
+
+ * editing/TextIterator.cpp:
+ (WebCore::TextIterator::handleTextNode):
+ * editing/TextIterator.h:
+ * rendering/SimpleLineLayoutFlowContents.cpp: Instruments log shows that vector's expandCapacity could be expensive when flow has large amount of children.
+ (WebCore::SimpleLineLayout::initializeSegments):
+
2015-04-09 Chris Dumez <cdumez@apple.com>
[WK2][iOS] editorState() should not cause a synchronous layout
return true;
// Use the simple layout runs to iterate over the text content.
ASSERT(renderer.parent() && is<RenderBlockFlow>(renderer.parent()));
- const auto& blockFlow = downcast<RenderBlockFlow>(*renderer.parent());
- SimpleLineLayout::RunResolver runResolver(blockFlow, *layout);
- auto range = runResolver.rangeForRenderer(renderer);
unsigned endPosition = (m_node == m_endContainer) ? static_cast<unsigned>(m_endOffset) : rendererText.length();
- // Simple line layout run positions are all absolute to the parent flow.
- // Offsetting is required when multiple renderers are present.
- if (previousTextNode && previousTextNode != &textNode) {
- const RenderObject& previousRenderer = *previousTextNode->renderer();
- if (previousRenderer.parent() != &blockFlow)
- m_previousTextLengthInFlow = 0;
- else
- m_previousTextLengthInFlow += previousTextNode->renderer()->text()->length();
+ const auto& blockFlow = downcast<RenderBlockFlow>(*renderer.parent());
+ if (!m_flowRunResolverCache || &m_flowRunResolverCache->flow() != &blockFlow) {
+ m_flowRunResolverCache = std::make_unique<SimpleLineLayout::RunResolver>(blockFlow, *layout);
+ m_previousTextLengthInFlow = 0;
+ } else if (previousTextNode && previousTextNode != &textNode) {
+ // Simple line layout run positions are all absolute to the parent flow.
+ // Offsetting is required when multiple renderers are present.
+ m_previousTextLengthInFlow += previousTextNode->renderer()->text()->length();
}
// Skip to m_offset position.
+ auto range = m_flowRunResolverCache->rangeForRenderer(renderer);
auto it = range.begin();
auto end = range.end();
while (it != end && (*it).end() <= (static_cast<unsigned>(m_offset) + m_previousTextLengthInFlow))
class InlineTextBox;
class RenderText;
class RenderTextFragment;
+namespace SimpleLineLayout {
+class RunResolver;
+}
WEBCORE_EXPORT String plainText(const Range*, TextIteratorBehavior = TextIteratorDefaultBehavior, bool isDisplayString = false);
WEBCORE_EXPORT String plainTextReplacingNoBreakSpace(const Range*, TextIteratorBehavior = TextIteratorDefaultBehavior, bool isDisplayString = false);
// Used to do simple line layout run logic.
bool m_nextRunNeedsWhitespace { false };
unsigned m_previousTextLengthInFlow { 0 };
+ std::unique_ptr<SimpleLineLayout::RunResolver> m_flowRunResolverCache;
+
// Used when text boxes are out of order (Hebrew/Arabic with embedded LTR text)
Vector<InlineTextBox*> m_sortedTextBoxes;
size_t m_sortedTextBoxesPosition;
static Vector<FlowContents::Segment> initializeSegments(const RenderBlockFlow& flow)
{
- Vector<FlowContents::Segment, 8> segments;
+
+ unsigned numberOfChildren = 0;
+ auto children = childrenOfType<RenderText>(flow);
+ for (auto it = children.begin(), end = children.end(); it != end; ++it)
+ ++numberOfChildren;
+ Vector<FlowContents::Segment> segments;
+ segments.reserveCapacity(numberOfChildren);
unsigned startPosition = 0;
for (auto& textChild : childrenOfType<RenderText>(flow)) {
unsigned textLength = textChild.text()->length();
}
RunResolver::RunResolver(const RenderBlockFlow& flow, const Layout& layout)
- : m_layout(layout)
+ : m_flowRenderer(flow)
+ , m_layout(layout)
, m_flowContents(flow)
, m_lineHeight(lineHeightFromFlow(flow))
, m_baseline(baselineFromFlow(flow))
RunResolver(const RenderBlockFlow&, const Layout&);
+ const RenderBlockFlow& flow() const { return m_flowRenderer; }
Iterator begin() const;
Iterator end() const;
enum class IndexType { First, Last };
unsigned lineIndexForHeight(LayoutUnit, IndexType) const;
+ const RenderBlockFlow& m_flowRenderer;
const Layout& m_layout;
const FlowContents m_flowContents;
const LayoutUnit m_lineHeight;