https://bugs.webkit.org/show_bug.cgi?id=68658
authorhyatt@apple.com <hyatt@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 22 Sep 2011 22:28:21 +0000 (22:28 +0000)
committerhyatt@apple.com <hyatt@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 22 Sep 2011 22:28:21 +0000 (22:28 +0000)
Make matchedEndLine smart enough to not match lines that have moved to new
regions with different available content logical widths. When this happens, we go ahead and treat
the line as failing to match.

Reviewed by Anders Carlsson.

Source/WebCore:

Added new tests in fast/regions.

* rendering/RenderBlock.cpp:
(WebCore::RenderBlock::lineWidthForPaginatedLineChanged):
* rendering/RenderBlock.h:
Enhanced to take an optional delta, so that you can check a new position without having to move
the line box.

* rendering/RenderBlockLineLayout.cpp:
(WebCore::RenderBlock::checkPaginationAndFloatsAtEndLine):
New function that refactors checking for line width changes from region movement as well as the
float checks. Since the float checks were duplicated twice, this is a nice refactoring.

(WebCore::RenderBlock::matchedEndLine):
Changed to call the new helper function that will check both floats and pagination.

LayoutTests:

* fast/regions/webkit-flow-inlines-dynamic.html: Added.
* platform/mac/fast/regions/webkit-flow-inlines-dynamic-expected.png: Added.
* platform/mac/fast/regions/webkit-flow-inlines-dynamic-expected.txt: Added.

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

LayoutTests/ChangeLog
LayoutTests/fast/regions/webkit-flow-inlines-dynamic.html [new file with mode: 0644]
LayoutTests/platform/mac/fast/regions/webkit-flow-inlines-dynamic-expected.png [new file with mode: 0644]
LayoutTests/platform/mac/fast/regions/webkit-flow-inlines-dynamic-expected.txt [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/rendering/RenderBlock.cpp
Source/WebCore/rendering/RenderBlock.h
Source/WebCore/rendering/RenderBlockLineLayout.cpp

index ce18ac6..dc7ba02 100644 (file)
@@ -1,3 +1,17 @@
+2011-09-22  David Hyatt  <hyatt@apple.com>
+
+        https://bugs.webkit.org/show_bug.cgi?id=68658
+
+        Make matchedEndLine smart enough to not match lines that have moved to new
+        regions with different available content logical widths. When this happens, we go ahead and treat
+        the line as failing to match.
+
+        Reviewed by Anders Carlsson.
+
+        * fast/regions/webkit-flow-inlines-dynamic.html: Added.
+        * platform/mac/fast/regions/webkit-flow-inlines-dynamic-expected.png: Added.
+        * platform/mac/fast/regions/webkit-flow-inlines-dynamic-expected.txt: Added.
+
 2011-09-22  Adam Barth  <abarth@webkit.org>
 
         Skip test that need new baselines.
diff --git a/LayoutTests/fast/regions/webkit-flow-inlines-dynamic.html b/LayoutTests/fast/regions/webkit-flow-inlines-dynamic.html
new file mode 100644 (file)
index 0000000..004abc3
--- /dev/null
@@ -0,0 +1,59 @@
+<!doctype html>
+
+ <style>
+    #content {
+        -webkit-flow: "flow1";
+        text-align: justify;
+        padding: 5px;
+    }
+    
+    #first-box {
+        border: 1px solid blue;
+    }
+    
+    #second-box {
+        margin:10px;
+        border: 1px solid green;
+    }
+    
+    #region1, #region2, #region3 {
+        border: 1px solid black;
+        content: -webkit-from-flow("flow1");
+    }
+
+    #region1 {
+        width: 200px;
+        height: 100px;
+    }
+    
+    #region2 {
+        width: 300px;
+        height: 180px;
+    }
+    
+    #region3 {
+        width: 120px;
+        height: 120px;
+    }
+</style>
+
+<div id="content">
+    <div id="first-box">
+        <div id="second-box">
+            <span id="test">This line of text should not get out of the region.</span> This line of text should not get out of the region. This line of text should not get out of the region. This line of text should not get out of the region.<br><br>
+            This line of text should not get out of the region. This line of text should not get out of the region. This line of text should not get out of the region. This line of text should not get out of the region.<br><br>
+            This line of text should not get out of the region.<br><br>
+        </div>
+    </div>
+</div>
+
+<div id="container">
+    <div id="region1"></div>
+    <div id="region2"></div>
+    <div id="region3"></div>
+</div>
+
+<script>
+document.body.offsetWidth;
+document.getElementById('test').appendChild(document.createTextNode(" Here is some added content that will mess things up, since it shoves things down."));
+</script>
diff --git a/LayoutTests/platform/mac/fast/regions/webkit-flow-inlines-dynamic-expected.png b/LayoutTests/platform/mac/fast/regions/webkit-flow-inlines-dynamic-expected.png
new file mode 100644 (file)
index 0000000..4297a79
Binary files /dev/null and b/LayoutTests/platform/mac/fast/regions/webkit-flow-inlines-dynamic-expected.png differ
diff --git a/LayoutTests/platform/mac/fast/regions/webkit-flow-inlines-dynamic-expected.txt b/LayoutTests/platform/mac/fast/regions/webkit-flow-inlines-dynamic-expected.txt
new file mode 100644 (file)
index 0000000..e99cef1
--- /dev/null
@@ -0,0 +1,52 @@
+layer at (0,0) size 800x600
+  RenderView at (0,0) size 800x600
+layer at (0,0) size 800x422
+  RenderBlock {HTML} at (0,0) size 800x422
+    RenderBody {BODY} at (8,8) size 784x406
+      RenderBlock {DIV} at (0,0) size 784x406
+        RenderRegion {DIV} at (0,0) size 202x102 [border: (1px solid #000000)]
+        RenderRegion {DIV} at (0,102) size 302x182 [border: (1px solid #000000)]
+        RenderRegion {DIV} at (0,284) size 122x122 [border: (1px solid #000000)]
+Flow Threads
+  Thread with flow-name 'flow1'
+    layer at (0,0) size 300x400
+      RenderFlowThread at (0,0) size 300x400
+        RenderBlock {DIV} at (0,0) size 300x471
+          RenderBlock {DIV} at (5,5) size 290x461 [border: (1px solid #0000FF)]
+            RenderBlock {DIV} at (11,11) size 268x439 [border: (1px solid #008000)]
+              RenderInline {SPAN} at (0,0) size 266x101
+                RenderText {#text} at (1,1) size 166x36
+                  text run at (1,1) width 166: "This line of text should"
+                  text run at (1,19) width 166: "not get out of the region."
+                RenderText {#text} at (1,37) size 266x65
+                  text run at (1,37) width 166: "Here is some added"
+                  text run at (1,55) width 166: "content that will mess"
+                  text run at (1,84) width 266: "things up, since it shoves things down."
+              RenderText {#text} at (1,102) size 266x72
+                text run at (1,102) width 266: "This line of text should not get out of the"
+                text run at (1,120) width 266: "region. This line of text should not get out"
+                text run at (1,138) width 266: "of the region. This line of text should not"
+                text run at (1,156) width 131: "get out of the region."
+              RenderBR {BR} at (132,156) size 0x18
+              RenderBR {BR} at (1,174) size 0x18
+              RenderText {#text} at (1,192) size 266x126
+                text run at (1,192) width 266: "This line of text should not get out of the"
+                text run at (1,210) width 266: "region. This line of text should not get out"
+                text run at (1,228) width 266: "of the region. This line of text should not"
+                text run at (1,246) width 266: "get out of the region. This line of text"
+                text run at (1,264) width 86: "should not"
+                text run at (1,282) width 86: "get out of the"
+                text run at (1,300) width 44: "region."
+              RenderBR {BR} at (45,300) size 0x18
+              RenderBR {BR} at (1,318) size 0x18
+              RenderText {#text} at (1,336) size 86x84
+                text run at (1,336) width 86: "This line of"
+                text run at (1,354) width 86: "text should"
+                text run at (1,384) width 86: "not get out of"
+                text run at (1,402) width 67: "the region."
+              RenderBR {BR} at (68,402) size 0x18
+              RenderBR {BR} at (1,420) size 0x18
+  Regions for flow 'flow1'
+    RenderRegion {DIV} #region1 with index 0
+    RenderRegion {DIV} #region2 with index 0
+    RenderRegion {DIV} #region3 with index 0
index f20ef5e..423475b 100644 (file)
@@ -1,3 +1,29 @@
+2011-09-22  David Hyatt  <hyatt@apple.com>
+
+        https://bugs.webkit.org/show_bug.cgi?id=68658
+
+        Make matchedEndLine smart enough to not match lines that have moved to new
+        regions with different available content logical widths. When this happens, we go ahead and treat
+        the line as failing to match.
+
+        Reviewed by Anders Carlsson.
+
+        Added new tests in fast/regions.
+
+        * rendering/RenderBlock.cpp:
+        (WebCore::RenderBlock::lineWidthForPaginatedLineChanged):
+        * rendering/RenderBlock.h:
+        Enhanced to take an optional delta, so that you can check a new position without having to move
+        the line box.
+
+        * rendering/RenderBlockLineLayout.cpp:
+        (WebCore::RenderBlock::checkPaginationAndFloatsAtEndLine):
+        New function that refactors checking for line width changes from region movement as well as the
+        float checks. Since the float checks were duplicated twice, this is a nice refactoring.
+
+        (WebCore::RenderBlock::matchedEndLine):
+        Changed to call the new helper function that will check both floats and pagination.
+
 2011-09-22  Gavin Barraclough  <barraclough@apple.com>
 
         Implement Function.prototype.bind
index a8341c1..004e5a0 100644 (file)
@@ -6349,12 +6349,12 @@ LayoutUnit RenderBlock::adjustBlockChildForPagination(LayoutUnit logicalTopAfter
     return result;
 }
 
-bool RenderBlock::lineWidthForPaginatedLineChanged(RootInlineBox* rootBox) const
+bool RenderBlock::lineWidthForPaginatedLineChanged(RootInlineBox* rootBox, LayoutUnit lineDelta) const
 {
     if (!view()->hasRenderFlowThread() || view()->currentRenderFlowThread()->regionsHaveUniformLogicalWidth())
         return false;
 
-    return rootBox->paginatedLineWidth() != availableLogicalWidthForContent(rootBox->lineTopWithLeading());
+    return rootBox->paginatedLineWidth() != availableLogicalWidthForContent(rootBox->lineTopWithLeading() + lineDelta);
 }
 
 LayoutUnit RenderBlock::collapsedMarginBeforeForChild(RenderBox* child) const
index 83a9885..c97f638 100644 (file)
@@ -592,7 +592,8 @@ private:
     RootInlineBox* determineStartPosition(LineLayoutState&, InlineBidiResolver&);
     void determineEndPosition(LineLayoutState&, RootInlineBox* startBox, InlineIterator& cleanLineStart, BidiStatus& cleanLineBidiStatus);
     bool matchedEndLine(LineLayoutState&, const InlineBidiResolver&, const InlineIterator& endLineStart, const BidiStatus& endLineStatus);
-
+    bool checkPaginationAndFloatsAtEndLine(LineLayoutState&);
+    
     RootInlineBox* constructLine(BidiRunList<BidiRun>&, const LineInfo&);
     InlineFlowBox* createLineBoxes(RenderObject*, const LineInfo&, InlineBox* childBox);
 
@@ -831,7 +832,7 @@ private:
     // This function is called to test a line box that has moved in the block direction to see if it has ended up in a new
     // region/page/column that has a different available line width than the old one. Used to know when you have to dirty a
     // line, i.e., that it can't be re-used.
-    bool lineWidthForPaginatedLineChanged(RootInlineBox*) const;
+    bool lineWidthForPaginatedLineChanged(RootInlineBox*, LayoutUnit lineDelta = 0) const;
 
     struct FloatingObjectHashFunctions {
         static unsigned hash(FloatingObject* key) { return DefaultHash<RenderBox*>::Hash::hash(key->m_renderer); }
index 6a998cc..e01e751 100644 (file)
@@ -29,6 +29,7 @@
 #include "Logging.h"
 #include "RenderArena.h"
 #include "RenderCombineText.h"
+#include "RenderFlowThread.h"
 #include "RenderInline.h"
 #include "RenderLayer.h"
 #include "RenderListMarker.h"
@@ -1547,75 +1548,81 @@ void RenderBlock::determineEndPosition(LineLayoutState& layoutState, RootInlineB
     layoutState.setEndLine(last);
 }
 
-bool RenderBlock::matchedEndLine(LineLayoutState& layoutState, const InlineBidiResolver& resolver, const InlineIterator& endLineStart, const BidiStatus& endLineStatus)
+bool RenderBlock::checkPaginationAndFloatsAtEndLine(LineLayoutState& layoutState)
 {
-    if (resolver.position() == endLineStart) {
-        if (resolver.status() != endLineStatus)
-            return false;
+    LayoutUnit lineDelta = logicalHeight() - layoutState.endLineLogicalTop();
 
-        int delta = logicalHeight() - layoutState.endLineLogicalTop();
-        if (!delta || !m_floatingObjects)
-            return true;
+    bool paginated = view()->layoutState() && view()->layoutState()->isPaginated();
+    if (paginated && view()->hasRenderFlowThread() && !view()->currentRenderFlowThread()->regionsHaveUniformLogicalWidth()) {
+        // Check all lines from here to the end, and see if the hypothetical new position for the lines will result
+        // in a different available line width.
+        for (RootInlineBox* lineBox = layoutState.endLine(); lineBox; lineBox = lineBox->nextRootBox()) {
+            if (paginated) {
+                // This isn't the real move we're going to do, so don't update the line box's pagination
+                // strut yet.
+                LayoutUnit oldPaginationStrut = lineBox->paginationStrut();
+                lineDelta -= oldPaginationStrut;
+                adjustLinePositionForPagination(lineBox, lineDelta);
+                lineBox->setPaginationStrut(oldPaginationStrut);
+            }
+            if (lineWidthForPaginatedLineChanged(lineBox, lineDelta))
+                return false;
+        }
+    }
+    
+    if (!lineDelta || !m_floatingObjects)
+        return true;
+    
+    // See if any floats end in the range along which we want to shift the lines vertically.
+    int logicalTop = min(logicalHeight(), layoutState.endLineLogicalTop());
 
-        // See if any floats end in the range along which we want to shift the lines vertically.
-        int logicalTop = min(logicalHeight(), layoutState.endLineLogicalTop());
+    RootInlineBox* lastLine = layoutState.endLine();
+    while (RootInlineBox* nextLine = lastLine->nextRootBox())
+        lastLine = nextLine;
 
-        RootInlineBox* lastLine = layoutState.endLine();
-        while (RootInlineBox* nextLine = lastLine->nextRootBox())
-            lastLine = nextLine;
+    int logicalBottom = lastLine->lineBottomWithLeading() + abs(lineDelta);
 
-        int logicalBottom = lastLine->lineBottomWithLeading() + abs(delta);
+    const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
+    FloatingObjectSetIterator end = floatingObjectSet.end();
+    for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) {
+        FloatingObject* f = *it;
+        if (logicalBottomForFloat(f) >= logicalTop && logicalBottomForFloat(f) < logicalBottom)
+            return false;
+    }
 
-        const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
-        FloatingObjectSetIterator end = floatingObjectSet.end();
-        for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) {
-            FloatingObject* f = *it;
-            if (logicalBottomForFloat(f) >= logicalTop && logicalBottomForFloat(f) < logicalBottom)
-                return false;
-        }
+    return true;
+}
 
-        return true;
+bool RenderBlock::matchedEndLine(LineLayoutState& layoutState, const InlineBidiResolver& resolver, const InlineIterator& endLineStart, const BidiStatus& endLineStatus)
+{
+    if (resolver.position() == endLineStart) {
+        if (resolver.status() != endLineStatus)
+            return false;
+        return checkPaginationAndFloatsAtEndLine(layoutState);
     }
 
     // The first clean line doesn't match, but we can check a handful of following lines to try
     // to match back up.
     static int numLines = 8; // The # of lines we're willing to match against.
-    RootInlineBox* line = layoutState.endLine();
+    RootInlineBox* originalEndLine = layoutState.endLine();
+    RootInlineBox* line = originalEndLine;
     for (int i = 0; i < numLines && line; i++, line = line->nextRootBox()) {
         if (line->lineBreakObj() == resolver.position().m_obj && line->lineBreakPos() == resolver.position().m_pos) {
             // We have a match.
             if (line->lineBreakBidiStatus() != resolver.status())
                 return false; // ...but the bidi state doesn't match.
+            
+            bool matched = false;
             RootInlineBox* result = line->nextRootBox();
-
-            // Set our logical top to be the block height of endLine.
-            if (result)
+            if (result) {
                 layoutState.setEndLineLogicalTop(line->lineBottomWithLeading());
-
-            int delta = logicalHeight() - layoutState.endLineLogicalTop();
-            if (delta && m_floatingObjects) {
-                // See if any floats end in the range along which we want to shift the lines vertically.
-                int logicalTop = min(logicalHeight(), layoutState.endLineLogicalTop());
-
-                RootInlineBox* lastLine = layoutState.endLine();
-                while (RootInlineBox* nextLine = lastLine->nextRootBox())
-                    lastLine = nextLine;
-
-                int logicalBottom = lastLine->lineBottomWithLeading() + abs(delta);
-
-                const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
-                FloatingObjectSetIterator end = floatingObjectSet.end();
-                for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) {
-                    FloatingObject* f = *it;
-                    if (logicalBottomForFloat(f) >= logicalTop && logicalBottomForFloat(f) < logicalBottom)
-                        return false;
-                }
+                layoutState.setEndLine(result);
+                matched = checkPaginationAndFloatsAtEndLine(layoutState);
             }
 
             // Now delete the lines that we failed to sync.
-            deleteLineRange(layoutState, renderArena(), layoutState.endLine(), result);
-            layoutState.setEndLine(result);
-            return result;
+            deleteLineRange(layoutState, renderArena(), originalEndLine, result);
+            return matched;
         }
     }