[Simple line layout] Cache run resolver.
authorzalan@apple.com <zalan@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 9 May 2018 00:20:18 +0000 (00:20 +0000)
committerzalan@apple.com <zalan@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 9 May 2018 00:20:18 +0000 (00:20 +0000)
https://bugs.webkit.org/show_bug.cgi?id=185411

Reviewed by Antti Koivisto.

This patch caches the run resolver on the [SimpleLine]Layout object.
In certain cases, when the block container has thousands of elements (foobar1<br>foobar2<br>.....foobar9999<br>),
constructing the resolver (and its dependencies) in a repeating fashion could hang the WebProcess.

Covered by existing tests.

* rendering/SimpleLineLayout.cpp:
(WebCore::SimpleLineLayout::create):
(WebCore::SimpleLineLayout::Layout::create):
(WebCore::SimpleLineLayout::Layout::Layout):
* rendering/SimpleLineLayout.h:
(WebCore::SimpleLineLayout::Layout::runResolver const):
* rendering/SimpleLineLayoutFunctions.cpp:
(WebCore::SimpleLineLayout::paintFlow):
(WebCore::SimpleLineLayout::hitTestFlow):
(WebCore::SimpleLineLayout::collectFlowOverflow):
(WebCore::SimpleLineLayout::computeBoundingBox):
(WebCore::SimpleLineLayout::computeFirstRunLocation):
(WebCore::SimpleLineLayout::collectAbsoluteRects):
(WebCore::SimpleLineLayout::collectAbsoluteQuads):
(WebCore::SimpleLineLayout::textOffsetForPoint):
(WebCore::SimpleLineLayout::collectAbsoluteQuadsForRange):
(WebCore::SimpleLineLayout::generateLineBoxTree):
* rendering/SimpleLineLayoutResolver.cpp:
(WebCore::SimpleLineLayout::LineResolver::LineResolver):
* rendering/SimpleLineLayoutResolver.h:
(WebCore::SimpleLineLayout::lineResolver):

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

Source/WebCore/ChangeLog
Source/WebCore/rendering/SimpleLineLayout.cpp
Source/WebCore/rendering/SimpleLineLayout.h
Source/WebCore/rendering/SimpleLineLayoutFunctions.cpp
Source/WebCore/rendering/SimpleLineLayoutResolver.cpp
Source/WebCore/rendering/SimpleLineLayoutResolver.h

index d351f8f..fd87e4e 100644 (file)
@@ -1,3 +1,38 @@
+2018-05-08  Zalan Bujtas  <zalan@apple.com>
+
+        [Simple line layout] Cache run resolver.
+        https://bugs.webkit.org/show_bug.cgi?id=185411
+
+        Reviewed by Antti Koivisto.
+
+        This patch caches the run resolver on the [SimpleLine]Layout object. 
+        In certain cases, when the block container has thousands of elements (foobar1<br>foobar2<br>.....foobar9999<br>),
+        constructing the resolver (and its dependencies) in a repeating fashion could hang the WebProcess.
+
+        Covered by existing tests.
+
+        * rendering/SimpleLineLayout.cpp:
+        (WebCore::SimpleLineLayout::create):
+        (WebCore::SimpleLineLayout::Layout::create):
+        (WebCore::SimpleLineLayout::Layout::Layout):
+        * rendering/SimpleLineLayout.h:
+        (WebCore::SimpleLineLayout::Layout::runResolver const):
+        * rendering/SimpleLineLayoutFunctions.cpp:
+        (WebCore::SimpleLineLayout::paintFlow):
+        (WebCore::SimpleLineLayout::hitTestFlow):
+        (WebCore::SimpleLineLayout::collectFlowOverflow):
+        (WebCore::SimpleLineLayout::computeBoundingBox):
+        (WebCore::SimpleLineLayout::computeFirstRunLocation):
+        (WebCore::SimpleLineLayout::collectAbsoluteRects):
+        (WebCore::SimpleLineLayout::collectAbsoluteQuads):
+        (WebCore::SimpleLineLayout::textOffsetForPoint):
+        (WebCore::SimpleLineLayout::collectAbsoluteQuadsForRange):
+        (WebCore::SimpleLineLayout::generateLineBoxTree):
+        * rendering/SimpleLineLayoutResolver.cpp:
+        (WebCore::SimpleLineLayout::LineResolver::LineResolver):
+        * rendering/SimpleLineLayoutResolver.h:
+        (WebCore::SimpleLineLayout::lineResolver):
+
 2018-05-08  Brent Fulgham  <bfulgham@apple.com>
 
         Switch some RELEASE_ASSERTS to plain debug ASSERTS in PlatformScreenMac.mm
index 301300f..2a3e670 100644 (file)
@@ -50,6 +50,7 @@
 #include "Settings.h"
 #include "SimpleLineLayoutFlowContents.h"
 #include "SimpleLineLayoutFunctions.h"
+#include "SimpleLineLayoutResolver.h"
 #include "SimpleLineLayoutTextFragmentIterator.h"
 #include "Text.h"
 #include "TextPaintStyle.h"
@@ -962,22 +963,30 @@ std::unique_ptr<Layout> create(RenderBlockFlow& flow)
     unsigned lineCount = 0;
     Layout::RunVector runs;
     createTextRuns(runs, flow, lineCount);
-    return Layout::create(runs, lineCount);
+    return Layout::create(runs, lineCount, flow);
 }
 
-std::unique_ptr<Layout> Layout::create(const RunVector& runVector, unsigned lineCount)
+std::unique_ptr<Layout> Layout::create(const RunVector& runVector, unsigned lineCount, const RenderBlockFlow& blockFlow)
 {
     void* slot = WTF::fastMalloc(sizeof(Layout) + sizeof(Run) * runVector.size());
-    return std::unique_ptr<Layout>(new (NotNull, slot) Layout(runVector, lineCount));
+    return std::unique_ptr<Layout>(new (NotNull, slot) Layout(runVector, lineCount, blockFlow));
 }
 
-Layout::Layout(const RunVector& runVector, unsigned lineCount)
+Layout::Layout(const RunVector& runVector, unsigned lineCount, const RenderBlockFlow& blockFlow)
     : m_lineCount(lineCount)
     , m_runCount(runVector.size())
+    , m_blockFlowRenderer(blockFlow)
 {
     memcpy(m_runs, runVector.data(), m_runCount * sizeof(Run));
 }
 
+const RunResolver& Layout::runResolver() const
+{
+    if (!m_runResolver)
+        m_runResolver = std::make_unique<RunResolver>(m_blockFlowRenderer, *this);
+    return *m_runResolver;
+}
+
 Layout::~Layout()
 {
     simpleLineLayoutWillBeDeleted(*this);
index 527447d..6e36549 100644 (file)
@@ -41,10 +41,11 @@ class RenderBlockFlow;
 
 namespace SimpleLineLayout {
 
+class RunResolver;
+
 bool canUseFor(const RenderBlockFlow&);
 AvoidanceReasonFlags canUseForWithReason(const RenderBlockFlow&, IncludeReasons);
 
-
 struct Run {
 #if COMPILER(MSVC)
     Run() { }
@@ -79,7 +80,7 @@ class Layout {
 public:
     using RunVector = Vector<Run, 10>;
     using SimpleLineStruts = Vector<SimpleLineStrut, 4>;
-    static std::unique_ptr<Layout> create(const RunVector&, unsigned lineCount);
+    static std::unique_ptr<Layout> create(const RunVector&, unsigned lineCount, const RenderBlockFlow&);
 
     ~Layout();
 
@@ -93,13 +94,17 @@ public:
     bool hasLineStruts() const { return !m_lineStruts.isEmpty(); }
     void setLineStruts(SimpleLineStruts&& lineStruts) { m_lineStruts = lineStruts; }
     const SimpleLineStruts& struts() const { return m_lineStruts; }
+    const RunResolver& runResolver() const;
+
 private:
-    Layout(const RunVector&, unsigned lineCount);
+    Layout(const RunVector&, unsigned lineCount, const RenderBlockFlow&);
 
     unsigned m_lineCount;
     unsigned m_runCount;
     bool m_isPaginated { false };
     SimpleLineStruts m_lineStruts;
+    const RenderBlockFlow& m_blockFlowRenderer;
+    mutable std::unique_ptr<RunResolver> m_runResolver;
     Run m_runs[0];
 };
 
index a4eece1..2e75568 100644 (file)
@@ -106,7 +106,7 @@ void paintFlow(const RenderBlockFlow& flow, const Layout& layout, PaintInfo& pai
     LayoutRect paintRect = paintInfo.rect;
     paintRect.moveBy(-paintOffset);
 
-    auto resolver = runResolver(flow, layout);
+    auto& resolver = layout.runResolver();
     float deviceScaleFactor = flow.document().deviceScaleFactor();
     for (auto run : resolver.rangeForRect(paintRect)) {
         if (run.start() == run.end())
@@ -148,7 +148,7 @@ bool hitTestFlow(const RenderBlockFlow& flow, const Layout& layout, const HitTes
 
     LayoutRect rangeRect = locationInContainer.boundingBox();
     rangeRect.moveBy(-accumulatedOffset);
-    auto resolver = lineResolver(flow, layout);
+    auto resolver = lineResolver(layout.runResolver());
     auto range = resolver.rangeForRect(rangeRect);
     for (auto it = range.begin(), end = range.end(); it != end; ++it) {
         auto lineRect = *it;
@@ -165,7 +165,7 @@ bool hitTestFlow(const RenderBlockFlow& flow, const Layout& layout, const HitTes
 
 void collectFlowOverflow(RenderBlockFlow& flow, const Layout& layout)
 {
-    for (auto lineRect : lineResolver(flow, layout)) {
+    for (auto lineRect : lineResolver(layout.runResolver())) {
         LayoutRect visualOverflowRect = LayoutRect(computeOverflow(flow, lineRect));
         flow.addLayoutOverflow(LayoutRect(lineRect));
         flow.addVisualOverflow(visualOverflowRect);
@@ -174,7 +174,7 @@ void collectFlowOverflow(RenderBlockFlow& flow, const Layout& layout)
 
 IntRect computeBoundingBox(const RenderObject& renderer, const Layout& layout)
 {
-    auto resolver = runResolver(downcast<RenderBlockFlow>(*renderer.parent()), layout);
+    auto& resolver = layout.runResolver();
     FloatRect boundingBoxRect;
     for (auto run : resolver.rangeForRenderer(renderer)) {
         FloatRect rect = run.rect();
@@ -188,7 +188,7 @@ IntRect computeBoundingBox(const RenderObject& renderer, const Layout& layout)
 
 IntPoint computeFirstRunLocation(const RenderObject& renderer, const Layout& layout)
 {
-    auto resolver = runResolver(downcast<RenderBlockFlow>(*renderer.parent()), layout);
+    auto& resolver = layout.runResolver();
     auto range = resolver.rangeForRenderer(renderer);
     auto begin = range.begin();
     if (begin == range.end())
@@ -199,7 +199,7 @@ IntPoint computeFirstRunLocation(const RenderObject& renderer, const Layout& lay
 Vector<IntRect> collectAbsoluteRects(const RenderObject& renderer, const Layout& layout, const LayoutPoint& accumulatedOffset)
 {
     Vector<IntRect> rects;
-    auto resolver = runResolver(downcast<RenderBlockFlow>(*renderer.parent()), layout);
+    auto& resolver = layout.runResolver();
     for (auto run : resolver.rangeForRenderer(renderer)) {
         FloatRect rect = run.rect();
         rects.append(enclosingIntRect(FloatRect(accumulatedOffset + rect.location(), rect.size())));
@@ -210,7 +210,7 @@ Vector<IntRect> collectAbsoluteRects(const RenderObject& renderer, const Layout&
 Vector<FloatQuad> collectAbsoluteQuads(const RenderObject& renderer, const Layout& layout, bool* wasFixed)
 {
     Vector<FloatQuad> quads;
-    auto resolver = runResolver(downcast<RenderBlockFlow>(*renderer.parent()), layout);
+    auto& resolver = layout.runResolver();
     for (auto run : resolver.rangeForRenderer(renderer))
         quads.append(renderer.localToAbsoluteQuad(FloatQuad(run.rect()), UseTransforms, wasFixed));
     return quads;
@@ -220,7 +220,7 @@ unsigned textOffsetForPoint(const LayoutPoint& point, const RenderText& renderer
 {
     auto& flow = downcast<RenderBlockFlow>(*renderer.parent());
     ASSERT(flow.firstChild() == flow.lastChild());
-    auto resolver = runResolver(flow, layout);
+    auto& resolver = layout.runResolver();
     auto it = resolver.runForPoint(point);
     if (it == resolver.end())
         return renderer.text().length();
@@ -235,7 +235,7 @@ Vector<FloatQuad> collectAbsoluteQuadsForRange(const RenderObject& renderer, uns
 {
     auto& style = downcast<RenderBlockFlow>(*renderer.parent()).style();
     Vector<FloatQuad> quads;
-    auto resolver = runResolver(downcast<RenderBlockFlow>(*renderer.parent()), layout);
+    auto& resolver = layout.runResolver();
     for (auto run : resolver.rangeForRendererWithOffsets(renderer, start, end)) {
         // This run is fully contained.
         if (start <= run.start() && end >= run.end()) {
@@ -322,7 +322,7 @@ void generateLineBoxTree(RenderBlockFlow& flow, const Layout& layout)
         return;
 
     Ref<BidiContext> bidiContext = BidiContext::create(0, U_LEFT_TO_RIGHT);
-    auto resolver = runResolver(flow, layout);
+    auto& resolver = layout.runResolver();
     unsigned lineIndex = 0;
     while (true) {
         auto range = resolver.rangeForLine(lineIndex++);
index 3e17cc9..b313cd3 100644 (file)
@@ -337,8 +337,8 @@ const RenderObject& LineResolver::Iterator::renderer() const
     return m_runIterator.resolver().flowContents().segmentForRun(run.start(), run.end()).renderer;
 }
 
-LineResolver::LineResolver(const RenderBlockFlow& flow, const Layout& layout)
-    : m_runResolver(flow, layout)
+LineResolver::LineResolver(const RunResolver& runResolver)
+    : m_runResolver(runResolver)
 {
 }
 
index 736b8cb..4559260 100644 (file)
@@ -27,6 +27,7 @@
 
 #include "LayoutRect.h"
 #include "RenderBlockFlow.h"
+#include "SimpleLineLayout.h"
 #include "SimpleLineLayoutFlowContents.h"
 #include <wtf/IteratorRange.h>
 #include <wtf/text/WTFString.h>
@@ -149,7 +150,7 @@ public:
         RunResolver::Iterator m_runIterator;
     };
 
-    LineResolver(const RenderBlockFlow&, const Layout&);
+    LineResolver(const RunResolver&);
 
     Iterator begin() const;
     Iterator end() const;
@@ -157,11 +158,11 @@ public:
     WTF::IteratorRange<Iterator> rangeForRect(const LayoutRect&) const;
 
 private:
-    RunResolver m_runResolver;
+    const RunResolver& m_runResolver;
 };
 
 RunResolver runResolver(const RenderBlockFlow&, const Layout&);
-LineResolver lineResolver(const RenderBlockFlow&, const Layout&);
+LineResolver lineResolver(const RunResolver&);
 
 inline unsigned RunResolver::Run::start() const
 {
@@ -303,9 +304,9 @@ inline RunResolver runResolver(const RenderBlockFlow& flow, const Layout& layout
     return RunResolver(flow, layout);
 }
 
-inline LineResolver lineResolver(const RenderBlockFlow& flow, const Layout& layout)
+inline LineResolver lineResolver(const RunResolver& runResolver)
 {
-    return LineResolver(flow, layout);
+    return LineResolver(runResolver);
 }
 
 }