Push through multiple regions when an object doesn't fit in any of them. Unlike with pages and
columns, when regions have a non-uniform height, we may need to push through multiple regions
in order to find one that fits.
Added an optimization for quickly noticing if regions do have a uniform height so that we can
treat them like columns and pages if so.
Also fixed the end line matchup to properly null out endLine when no next line box exists. The new
layout tests I wrote to cover this feature exposed this crasher, so fixing it in order to land
the new tests.
Reviewed by Anders Carlsson.
Source/WebCore:
Added new tests in fast/regions.
* rendering/RenderBlock.cpp:
(WebCore::RenderBlock::adjustForUnsplittableChild):
(WebCore::RenderBlock::pushToNextPageWithMinimumLogicalHeight):
(WebCore::RenderBlock::adjustLinePositionForPagination):
* rendering/RenderBlock.h:
* rendering/RenderBlockLineLayout.cpp:
(WebCore::RenderBlock::matchedEndLine):
* rendering/RenderFlowThread.cpp:
(WebCore::RenderFlowThread::RenderFlowThread):
(WebCore::RenderFlowThread::layout):
* rendering/RenderFlowThread.h:
LayoutTests:
* fast/regions/webkit-flow-float-pushed-to-last-region.html: Added.
* fast/regions/webkit-flow-float-unable-to-push.html: Added.
* platform/mac/fast/regions/webkit-flow-float-pushed-to-last-region-expected.png: Added.
* platform/mac/fast/regions/webkit-flow-float-pushed-to-last-region-expected.txt: Added.
* platform/mac/fast/regions/webkit-flow-float-unable-to-push-expected.png: Added.
* platform/mac/fast/regions/webkit-flow-float-unable-to-push-expected.txt: Added.
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@95855
268f45cc-cd09-0410-ab3c-
d52691b4dbfc
+2011-09-23 David Hyatt <hyatt@apple.com>
+
+ https://bugs.webkit.org/show_bug.cgi?id=68719
+
+ Push through multiple regions when an object doesn't fit in any of them. Unlike with pages and
+ columns, when regions have a non-uniform height, we may need to push through multiple regions
+ in order to find one that fits.
+
+ Added an optimization for quickly noticing if regions do have a uniform height so that we can
+ treat them like columns and pages if so.
+
+ Also fixed the end line matchup to properly null out endLine when no next line box exists. The new
+ layout tests I wrote to cover this feature exposed this crasher, so fixing it in order to land
+ the new tests.
+
+ Reviewed by Anders Carlsson.
+
+ * fast/regions/webkit-flow-float-pushed-to-last-region.html: Added.
+ * fast/regions/webkit-flow-float-unable-to-push.html: Added.
+ * platform/mac/fast/regions/webkit-flow-float-pushed-to-last-region-expected.png: Added.
+ * platform/mac/fast/regions/webkit-flow-float-pushed-to-last-region-expected.txt: Added.
+ * platform/mac/fast/regions/webkit-flow-float-unable-to-push-expected.png: Added.
+ * platform/mac/fast/regions/webkit-flow-float-unable-to-push-expected.txt: Added.
+
2011-09-23 Konstantin Scheglov <scheglov@google.com>
Redrawing dirty parts of a large table is very slow
--- /dev/null
+<!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;
+ }
+
+ #float1 {
+ float: right;
+ width: 130px;
+ height: 100px;
+ background-color:green
+ }
+
+ #region1, #region2, #region3 {
+ border: 1px solid black;
+ content: -webkit-from-flow("flow1");
+ }
+
+ #region1 {
+ width: 400px;
+ height: 100px;
+ }
+
+ #region2 {
+ width: 300px;
+ height: 90px;
+ }
+
+ #region3 {
+ width: 400px;
+ height: 300px;
+ }
+</style>
+
+<div id="content">
+ <div id="first-box">
+ <div id="second-box">
+ <p>This line of text <img id="float1"> 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.</p>
+ <p>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.</p>
+ <p>This line of text should not get out of the region.</p>
+ </div>
+ </div>
+</div>
+
+<div id="container">
+ <div id="region1"></div>
+ <div id="region2"></div>
+ <div id="region3"></div>
+</div>
--- /dev/null
+<!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;
+ }
+
+ #float1 {
+ float: right;
+ width: 130px;
+ height: 100px;
+ background-color:green
+ }
+
+ #region1, #region2, #region3 {
+ border: 1px solid black;
+ content: -webkit-from-flow("flow1");
+ }
+
+ #region1 {
+ width: 400px;
+ height: 90px;
+ }
+
+ #region2 {
+ width: 300px;
+ height: 90px;
+ }
+
+ #region3 {
+ width: 400px;
+ height: 90px;
+ }
+</style>
+
+<div id="content">
+ <div id="first-box">
+ <div id="second-box">
+ <p>This line of text <img id="float1"> 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.</p>
+ <p>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.</p>
+ <p>This line of text should not get out of the region.</p>
+ </div>
+ </div>
+</div>
+
+<div id="container">
+ <div id="region1"></div>
+ <div id="region2"></div>
+ <div id="region3"></div>
+</div>
--- /dev/null
+layer at (0,0) size 800x600
+ RenderView at (0,0) size 800x600
+layer at (0,0) size 800x512
+ RenderBlock {HTML} at (0,0) size 800x512
+ RenderBody {BODY} at (8,8) size 784x496
+ RenderBlock {DIV} at (0,0) size 784x496
+ RenderRegion {DIV} at (0,0) size 402x102 [border: (1px solid #000000)]
+ RenderRegion {DIV} at (0,102) size 302x92 [border: (1px solid #000000)]
+ RenderRegion {DIV} at (0,194) size 402x302 [border: (1px solid #000000)]
+Flow Threads
+ Thread with flow-name 'flow1'
+ layer at (0,0) size 400x490
+ RenderFlowThread at (0,0) size 400x490
+ RenderBlock {DIV} at (0,0) size 400x453
+ RenderBlock {DIV} at (5,5) size 390x443 [border: (1px solid #0000FF)]
+ RenderBlock {DIV} at (11,11) size 368x421 [border: (1px solid #008000)]
+ RenderBlock {P} at (1,17) size 366x265
+ RenderText {#text} at (0,157) size 104x18
+ text run at (0,157) width 104: "This line of text "
+ RenderImage {IMG} at (236,157) size 130x100 [bgcolor=#008000]
+ RenderText {#text} at (104,157) size 236x108
+ text run at (104,157) width 132: "should not get out of"
+ text run at (0,175) width 26: "the "
+ text run at (26,175) width 210: "region. This line of text should"
+ text run at (0,193) width 236: "not get out of the region. This line of"
+ text run at (0,211) width 236: "text should not get out of the region."
+ text run at (0,229) width 236: "This line of text should not get out of"
+ text run at (0,247) width 67: "the region."
+ RenderBlock {P} at (1,298) size 366x72
+ RenderText {#text} at (0,0) size 366x72
+ text run at (0,0) width 366: "This line of text should not get out of the region. This line"
+ text run at (0,18) width 366: "of text should not get out of the region. This line of text"
+ text run at (0,36) width 366: "should not get out of the region. This line of text should"
+ text run at (0,54) width 155: "not get out of the region."
+ RenderBlock {P} at (1,386) size 366x18
+ RenderText {#text} at (0,0) size 304x18
+ text run at (0,0) width 304: "This line of text should not get out of the region."
+ Regions for flow 'flow1'
+ RenderRegion {DIV} #region1 with index 0
+ RenderRegion {DIV} #region2 with index 0
+ RenderRegion {DIV} #region3 with index 0
--- /dev/null
+layer at (0,0) size 800x600
+ RenderView at (0,0) size 800x600
+layer at (0,0) size 800x292
+ RenderBlock {HTML} at (0,0) size 800x292
+ RenderBody {BODY} at (8,8) size 784x276
+ RenderBlock {DIV} at (0,0) size 784x276
+ RenderRegion {DIV} at (0,0) size 402x92 [border: (1px solid #000000)]
+ RenderRegion {DIV} at (0,92) size 302x92 [border: (1px solid #000000)]
+ RenderRegion {DIV} at (0,184) size 402x92 [border: (1px solid #000000)]
+Flow Threads
+ Thread with flow-name 'flow1'
+ layer at (0,0) size 400x270
+ RenderFlowThread at (0,0) size 400x270
+ RenderBlock {DIV} at (0,0) size 400x301
+ RenderBlock {DIV} at (5,5) size 390x291 [border: (1px solid #0000FF)]
+ RenderBlock {DIV} at (11,11) size 368x269 [border: (1px solid #008000)]
+ RenderBlock {P} at (1,17) size 366x111
+ RenderText {#text} at (0,0) size 104x18
+ text run at (0,0) width 104: "This line of text "
+ RenderImage {IMG} at (236,0) size 130x100 [bgcolor=#008000]
+ RenderText {#text} at (104,0) size 236x111
+ text run at (104,0) width 132: "should not get out of"
+ text run at (0,18) width 26: "the "
+ text run at (26,18) width 210: "region. This line of text should"
+ text run at (0,36) width 236: "not get out of the region. This line of"
+ text run at (0,57) width 236: "text should not get out of the region."
+ text run at (0,75) width 236: "This line of text should not get out of"
+ text run at (0,93) width 67: "the region."
+ RenderBlock {P} at (1,144) size 366x74
+ RenderText {#text} at (0,0) size 366x74
+ text run at (0,0) width 266: "This line of text should not get out of the"
+ text run at (0,20) width 366: "region. This line of text should not get out of the region."
+ text run at (0,38) width 366: "This line of text should not get out of the region. This line"
+ text run at (0,56) width 245: "of text should not get out of the region."
+ RenderBlock {P} at (1,234) size 366x18
+ RenderText {#text} at (0,0) size 304x18
+ text run at (0,0) width 304: "This line of text should not get out of the region."
+ Regions for flow 'flow1'
+ RenderRegion {DIV} #region1 with index 0
+ RenderRegion {DIV} #region2 with index 0
+ RenderRegion {DIV} #region3 with index 0
+2011-09-23 David Hyatt <hyatt@apple.com>
+
+ https://bugs.webkit.org/show_bug.cgi?id=68719
+
+ Push through multiple regions when an object doesn't fit in any of them. Unlike with pages and
+ columns, when regions have a non-uniform height, we may need to push through multiple regions
+ in order to find one that fits.
+
+ Added an optimization for quickly noticing if regions do have a uniform height so that we can
+ treat them like columns and pages if so.
+
+ Also fixed the end line matchup to properly null out endLine when no next line box exists. The new
+ layout tests I wrote to cover this feature exposed this crasher, so fixing it in order to land
+ the new tests.
+
+ Reviewed by Anders Carlsson.
+
+ Added new tests in fast/regions.
+
+ * rendering/RenderBlock.cpp:
+ (WebCore::RenderBlock::adjustForUnsplittableChild):
+ (WebCore::RenderBlock::pushToNextPageWithMinimumLogicalHeight):
+ (WebCore::RenderBlock::adjustLinePositionForPagination):
+ * rendering/RenderBlock.h:
+ * rendering/RenderBlockLineLayout.cpp:
+ (WebCore::RenderBlock::matchedEndLine):
+ * rendering/RenderFlowThread.cpp:
+ (WebCore::RenderFlowThread::RenderFlowThread):
+ (WebCore::RenderFlowThread::layout):
+ * rendering/RenderFlowThread.h:
+
2011-09-23 Konstantin Scheglov <scheglov@google.com>
Redrawing dirty parts of a large table is very slow
if (layoutState->m_columnInfo)
layoutState->m_columnInfo->updateMinimumColumnHeight(childLogicalHeight);
LayoutUnit pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset);
- if (!pageLogicalHeight || (childLogicalHeight > pageLogicalHeight && !view()->hasRenderFlowThread()))
+ bool hasUniformPageLogicalHeight = !view()->hasRenderFlowThread() || view()->currentRenderFlowThread()->regionsHaveUniformLogicalHeight();
+ if (!pageLogicalHeight || (hasUniformPageLogicalHeight && childLogicalHeight > pageLogicalHeight))
return logicalOffset;
LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(logicalOffset);
- if (remainingLogicalHeight < childLogicalHeight)
+ if (remainingLogicalHeight < childLogicalHeight) {
+ if (!hasUniformPageLogicalHeight && !pushToNextPageWithMinimumLogicalHeight(remainingLogicalHeight, logicalOffset, childLogicalHeight))
+ return logicalOffset;
return logicalOffset + remainingLogicalHeight;
+ }
return logicalOffset;
}
+bool RenderBlock::pushToNextPageWithMinimumLogicalHeight(LayoutUnit& adjustment, LayoutUnit logicalOffset, LayoutUnit minimumLogicalHeight) const
+{
+ bool checkedRegion = false;
+ for (LayoutUnit pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset + adjustment); pageLogicalHeight;
+ pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset + adjustment)) {
+ if (minimumLogicalHeight <= pageLogicalHeight)
+ return true;
+ adjustment += pageLogicalHeight;
+ checkedRegion = true;
+ }
+ return !checkedRegion;
+}
+
void RenderBlock::adjustLinePositionForPagination(RootInlineBox* lineBox, LayoutUnit& delta)
{
// FIXME: For now we paginate using line overflow. This ensures that lines don't overlap at all when we
logicalOffset += delta;
lineBox->setPaginationStrut(0);
LayoutUnit pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset);
- if (!pageLogicalHeight || (lineHeight > pageLogicalHeight && !renderView->hasRenderFlowThread()))
+ bool hasUniformPageLogicalHeight = !view()->hasRenderFlowThread() || view()->currentRenderFlowThread()->regionsHaveUniformLogicalHeight();
+ if (!pageLogicalHeight || (hasUniformPageLogicalHeight && lineHeight > pageLogicalHeight))
return;
const bool includeBoundaryPoint = false;
LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(logicalOffset, includeBoundaryPoint);
if (remainingLogicalHeight < lineHeight) {
+ // If we have a non-uniform page height, then we have to shift further possibly.
+ if (!hasUniformPageLogicalHeight && !pushToNextPageWithMinimumLogicalHeight(remainingLogicalHeight, logicalOffset, lineHeight))
+ return;
LayoutUnit totalLogicalHeight = lineHeight + max<LayoutUnit>(0, logicalOffset);
- if (lineBox == firstRootBox() && totalLogicalHeight < pageLogicalHeight && !isPositioned() && !isTableCell())
+ LayoutUnit pageLogicalHeightAtNewOffset = hasUniformPageLogicalHeight ? pageLogicalHeight : pageLogicalHeightForOffset(logicalOffset + remainingLogicalHeight);
+ if (lineBox == firstRootBox() && totalLogicalHeight < pageLogicalHeightAtNewOffset && !isPositioned() && !isTableCell())
setPaginationStrut(remainingLogicalHeight + max<LayoutUnit>(0, logicalOffset));
else {
delta += remainingLogicalHeight;
LayoutUnit logicalPageOffset() const;
LayoutUnit pageLogicalHeightForOffset(LayoutUnit offset) const;
LayoutUnit pageRemainingLogicalHeightForOffset(LayoutUnit offset, bool includeBoundaryPoint = true) const;
+ bool pushToNextPageWithMinimumLogicalHeight(LayoutUnit& adjustment, LayoutUnit logicalOffset, LayoutUnit minimumLogicalHeight) const;
LayoutUnit adjustForUnsplittableChild(RenderBox* child, LayoutUnit logicalOffset, bool includeMargins = false); // If the child is unsplittable and can't fit on the current page, return the top of the next page/column.
void adjustLinePositionForPagination(RootInlineBox*, LayoutUnit& deltaOffset); // Computes a deltaOffset value that put a line at the top of the next page if it doesn't fit on the current page.
bool matched = false;
RootInlineBox* result = line->nextRootBox();
+ layoutState.setEndLine(result);
if (result) {
layoutState.setEndLineLogicalTop(line->lineBottomWithLeading());
- layoutState.setEndLine(result);
matched = checkPaginationAndFloatsAtEndLine(layoutState);
}
, m_hasValidRegions(false)
, m_regionsInvalidated(false)
, m_regionsHaveUniformLogicalWidth(true)
+ , m_regionsHaveUniformLogicalHeight(true)
, m_regionFittingDisableCount(0)
{
setIsAnonymous(false);
m_regionsInvalidated = false;
m_hasValidRegions = false;
m_regionsHaveUniformLogicalWidth = true;
+ m_regionsHaveUniformLogicalHeight = true;
LayoutUnit previousRegionLogicalWidth = 0;
+ LayoutUnit previousRegionLogicalHeight = 0;
if (hasRegions()) {
int logicalHeight = 0;
for (RenderRegionList::iterator iter = m_regionList.begin(); iter != m_regionList.end(); ++iter) {
ASSERT(!region->needsLayout());
LayoutUnit regionLogicalWidth;
+ LayoutUnit regionLogicalHeight;
IntRect regionRect;
if (isHorizontalWritingMode()) {
regionRect = IntRect(0, logicalHeight, region->contentWidth(), region->contentHeight());
logicalHeight += regionRect.height();
regionLogicalWidth = region->contentWidth();
+ regionLogicalHeight = region->contentHeight();
} else {
regionRect = IntRect(logicalHeight, 0, region->contentWidth(), region->contentHeight());
logicalHeight += regionRect.width();
regionLogicalWidth = region->contentHeight();
+ regionLogicalHeight = region->contentWidth();
}
if (!m_hasValidRegions)
m_hasValidRegions = true;
- else if (m_regionsHaveUniformLogicalWidth && previousRegionLogicalWidth != regionLogicalWidth)
- m_regionsHaveUniformLogicalWidth = false;
+ else {
+ if (m_regionsHaveUniformLogicalWidth && previousRegionLogicalWidth != regionLogicalWidth)
+ m_regionsHaveUniformLogicalWidth = false;
+ if (m_regionsHaveUniformLogicalHeight && previousRegionLogicalHeight != regionLogicalHeight)
+ m_regionsHaveUniformLogicalHeight = false;
+ }
previousRegionLogicalWidth = regionLogicalWidth;
void enableRegionFitting() { ASSERT(m_regionFittingDisableCount > 0); m_regionFittingDisableCount--; }
bool regionsHaveUniformLogicalWidth() const { return m_regionsHaveUniformLogicalWidth; }
-
+ bool regionsHaveUniformLogicalHeight() const { return m_regionsHaveUniformLogicalHeight; }
+
RenderRegion* mapFromFlowToRegion(TransformState&) const;
private:
bool m_hasValidRegions;
bool m_regionsInvalidated;
bool m_regionsHaveUniformLogicalWidth;
+ bool m_regionsHaveUniformLogicalHeight;
unsigned m_regionFittingDisableCount;
};