Simple line layout: Add top level pagination support.
authorzalan@apple.com <zalan@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 9 Mar 2017 15:25:12 +0000 (15:25 +0000)
committerzalan@apple.com <zalan@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 9 Mar 2017 15:25:12 +0000 (15:25 +0000)
https://bugs.webkit.org/show_bug.cgi?id=169410
<rdar://problem/28536227>

Reviewed by Antti Koivisto.

Source/WebCore:

This patch enables top level pagination for simple line layout.

Covered by existing tests.

* rendering/RenderMultiColumnFlowThread.h:
* rendering/RenderView.cpp:
(WebCore::RenderView::pushLayoutStateForPagination): Pagination flag needs to be set before calling pushLayoutStateForCurrentFlowThread.
* rendering/SimpleLineLayout.cpp:
(WebCore::SimpleLineLayout::canUseForWithReason):
* rendering/SimpleLineLayoutCoverage.cpp:
(WebCore::SimpleLineLayout::printReason):
* rendering/SimpleLineLayoutCoverage.h:
* rendering/SimpleLineLayoutFunctions.cpp:
(WebCore::SimpleLineLayout::paintFlow):
* rendering/SimpleLineLayoutPagination.cpp:
(WebCore::SimpleLineLayout::computeLineTopAndBottomWithOverflow): Matching normal line layout values.
(WebCore::SimpleLineLayout::setPageBreakForLine): Logic here matches RenderBlockFlow::adjustLinePositionForPagination

LayoutTests:

* TestExpectations:

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

LayoutTests/ChangeLog
LayoutTests/TestExpectations
Source/WebCore/ChangeLog
Source/WebCore/rendering/RenderMultiColumnFlowThread.h
Source/WebCore/rendering/RenderView.cpp
Source/WebCore/rendering/SimpleLineLayout.cpp
Source/WebCore/rendering/SimpleLineLayoutCoverage.cpp
Source/WebCore/rendering/SimpleLineLayoutCoverage.h
Source/WebCore/rendering/SimpleLineLayoutPagination.cpp

index 51f3180..ceca097 100644 (file)
@@ -1,3 +1,13 @@
+2017-03-09  Zalan Bujtas  <zalan@apple.com>
+
+        Simple line layout: Add top level pagination support.
+        https://bugs.webkit.org/show_bug.cgi?id=169410
+        <rdar://problem/28536227>
+
+        Reviewed by Antti Koivisto.
+
+        * TestExpectations:
+
 2017-03-08  Per Arne Vollan  <pvollan@apple.com>
 
         Implement stroke-width CSS property.
index 561aa58..8c51d7c 100644 (file)
@@ -1209,6 +1209,9 @@ svg/custom/font-face-fallback.svg [ Skip ]
 # Test disabled until we can fix layout of orthogonal writing mode roots
 fast/table/colspanMinWidth-vertical.html [ Skip ]
 
+# Orphan lines with visual overflow vs. simple line layout.
+webkit.org/b/169409 fast/multicol/orphans-negative-line-spacing.html [ ImageOnlyFailure ]
+
 ### END OF -disabled tests
 ########################################
 
index 055c829..af7778d 100644 (file)
@@ -1,3 +1,29 @@
+2017-03-09  Zalan Bujtas  <zalan@apple.com>
+
+        Simple line layout: Add top level pagination support.
+        https://bugs.webkit.org/show_bug.cgi?id=169410
+        <rdar://problem/28536227>
+
+        Reviewed by Antti Koivisto.
+
+        This patch enables top level pagination for simple line layout.
+
+        Covered by existing tests.
+
+        * rendering/RenderMultiColumnFlowThread.h:
+        * rendering/RenderView.cpp:
+        (WebCore::RenderView::pushLayoutStateForPagination): Pagination flag needs to be set before calling pushLayoutStateForCurrentFlowThread.
+        * rendering/SimpleLineLayout.cpp:
+        (WebCore::SimpleLineLayout::canUseForWithReason):
+        * rendering/SimpleLineLayoutCoverage.cpp:
+        (WebCore::SimpleLineLayout::printReason):
+        * rendering/SimpleLineLayoutCoverage.h:
+        * rendering/SimpleLineLayoutFunctions.cpp:
+        (WebCore::SimpleLineLayout::paintFlow):
+        * rendering/SimpleLineLayoutPagination.cpp:
+        (WebCore::SimpleLineLayout::computeLineTopAndBottomWithOverflow): Matching normal line layout values.
+        (WebCore::SimpleLineLayout::setPageBreakForLine): Logic here matches RenderBlockFlow::adjustLinePositionForPagination
+
 2017-03-09  Tomas Popela  <tpopela@redhat.com>
 
         [GStreamer][MSE] Fix 'comparison between signed and unsigned integer
index dfdffce..6d934e1 100644 (file)
@@ -43,6 +43,7 @@ public:
     RenderMultiColumnSet* firstMultiColumnSet() const;
     RenderMultiColumnSet* lastMultiColumnSet() const;
     RenderBox* firstColumnSetOrSpanner() const;
+    bool hasColumnSpanner() const { return !m_spannerMap.isEmpty(); }
     static RenderBox* nextColumnSetOrSpannerSiblingOf(const RenderBox*);
     static RenderBox* previousColumnSetOrSpannerSiblingOf(const RenderBox*);
 
index 49fa3f5..a0fa2a5 100644 (file)
@@ -1237,11 +1237,12 @@ void RenderView::pushLayoutState(RenderObject& root)
 
 void RenderView::pushLayoutStateForPagination(RenderBlockFlow& layoutRoot)
 {
-    pushLayoutState(layoutRoot);
-    ASSERT(m_layoutState);
+    ASSERT(!m_layoutState);
+    m_layoutState = std::make_unique<LayoutState>(layoutRoot);
     m_layoutState->m_isPaginated = true;
     // This is just a flag for known page height (see RenderBlockFlow::checkForPaginationLogicalHeightChange).
     m_layoutState->m_pageLogicalHeight = 1;
+    pushLayoutStateForCurrentFlowThread(layoutRoot);
 }
 
 IntSize RenderView::viewportSizeForCSSViewportUnits() const
index 58319af..7f73b17 100644 (file)
 #include "PaintInfo.h"
 #include "RenderBlockFlow.h"
 #include "RenderChildIterator.h"
+#include "RenderFlowThread.h"
 #include "RenderLineBreak.h"
+#include "RenderMultiColumnFlowThread.h"
 #include "RenderStyle.h"
 #include "RenderText.h"
 #include "RenderTextControl.h"
+#include "RenderView.h"
 #include "Settings.h"
 #include "SimpleLineLayoutFlowContents.h"
 #include "SimpleLineLayoutFunctions.h"
@@ -246,8 +249,21 @@ AvoidanceReasonFlags canUseForWithReason(const RenderBlockFlow& flow, IncludeRea
         SET_REASON_AND_RETURN_IF_NEEDED(FlowHasNoParent, reasons, includeReasons);
     if (!flow.firstChild())
         SET_REASON_AND_RETURN_IF_NEEDED(FlowHasNoChild, reasons, includeReasons);
-    if (flow.flowThreadState() != RenderObject::NotInsideFlowThread)
-        SET_REASON_AND_RETURN_IF_NEEDED(FlowIsInsideRegion, reasons, includeReasons);
+    if (flow.flowThreadState() != RenderObject::NotInsideFlowThread) {
+        auto* flowThread = flow.flowThreadContainingBlock();
+        if (!is<RenderMultiColumnFlowThread>(flowThread))
+            SET_REASON_AND_RETURN_IF_NEEDED(FlowIsInsideANonMultiColumnThread, reasons, includeReasons);
+        auto& columnThread = downcast<RenderMultiColumnFlowThread>(*flowThread);
+        if (columnThread.parent() != &flow.view())
+            SET_REASON_AND_RETURN_IF_NEEDED(MultiColumnFlowIsNotTopLevel, reasons, includeReasons);
+        if (columnThread.hasColumnSpanner())
+            SET_REASON_AND_RETURN_IF_NEEDED(MultiColumnFlowHasColumnSpanner, reasons, includeReasons);
+        auto& style = flow.style();
+        if (style.verticalAlign() != BASELINE)
+            SET_REASON_AND_RETURN_IF_NEEDED(MultiColumnFlowVerticalAlign, reasons, includeReasons);
+        if (style.isFloating())
+            SET_REASON_AND_RETURN_IF_NEEDED(MultiColumnFlowIsFloating, reasons, includeReasons);
+    }
     if (!flow.isHorizontalWritingMode())
         SET_REASON_AND_RETURN_IF_NEEDED(FlowHasHorizonalWritingMode, reasons, includeReasons);
     if (flow.hasOutline())
index ba462af..f597ae5 100644 (file)
@@ -42,8 +42,8 @@ namespace SimpleLineLayout {
 static void printReason(AvoidanceReason reason, TextStream& stream)
 {
     switch (reason) {
-    case FlowIsInsideRegion:
-        stream << "flow is inside region";
+    case FlowIsInsideANonMultiColumnThread:
+        stream << "flow is inside a non-multicolumn container";
         break;
     case FlowHasHorizonalWritingMode:
         stream << "horizontal writing mode";
@@ -183,6 +183,18 @@ static void printReason(AvoidanceReason reason, TextStream& stream)
     case FlowTextHasSurrogatePair:
         stream << "surrogate pair";
         break;
+    case MultiColumnFlowIsNotTopLevel:
+        stream << "non top level column";
+        break;
+    case MultiColumnFlowHasColumnSpanner:
+        stream << "column has spanner";
+        break;
+    case MultiColumnFlowVerticalAlign:
+        stream << "column with vertical-align != baseline";
+        break;
+    case MultiColumnFlowIsFloating:
+        stream << "column with floating objecgts";
+        break;
     case FlowTextIsEmpty:
     case FlowHasNoChild:
     case FlowHasNoParent:
index 69d2a13..cda44dd 100644 (file)
@@ -35,7 +35,7 @@ void toggleSimpleLineLayout();
 #endif
 
 enum AvoidanceReason_ : uint64_t {
-    FlowIsInsideRegion                    = 1LLU  << 0,
+    FlowIsInsideANonMultiColumnThread     = 1LLU  << 0,
     FlowHasHorizonalWritingMode           = 1LLU  << 1,
     FlowHasOutline                        = 1LLU  << 2,
     FlowIsRuby                            = 1LLU  << 3,
@@ -86,7 +86,11 @@ enum AvoidanceReason_ : uint64_t {
     FlowHasHangingPunctuation             = 1LLU  << 48,
     FlowFontHasOverflowGlyph              = 1LLU  << 49,
     FlowTextHasSurrogatePair              = 1LLU  << 50,
-    EndOfReasons                          = 1LLU  << 51
+    MultiColumnFlowIsNotTopLevel          = 1LLU  << 51,
+    MultiColumnFlowHasColumnSpanner       = 1LLU  << 52,
+    MultiColumnFlowVerticalAlign          = 1LLU  << 53,
+    MultiColumnFlowIsFloating             = 1LLU  << 54,
+    EndOfReasons                          = 1LLU  << 55
 };
 const unsigned NoReason = 0;
 
index cf5b684..11739c4 100644 (file)
@@ -44,8 +44,8 @@ static PaginatedLine computeLineTopAndBottomWithOverflow(const RenderBlockFlow&
 {
     // FIXME: Add visualOverflowForDecorations.
     auto& fontMetrics = flow.style().fontCascade().fontMetrics();
-    auto ascent = fontMetrics.floatAscent();
-    auto descent = fontMetrics.floatDescent();
+    auto ascent = fontMetrics.ascent();
+    auto descent = fontMetrics.descent();
     auto lineHeight = lineHeightFromFlow(flow);
     LayoutUnit offset = flow.borderAndPaddingBefore();
     for (auto& strut : struts) {
@@ -94,17 +94,20 @@ static LayoutUnit computeOffsetAfterLineBreak(LayoutUnit lineBreakPosition, bool
 static void setPageBreakForLine(unsigned lineBreakIndex, PaginatedLines& lines, RenderBlockFlow& flow, Layout::SimpleLineStruts& struts,
     bool atTheTopOfColumnOrPage)
 {
-    if (!lineBreakIndex) {
-        // When the first line does not fit the current page, just add a page break in front and set the strut on the block.
-        auto line = lines.first();
-        auto remainingLogicalHeight = flow.pageRemainingLogicalHeightForOffset(line.top, RenderBlockFlow::ExcludePageBoundary);
+    auto line = lines.at(lineBreakIndex);
+    auto remainingLogicalHeight = flow.pageRemainingLogicalHeightForOffset(line.top, RenderBlockFlow::ExcludePageBoundary);
+    auto& style = flow.style();
+    auto firstLineWithDoesNotFit = !lineBreakIndex && line.height < flow.pageLogicalHeightForOffset(line.top);
+    auto orphanDoesNotFit = !style.hasAutoOrphans() && style.orphans() > (short)lineBreakIndex;
+    if (firstLineWithDoesNotFit || orphanDoesNotFit) {
         flow.setPageBreak(line.top, line.height - remainingLogicalHeight);
-        flow.setPaginationStrut(remainingLogicalHeight);
+        flow.setPaginationStrut(line.top + remainingLogicalHeight);
         return;
     }
-    auto beforeLineBreak = lines.at(lineBreakIndex - 1);
-    auto spaceShortage = flow.pageRemainingLogicalHeightForOffset(beforeLineBreak.top, RenderBlockFlow::ExcludePageBoundary) - beforeLineBreak.height;
-    flow.setPageBreak(beforeLineBreak.bottom, spaceShortage);
+    if (atTheTopOfColumnOrPage)
+        flow.setPageBreak(line.top, line.height);
+    else
+        flow.setPageBreak(line.top, line.height - remainingLogicalHeight);
     struts.append({ lineBreakIndex, computeOffsetAfterLineBreak(lines[lineBreakIndex].top, !lineBreakIndex, atTheTopOfColumnOrPage, flow) });
 }