[Simple line layout] Generate inline boxtree using simple line layout runs.
authorzalan@apple.com <zalan@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 23 Apr 2018 14:47:00 +0000 (14:47 +0000)
committerzalan@apple.com <zalan@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 23 Apr 2018 14:47:00 +0000 (14:47 +0000)
https://bugs.webkit.org/show_bug.cgi?id=184833

Reviewed by Antti Koivisto.

RenderBlockFlow::ensureLineBoxes triggers line layout on the block content to replace
the simple line layout runs with an inline boxtree. The runs generated by the fast path
should always match the inline tree boxes.
In this patch instead of triggering layout, we just convert the simple line runs to
inline boxes.
Currently, it works with only one, non-paginated text renderer, but we should be
able to extend it to all the simple line layout content.

Covered by existing tests.

* rendering/InlineBox.h:
(WebCore::InlineBox::setHasHyphen):
(WebCore::InlineBox::setCanHaveLeadingExpansion):
(WebCore::InlineBox::setCanHaveTrailingExpansion):
(WebCore::InlineBox::setForceTrailingExpansion):
(WebCore::InlineBox::setForceLeadingExpansion):
(WebCore::InlineBox::hasHyphen const):
(WebCore::InlineBox::canHaveLeadingExpansion const):
(WebCore::InlineBox::canHaveTrailingExpansion const):
(WebCore::InlineBox::forceTrailingExpansion const):
* rendering/RenderBlockFlow.cpp:
(WebCore::RenderBlockFlow::ensureLineBoxes):
* rendering/RenderBlockFlow.h:
* rendering/SimpleLineLayoutFlowContents.h:
(WebCore::SimpleLineLayout::FlowContents::segmentForRun const):
* rendering/SimpleLineLayoutFunctions.cpp:
(WebCore::SimpleLineLayout::canUseForLineBoxTree):
(WebCore::SimpleLineLayout::initializeInlineBox):
(WebCore::SimpleLineLayout::generateLineBoxTree):
* rendering/SimpleLineLayoutFunctions.h:
* rendering/SimpleLineLayoutResolver.cpp:
(WebCore::SimpleLineLayout::RunResolver::rangeForLine const):
* rendering/SimpleLineLayoutResolver.h:

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

Source/WebCore/ChangeLog
Source/WebCore/rendering/InlineBox.h
Source/WebCore/rendering/RenderBlockFlow.cpp
Source/WebCore/rendering/RenderBlockFlow.h
Source/WebCore/rendering/SimpleLineLayoutFlowContents.h
Source/WebCore/rendering/SimpleLineLayoutFunctions.cpp
Source/WebCore/rendering/SimpleLineLayoutFunctions.h
Source/WebCore/rendering/SimpleLineLayoutResolver.cpp
Source/WebCore/rendering/SimpleLineLayoutResolver.h

index 7a75f3b..182e635 100644 (file)
@@ -1,3 +1,44 @@
+2018-04-23  Zalan Bujtas  <zalan@apple.com>
+
+        [Simple line layout] Generate inline boxtree using simple line layout runs.
+        https://bugs.webkit.org/show_bug.cgi?id=184833
+
+        Reviewed by Antti Koivisto.
+
+        RenderBlockFlow::ensureLineBoxes triggers line layout on the block content to replace
+        the simple line layout runs with an inline boxtree. The runs generated by the fast path
+        should always match the inline tree boxes.
+        In this patch instead of triggering layout, we just convert the simple line runs to
+        inline boxes.
+        Currently, it works with only one, non-paginated text renderer, but we should be
+        able to extend it to all the simple line layout content.   
+
+        Covered by existing tests.
+
+        * rendering/InlineBox.h:
+        (WebCore::InlineBox::setHasHyphen):
+        (WebCore::InlineBox::setCanHaveLeadingExpansion):
+        (WebCore::InlineBox::setCanHaveTrailingExpansion):
+        (WebCore::InlineBox::setForceTrailingExpansion):
+        (WebCore::InlineBox::setForceLeadingExpansion):
+        (WebCore::InlineBox::hasHyphen const):
+        (WebCore::InlineBox::canHaveLeadingExpansion const):
+        (WebCore::InlineBox::canHaveTrailingExpansion const):
+        (WebCore::InlineBox::forceTrailingExpansion const):
+        * rendering/RenderBlockFlow.cpp:
+        (WebCore::RenderBlockFlow::ensureLineBoxes):
+        * rendering/RenderBlockFlow.h:
+        * rendering/SimpleLineLayoutFlowContents.h:
+        (WebCore::SimpleLineLayout::FlowContents::segmentForRun const):
+        * rendering/SimpleLineLayoutFunctions.cpp:
+        (WebCore::SimpleLineLayout::canUseForLineBoxTree):
+        (WebCore::SimpleLineLayout::initializeInlineBox):
+        (WebCore::SimpleLineLayout::generateLineBoxTree):
+        * rendering/SimpleLineLayoutFunctions.h:
+        * rendering/SimpleLineLayoutResolver.cpp:
+        (WebCore::SimpleLineLayout::RunResolver::rangeForLine const):
+        * rendering/SimpleLineLayoutResolver.h:
+
 2018-04-23  Zan Dobersek  <zdobersek@igalia.com>
 
         [CoordGraphics] Remove unused trajectory cruft in CoordinatedLayerTreeHost, CoordinatedGraphicsLayer
index 7f1dd6c..e93e936 100644 (file)
@@ -280,6 +280,12 @@ public:
     }
     float expansion() const { return m_expansion; }
 
+    void setHasHyphen(bool hasHyphen) { m_bitfields.setHasEllipsisBoxOrHyphen(hasHyphen); }
+    void setCanHaveLeadingExpansion(bool canHaveLeadingExpansion) { m_bitfields.setHasSelectedChildrenOrCanHaveLeadingExpansion(canHaveLeadingExpansion); }
+    void setCanHaveTrailingExpansion(bool canHaveTrailingExpansion) { m_bitfields.setCanHaveTrailingExpansion(canHaveTrailingExpansion); }
+    void setForceTrailingExpansion() { m_bitfields.setForceTrailingExpansion(true); }
+    void setForceLeadingExpansion() { m_bitfields.setForceLeadingExpansion(true); }
+
 private:
     InlineBox* m_next { nullptr }; // The next element on the same line as us.
     InlineBox* m_prev { nullptr }; // The previous element on the same line as us.
@@ -395,14 +401,9 @@ protected:
 
     // For InlineTextBox
     bool hasHyphen() const { return m_bitfields.hasEllipsisBoxOrHyphen(); }
-    void setHasHyphen(bool hasHyphen) { m_bitfields.setHasEllipsisBoxOrHyphen(hasHyphen); }    
     bool canHaveLeadingExpansion() const { return m_bitfields.hasSelectedChildrenOrCanHaveLeadingExpansion(); }
-    void setCanHaveLeadingExpansion(bool canHaveLeadingExpansion) { m_bitfields.setHasSelectedChildrenOrCanHaveLeadingExpansion(canHaveLeadingExpansion); }
     bool canHaveTrailingExpansion() const { return m_bitfields.canHaveTrailingExpansion(); }
-    void setCanHaveTrailingExpansion(bool canHaveTrailingExpansion) { m_bitfields.setCanHaveTrailingExpansion(canHaveTrailingExpansion); }
-    void setForceTrailingExpansion() { m_bitfields.setForceTrailingExpansion(true); }
     bool forceTrailingExpansion() const { return m_bitfields.forceTrailingExpansion(); }
-    void setForceLeadingExpansion() { m_bitfields.setForceLeadingExpansion(true); }
     bool forceLeadingExpansion() const { return m_bitfields.forceLeadingExpansion(); }
     
     // For InlineFlowBox and InlineTextBox
index 85f3409..4eacb8c 100644 (file)
@@ -53,6 +53,7 @@
 #include "Settings.h"
 #include "SimpleLineLayoutFunctions.h"
 #include "SimpleLineLayoutPagination.h"
+#include "SimpleLineLayoutResolver.h"
 #include "TextAutoSizing.h"
 #include "VerticalPositionCache.h"
 #include "VisiblePosition.h"
@@ -3620,6 +3621,12 @@ void RenderBlockFlow::ensureLineBoxes()
     setLineLayoutPath(ForceLineBoxesPath);
     if (!m_simpleLineLayout)
         return;
+
+    if (SimpleLineLayout::canUseForLineBoxTree(*this, *m_simpleLineLayout)) {
+        SimpleLineLayout::generateLineBoxTree(*this, *m_simpleLineLayout);
+        m_simpleLineLayout = nullptr;
+        return;
+    }
     bool isPaginated = m_simpleLineLayout->isPaginated();
     m_simpleLineLayout = nullptr;
 
index 52dc7da..c220bdb 100644 (file)
@@ -360,6 +360,7 @@ public:
     const SimpleLineLayout::Layout* simpleLineLayout() const;
     void deleteLineBoxesBeforeSimpleLineLayout();
     void ensureLineBoxes();
+    void generateLineBoxTree();
 
 #if ENABLE(TREE_DEBUGGING)
     void outputLineTreeAndMark(WTF::TextStream&, const InlineBox* markedBox, int depth) const;
@@ -533,6 +534,7 @@ public:
     LayoutUnit startAlignedOffsetForLine(LayoutUnit position, IndentTextOrNot shouldIndentText);
     virtual ETextAlign textAlignmentForLine(bool endsWithSoftBreak) const;
     virtual void adjustInlineDirectionLineBounds(int /* expansionOpportunityCount */, float& /* logicalLeft */, float& /* logicalWidth */) const { }
+    RootInlineBox* constructLine(BidiRunList<BidiRun>&, const LineInfo&);
 
 private:        
     void adjustIntrinsicLogicalWidthsForColumns(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const;
@@ -542,7 +544,6 @@ private:
 
     virtual std::unique_ptr<RootInlineBox> createRootInlineBox(); // Subclassed by RenderSVGText.
     InlineFlowBox* createLineBoxes(RenderObject*, const LineInfo&, InlineBox* childBox);
-    RootInlineBox* constructLine(BidiRunList<BidiRun>&, const LineInfo&);
     void setMarginsForRubyRun(BidiRun*, RenderRubyRun&, RenderObject*, const LineInfo&);
     void computeInlineDirectionPositionsForLine(RootInlineBox*, const LineInfo&, BidiRun* firstRun, BidiRun* trailingSpaceRun, bool reachedEnd, GlyphOverflowAndFallbackFontsMap&, VerticalPositionCache&, WordMeasurements&);
     void updateRubyForJustifiedText(RenderRubyRun&, BidiRun&, const Vector<unsigned, 16>& expansionOpportunities, unsigned& expansionOpportunityCount, float& totalLogicalWidth, float availableLogicalWidth, size_t& expansionIndex);
index 6a594fa..2dee1ad 100644 (file)
@@ -65,8 +65,9 @@ private:
 inline const FlowContents::Segment& FlowContents::segmentForRun(unsigned start, unsigned end) const
 {
     ASSERT(start <= end);
+    auto isEmptyRange = start == end;
     auto& lastSegment = m_segments[m_lastSegmentIndex];
-    if (lastSegment.start <= start && end <= lastSegment.end)
+    if ((lastSegment.start <= start && end <= lastSegment.end) && (!isEmptyRange || end != lastSegment.end))
         return m_segments[m_lastSegmentIndex];
     return m_segments[segmentIndexForRunSlow(start, end)];
 }
index fb05761..6023efd 100644 (file)
@@ -26,6 +26,8 @@
 #include "config.h"
 #include "SimpleLineLayoutFunctions.h"
 
+#include "BidiRun.h"
+#include "BidiRunList.h"
 #include "FontCache.h"
 #include "Frame.h"
 #include "GraphicsContext.h"
@@ -33,6 +35,7 @@
 #include "HitTestRequest.h"
 #include "HitTestResult.h"
 #include "InlineTextBox.h"
+#include "LineInfo.h"
 #include "PaintInfo.h"
 #include "RenderBlockFlow.h"
 #include "RenderIterator.h"
@@ -269,6 +272,97 @@ void simpleLineLayoutWillBeDeleted(const Layout& layout)
         TextPainter::removeGlyphDisplayList(layout.runAt(i));
 }
 
+bool canUseForLineBoxTree(RenderBlockFlow& flow, const Layout& layout)
+{
+    if (layout.isPaginated())
+        return false;
+    
+    if (flow.style().preserveNewline())
+        return false;
+    
+    if (!flow.firstChild())
+        return false;
+    
+    if (flow.firstChild() != flow.lastChild())
+        return false;
+
+    if (!is<RenderText>(*flow.firstChild()))
+        return false;
+
+    return true;
+}
+
+static void initializeInlineBox(InlineBox& inlineBox, const RunResolver::Run& run)
+{
+    inlineBox.setLogicalLeft(run.logicalLeft());
+    inlineBox.setLogicalTop(run.rect().y());
+    inlineBox.setLogicalWidth(run.logicalRight() - run.logicalLeft());
+
+    inlineBox.setHasHyphen(run.hasHyphen());
+    inlineBox.setExpansionWithoutGrowing(run.expansion());
+
+    auto expansionBehavior = run.expansionBehavior();
+    inlineBox.setCanHaveLeadingExpansion(expansionBehavior & AllowLeadingExpansion);
+    inlineBox.setCanHaveTrailingExpansion(expansionBehavior & AllowTrailingExpansion);
+    if (expansionBehavior & ForceTrailingExpansion)
+        inlineBox.setForceTrailingExpansion();
+    if (expansionBehavior & ForceLeadingExpansion)
+        inlineBox.setForceLeadingExpansion();
+}
+
+void generateLineBoxTree(RenderBlockFlow& flow, const Layout& layout)
+{
+    ASSERT(!flow.lineBoxes().firstLineBox());
+    if (!layout.runCount())
+        return;
+
+    Ref<BidiContext> bidiContext = BidiContext::create(0, U_LEFT_TO_RIGHT);
+    auto resolver = runResolver(flow, layout);
+    unsigned lineIndex = 0;
+    while (true) {
+        auto range = resolver.rangeForLine(lineIndex++);
+        if (range.begin() == range.end())
+            break;
+
+        // Generate bidi runs out of simple line layout runs.
+        BidiRunList<BidiRun> bidiRuns;
+        for (auto it = range.begin(); it != range.end(); ++it) {
+            auto run = *it;
+            bidiRuns.appendRun(std::make_unique<BidiRun>(run.start(), run.end(), *flow.firstChild(), bidiContext.ptr(), U_LEFT_TO_RIGHT));
+        }
+
+        LineInfo lineInfo;
+        lineInfo.setFirstLine(!flow.lineBoxes().firstLineBox());
+        // FIXME: This is needed for flow boxes -but we don't have them yet.
+        // lineInfo.setLastLine(lastLine);
+        lineInfo.setEmpty(!bidiRuns.runCount());
+        bidiRuns.setLogicallyLastRun(bidiRuns.lastRun());
+        auto* root = flow.constructLine(bidiRuns, lineInfo);
+        bidiRuns.clear();
+        if (!root)
+            continue;
+
+        auto& rootLineBox = *root;
+        auto it = range.begin();
+        float lineWidth = 0;
+        // Set the geometry for the inlineboxes.
+        for (auto* inlineBox = rootLineBox.firstChild(); inlineBox && it != range.end(); inlineBox = inlineBox->nextOnLine(), ++it) {
+            auto run = *it;
+            initializeInlineBox(*inlineBox, run);
+            lineWidth += inlineBox->logicalWidth();
+        }
+
+        // Finish setting up the rootline.
+        auto firstRun = *range.begin();
+        rootLineBox.setLogicalLeft(firstRun.logicalLeft());
+        rootLineBox.setLogicalWidth(lineWidth);
+        auto lineTop = firstRun.rect().y();
+        auto lineHeight = firstRun.rect().height();
+        rootLineBox.setLogicalTop(lineTop);
+        rootLineBox.setLineTopBottomPositions(lineTop, lineTop + lineHeight, lineTop, lineTop + lineHeight);
+    }
+}
+
 #if ENABLE(TREE_DEBUGGING)
 static void printPrefix(TextStream& stream, int& printedCharacters, int depth)
 {
index b97f16b..6f9ae74 100644 (file)
@@ -64,6 +64,9 @@ Vector<FloatQuad> collectAbsoluteQuadsForRange(const RenderObject&, unsigned sta
 LayoutUnit lineHeightFromFlow(const RenderBlockFlow&);
 LayoutUnit baselineFromFlow(const RenderBlockFlow&);
 
+bool canUseForLineBoxTree(RenderBlockFlow&, const Layout&);
+void generateLineBoxTree(RenderBlockFlow&, const Layout&);
+
 const RenderObject& rendererForPosition(const FlowContents&, unsigned);
 
 void simpleLineLayoutWillBeDeleted(const Layout&);
index ea0c91c..4764295 100644 (file)
@@ -202,6 +202,16 @@ WTF::IteratorRange<RunResolver::Iterator> RunResolver::rangeForRect(const Layout
     return { rangeBegin, rangeEnd };
 }
 
+WTF::IteratorRange<RunResolver::Iterator> RunResolver::rangeForLine(unsigned lineIndex) const
+{
+    auto rangeBegin = begin().advanceLines(lineIndex);
+    if (rangeBegin == end())
+        return { end(), end() };
+    auto rangeEnd = rangeBegin;
+    rangeEnd.advanceLines(1);
+    return { rangeBegin, rangeEnd };
+}
+
 WTF::IteratorRange<RunResolver::Iterator> RunResolver::rangeForRenderer(const RenderObject& renderer) const
 {
     if (begin() == end())
index ff56f4d..0e8f207 100644 (file)
@@ -104,6 +104,7 @@ public:
 
     WTF::IteratorRange<Iterator> rangeForRect(const LayoutRect&) const;
     WTF::IteratorRange<Iterator> rangeForRenderer(const RenderObject&) const;
+    WTF::IteratorRange<Iterator> rangeForLine(unsigned lineIndex) const;
     Iterator runForPoint(const LayoutPoint&) const;
     WTF::IteratorRange<Iterator> rangeForRendererWithOffsets(const RenderObject&, unsigned start, unsigned end) const;