Source/WebCore: https://bugs.webkit.org/show_bug.cgi?id=76197
authorhyatt@apple.com <hyatt@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 17 Jan 2012 19:16:24 +0000 (19:16 +0000)
committerhyatt@apple.com <hyatt@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 17 Jan 2012 19:16:24 +0000 (19:16 +0000)
Implementation of baseline grid alignment. This patch implements line grid tracking in the layout state,
and also implements the snapping of lines to baselines. It works with normal flow, positioning and floats and
with pagination, as long as the grid is inside the pagination context and not outside.

Reviewed by Simon Fraser.

Added a bunch of new tests in fast/line-grid.

* WebCore.xcodeproj/project.pbxproj:
* rendering/InlineFlowBox.h:
(WebCore::InlineFlowBox::setHasTextChildren):
* rendering/LayoutState.cpp:
(WebCore::LayoutState::LayoutState):
(WebCore::LayoutState::propagateLineGridInfo):
(WebCore::LayoutState::establishLineGrid):
* rendering/LayoutState.h:
(WebCore::LayoutState::LayoutState):
(WebCore::LayoutState::pageLogicalHeight):
(WebCore::LayoutState::currentLineGrid):
(WebCore::LayoutState::currentLineGridOffset):
(WebCore::LayoutState::layoutOffset):
(WebCore::LayoutState::needsBlockDirectionLocationSetBeforeLayout):
* rendering/RenderBlock.cpp:
(WebCore::RenderBlock::layoutBlockChildren):
(WebCore::RenderBlock::layoutPositionedObjects):
(WebCore::RenderBlock::insertFloatingObject):
(WebCore::RenderBlock::positionNewFloats):
(WebCore::RenderBlock::pageLogicalTopForOffset):
(WebCore::RenderBlock::adjustLinePositionForPagination):
* rendering/RenderBlock.h:
(WebCore::RenderBlock::lineGridBox):
(WebCore::RenderBlock::setLineGridBox):
(WebCore::RenderBlock::RenderBlockRareData::RenderBlockRareData):
* rendering/RenderBlockLineLayout.cpp:
(WebCore::RenderBlock::layoutInlineChildren):
(WebCore::RenderBlock::layoutLineGridBox):
* rendering/RenderFlowThread.cpp:
(WebCore::RenderFlowThread::regionLogicalTopForLine):
* rendering/RenderFlowThread.h:
* rendering/RenderView.h:
(WebCore::RenderView::pushLayoutState):
* rendering/RootInlineBox.cpp:
(WebCore::RootInlineBox::alignBoxesInBlockDirection):
(WebCore::RootInlineBox::lineGridSnapAdjustment):
* rendering/RootInlineBox.h:

LayoutTests: https://bugs.webkit.org/show_bug.cgi?id=76197

Add tests for baseline line grid alignment.

Reviewed by Simon Fraser.

* fast/line-grid/line-grid-floating.html: Added.
* fast/line-grid/line-grid-inside-columns.html: Added.
* fast/line-grid/line-grid-into-floats.html: Added.
* fast/line-grid/line-grid-positioned.html: Added.
* platform/mac/fast/line-grid: Added.
* platform/mac/fast/line-grid/line-grid-floating-expected.png: Added.
* platform/mac/fast/line-grid/line-grid-floating-expected.txt: Added.
* platform/mac/fast/line-grid/line-grid-inside-columns-expected.png: Added.
* platform/mac/fast/line-grid/line-grid-inside-columns-expected.txt: Added.
* platform/mac/fast/line-grid/line-grid-into-floats-expected.png: Added.
* platform/mac/fast/line-grid/line-grid-into-floats-expected.txt: Added.
* platform/mac/fast/line-grid/line-grid-positioned-expected.png: Added.
* platform/mac/fast/line-grid/line-grid-positioned-expected.txt: Added.

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

25 files changed:
LayoutTests/ChangeLog
LayoutTests/fast/line-grid/line-grid-floating.html [new file with mode: 0644]
LayoutTests/fast/line-grid/line-grid-inside-columns.html [new file with mode: 0644]
LayoutTests/fast/line-grid/line-grid-into-floats.html [new file with mode: 0644]
LayoutTests/fast/line-grid/line-grid-positioned.html [new file with mode: 0644]
LayoutTests/platform/mac/fast/line-grid/line-grid-floating-expected.png [new file with mode: 0644]
LayoutTests/platform/mac/fast/line-grid/line-grid-floating-expected.txt [new file with mode: 0644]
LayoutTests/platform/mac/fast/line-grid/line-grid-inside-columns-expected.png [new file with mode: 0644]
LayoutTests/platform/mac/fast/line-grid/line-grid-inside-columns-expected.txt [new file with mode: 0644]
LayoutTests/platform/mac/fast/line-grid/line-grid-into-floats-expected.png [new file with mode: 0644]
LayoutTests/platform/mac/fast/line-grid/line-grid-into-floats-expected.txt [new file with mode: 0644]
LayoutTests/platform/mac/fast/line-grid/line-grid-positioned-expected.png [new file with mode: 0644]
LayoutTests/platform/mac/fast/line-grid/line-grid-positioned-expected.txt [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/rendering/InlineFlowBox.h
Source/WebCore/rendering/LayoutState.cpp
Source/WebCore/rendering/LayoutState.h
Source/WebCore/rendering/RenderBlock.cpp
Source/WebCore/rendering/RenderBlock.h
Source/WebCore/rendering/RenderBlockLineLayout.cpp
Source/WebCore/rendering/RenderFlowThread.cpp
Source/WebCore/rendering/RenderFlowThread.h
Source/WebCore/rendering/RenderView.h
Source/WebCore/rendering/RootInlineBox.cpp
Source/WebCore/rendering/RootInlineBox.h

index f172f21..401fd4b 100644 (file)
@@ -1,3 +1,25 @@
+2012-01-12  David Hyatt  <hyatt@apple.com>
+
+        https://bugs.webkit.org/show_bug.cgi?id=76197
+        
+        Add tests for baseline line grid alignment.
+
+        Reviewed by Simon Fraser.
+
+        * fast/line-grid/line-grid-floating.html: Added.
+        * fast/line-grid/line-grid-inside-columns.html: Added.
+        * fast/line-grid/line-grid-into-floats.html: Added.
+        * fast/line-grid/line-grid-positioned.html: Added.
+        * platform/mac/fast/line-grid: Added.
+        * platform/mac/fast/line-grid/line-grid-floating-expected.png: Added.
+        * platform/mac/fast/line-grid/line-grid-floating-expected.txt: Added.
+        * platform/mac/fast/line-grid/line-grid-inside-columns-expected.png: Added.
+        * platform/mac/fast/line-grid/line-grid-inside-columns-expected.txt: Added.
+        * platform/mac/fast/line-grid/line-grid-into-floats-expected.png: Added.
+        * platform/mac/fast/line-grid/line-grid-into-floats-expected.txt: Added.
+        * platform/mac/fast/line-grid/line-grid-positioned-expected.png: Added.
+        * platform/mac/fast/line-grid/line-grid-positioned-expected.txt: Added.
+
 2012-01-17  Tim Horton  <timothy_horton@apple.com>
 
         -webkit-cross-fade doesn't respect background-size
diff --git a/LayoutTests/fast/line-grid/line-grid-floating.html b/LayoutTests/fast/line-grid/line-grid-floating.html
new file mode 100644 (file)
index 0000000..66a8378
--- /dev/null
@@ -0,0 +1,26 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<style>
+.grid { -webkit-line-grid: simple; -webkit-line-grid-snap: baseline; 
+        font-size:36px; float:left;border:2px solid black;
+        padding:10px; margin:5px }
+</style>
+</head>
+<body>
+<div class="grid">
+<div style="font-size:12px">
+This text should snap<br>
+to a 36px font-size grid.<br>
+There should be lots of spacing between these lines.
+</div>
+</div>
+
+<div class="grid">
+This text should snap<br>
+to a 36px font-size grid.<br>
+</div>
+</div>
+
+</body>
+</html>
diff --git a/LayoutTests/fast/line-grid/line-grid-inside-columns.html b/LayoutTests/fast/line-grid/line-grid-inside-columns.html
new file mode 100644 (file)
index 0000000..4af3acd
--- /dev/null
@@ -0,0 +1,48 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<style>
+.grid { -webkit-line-grid: simple; -webkit-line-grid-snap: baseline; 
+        font-size:36px; }</style>
+</head>
+<body>
+
+<div style="height:500px; border:2px solid red; -webkit-column-count:2;">
+<div class="grid">
+<div style="font-size:16px">
+All of this text even though it's smaller should be on the 36px
+grid. The grid should reset at the top of the second column.<br>
+All of this text even though it's smaller should be on the 36px
+grid. The grid should reset at the top of the second column.<br>
+All of this text even though it's smaller should be on the 36px
+grid. The grid should reset at the top of the second column.<br>
+</div>
+<div style="font-size:24px">
+All of this text even though it's smaller should be on the 36px
+grid. The grid should reset at the top of the second column.<br>
+All of this text even though it's smaller should be on the 36px
+grid. The grid should reset at the top of the second column.<br>
+All of this text even though it's smaller should be on the 36px
+grid. The grid should reset at the top of the second column.<br>
+</div>
+<div style="font-size:10px">
+All of this text even though it's smaller should be on the 36px
+grid. The grid should reset at the top of the second column.<br>
+All of this text even though it's smaller should be on the 36px
+grid. The grid should reset at the top of the second column.<br>
+All of this text even though it's smaller should be on the 36px
+grid. The grid should reset at the top of the second column.<br>
+</div>
+<div style="font-size:18px">
+All of this text even though it's smaller should be on the 36px
+grid. The grid should reset at the top of the second column.<br>
+All of this text even though it's smaller should be on the 36px
+grid. The grid should reset at the top of the second column.<br>
+All of this text even though it's smaller should be on the 36px
+grid. The grid should reset at the top of the second column.<br>
+</div>
+</div>
+</div>
+</div>
+</body>
+</html>
diff --git a/LayoutTests/fast/line-grid/line-grid-into-floats.html b/LayoutTests/fast/line-grid/line-grid-into-floats.html
new file mode 100644 (file)
index 0000000..aa55510
--- /dev/null
@@ -0,0 +1,27 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<style>
+.grid { -webkit-line-grid: simple; -webkit-line-grid-snap: baseline; 
+        font-size:36px; 
+        padding:10px; }
+</style>
+</head>
+<body class="grid">
+<div style="float:left;font-size:12px;border:2px solid black; margin:5px">
+This text should snap<br>
+to a 36px font-size grid.<br>
+There should be lots of spacing between these lines.
+</div>
+
+<div style="float:left;font-size:20px;border:2px solid black; margin:5px">
+This text should snap<br>
+to a 36px font-size grid.<br>
+</div>
+
+Here we can see the actual lines of the grid outside of the floating
+objects. Everything should be aligned to these lines, including what
+is inside the two floats. 
+
+</body>
+</html>
diff --git a/LayoutTests/fast/line-grid/line-grid-positioned.html b/LayoutTests/fast/line-grid/line-grid-positioned.html
new file mode 100644 (file)
index 0000000..078c817
--- /dev/null
@@ -0,0 +1,26 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<style>
+.grid { -webkit-line-grid: simple; -webkit-line-grid-snap: baseline; 
+        font-size:36px; position:absolute;border:2px solid black;
+        padding:10px; }
+</style>
+</head>
+<body>
+<div style="left:10px; top:10px" class="grid">
+<div style="font-size:12px">
+This text should snap<br>
+to a 36px font-size grid.<br>
+There should be lots of spacing between these lines.
+</div>
+</div>
+
+<div style="left:350px; top:10px" class="grid">
+This text should snap<br>
+to a 36px font-size grid.<br>
+</div>
+</div>
+
+</body>
+</html>
diff --git a/LayoutTests/platform/mac/fast/line-grid/line-grid-floating-expected.png b/LayoutTests/platform/mac/fast/line-grid/line-grid-floating-expected.png
new file mode 100644 (file)
index 0000000..7ace91a
Binary files /dev/null and b/LayoutTests/platform/mac/fast/line-grid/line-grid-floating-expected.png differ
diff --git a/LayoutTests/platform/mac/fast/line-grid/line-grid-floating-expected.txt b/LayoutTests/platform/mac/fast/line-grid/line-grid-floating-expected.txt
new file mode 100644 (file)
index 0000000..041afa7
--- /dev/null
@@ -0,0 +1,22 @@
+layer at (0,0) size 800x600
+  RenderView at (0,0) size 800x600
+layer at (0,0) size 800x600
+  RenderBlock {HTML} at (0,0) size 800x600
+    RenderBody {BODY} at (8,8) size 784x584
+      RenderBlock (floating) {DIV} at (5,5) size 269x141 [border: (2px solid #000000)]
+        RenderBlock {DIV} at (12,12) size 245x117
+          RenderText {#text} at (0,21) size 101x14
+            text run at (0,21) width 101: "This text should snap"
+          RenderBR {BR} at (101,32) size 0x0
+          RenderText {#text} at (0,62) size 113x14
+            text run at (0,62) width 113: "to a 36px font-size grid."
+          RenderBR {BR} at (113,73) size 0x0
+          RenderText {#text} at (0,103) size 245x14
+            text run at (0,103) width 245: "There should be lots of spacing between these lines."
+      RenderBlock (floating) {DIV} at (284,5) size 369x106 [border: (2px solid #000000)]
+        RenderText {#text} at (12,12) size 307x41
+          text run at (12,12) width 307: "This text should snap"
+        RenderBR {BR} at (319,44) size 0x0
+        RenderText {#text} at (12,53) size 345x41
+          text run at (12,53) width 345: "to a 36px font-size grid."
+        RenderBR {BR} at (357,85) size 0x0
diff --git a/LayoutTests/platform/mac/fast/line-grid/line-grid-inside-columns-expected.png b/LayoutTests/platform/mac/fast/line-grid/line-grid-inside-columns-expected.png
new file mode 100644 (file)
index 0000000..f178fbe
Binary files /dev/null and b/LayoutTests/platform/mac/fast/line-grid/line-grid-inside-columns-expected.png differ
diff --git a/LayoutTests/platform/mac/fast/line-grid/line-grid-inside-columns-expected.txt b/LayoutTests/platform/mac/fast/line-grid/line-grid-inside-columns-expected.txt
new file mode 100644 (file)
index 0000000..3dacc16
--- /dev/null
@@ -0,0 +1,72 @@
+layer at (0,0) size 1188x585
+  RenderView at (0,0) size 800x585
+layer at (0,0) size 800x585
+  RenderBlock {HTML} at (0,0) size 800x585
+    RenderBody {BODY} at (8,8) size 784x569
+layer at (8,8) size 784x504
+  RenderBlock {DIV} at (0,0) size 784x504 [border: (2px solid #FF0000)]
+    RenderBlock {DIV} at (2,2) size 382x1488
+      RenderBlock {DIV} at (0,0) size 382x364
+        RenderText {#text} at (0,18) size 352x100
+          text run at (0,18) width 350: "All of this text even though it's smaller should be on the"
+          text run at (0,59) width 352: "36px grid. The grid should reset at the top of the second"
+          text run at (0,100) width 51: "column."
+        RenderBR {BR} at (51,114) size 0x0
+        RenderText {#text} at (0,141) size 352x100
+          text run at (0,141) width 350: "All of this text even though it's smaller should be on the"
+          text run at (0,182) width 352: "36px grid. The grid should reset at the top of the second"
+          text run at (0,223) width 51: "column."
+        RenderBR {BR} at (51,237) size 0x0
+        RenderText {#text} at (0,264) size 352x100
+          text run at (0,264) width 350: "All of this text even though it's smaller should be on the"
+          text run at (0,305) width 352: "36px grid. The grid should reset at the top of the second"
+          text run at (0,346) width 51: "column."
+        RenderBR {BR} at (51,360) size 0x0
+      RenderBlock {DIV} at (0,364) size 382x502
+        RenderText {#text} at (0,15) size 377x159
+          text run at (0,15) width 377: "All of this text even though it's smaller"
+          text run at (0,56) width 353: "should be on the 36px grid. The grid"
+          text run at (0,97) width 348: "should reset at the top of the second"
+          text run at (0,146) width 79: "column."
+        RenderBR {BR} at (79,168) size 0x0
+        RenderText {#text} at (0,187) size 377x151
+          text run at (0,187) width 377: "All of this text even though it's smaller"
+          text run at (0,228) width 353: "should be on the 36px grid. The grid"
+          text run at (0,269) width 348: "should reset at the top of the second"
+          text run at (0,310) width 79: "column."
+        RenderBR {BR} at (79,332) size 0x0
+        RenderText {#text} at (0,351) size 377x151
+          text run at (0,351) width 377: "All of this text even though it's smaller"
+          text run at (0,392) width 353: "should be on the 36px grid. The grid"
+          text run at (0,433) width 348: "should reset at the top of the second"
+          text run at (0,474) width 79: "column."
+        RenderBR {BR} at (79,496) size 0x0
+      RenderBlock {DIV} at (0,866) size 382x251
+        RenderText {#text} at (0,25) size 372x54
+          text run at (0,25) width 372: "All of this text even though it's smaller should be on the 36px grid. The grid should reset at"
+          text run at (0,66) width 120: "the top of the second column."
+        RenderBR {BR} at (120,76) size 0x0
+        RenderText {#text} at (0,107) size 372x62
+          text run at (0,107) width 372: "All of this text even though it's smaller should be on the 36px grid. The grid should reset at"
+          text run at (0,156) width 120: "the top of the second column."
+        RenderBR {BR} at (120,166) size 0x0
+        RenderText {#text} at (0,197) size 372x54
+          text run at (0,197) width 372: "All of this text even though it's smaller should be on the 36px grid. The grid should reset at"
+          text run at (0,238) width 120: "the top of the second column."
+        RenderBR {BR} at (120,248) size 0x0
+      RenderBlock {DIV} at (0,1117) size 382x371
+        RenderText {#text} at (0,21) size 381x104
+          text run at (0,21) width 381: "All of this text even though it's smaller should be on"
+          text run at (0,62) width 381: "the 36px grid. The grid should reset at the top of the"
+          text run at (0,103) width 114: "second column."
+        RenderBR {BR} at (114,120) size 0x0
+        RenderText {#text} at (0,144) size 381x104
+          text run at (0,144) width 381: "All of this text even though it's smaller should be on"
+          text run at (0,185) width 381: "the 36px grid. The grid should reset at the top of the"
+          text run at (0,226) width 114: "second column."
+        RenderBR {BR} at (114,243) size 0x0
+        RenderText {#text} at (0,267) size 381x104
+          text run at (0,267) width 381: "All of this text even though it's smaller should be on"
+          text run at (0,308) width 381: "the 36px grid. The grid should reset at the top of the"
+          text run at (0,349) width 114: "second column."
+        RenderBR {BR} at (114,366) size 0x0
diff --git a/LayoutTests/platform/mac/fast/line-grid/line-grid-into-floats-expected.png b/LayoutTests/platform/mac/fast/line-grid/line-grid-into-floats-expected.png
new file mode 100644 (file)
index 0000000..3b7fed2
Binary files /dev/null and b/LayoutTests/platform/mac/fast/line-grid/line-grid-into-floats-expected.png differ
diff --git a/LayoutTests/platform/mac/fast/line-grid/line-grid-into-floats-expected.txt b/LayoutTests/platform/mac/fast/line-grid/line-grid-into-floats-expected.txt
new file mode 100644 (file)
index 0000000..1c5ca8b
--- /dev/null
@@ -0,0 +1,28 @@
+layer at (0,0) size 800x600
+  RenderView at (0,0) size 800x600
+layer at (0,0) size 800x600
+  RenderBlock {HTML} at (0,0) size 800x600
+    RenderBody {BODY} at (8,8) size 784x584
+      RenderBlock (floating) {DIV} at (15,15) size 249x114 [border: (2px solid #000000)]
+        RenderText {#text} at (2,16) size 101x14
+          text run at (2,16) width 101: "This text should snap"
+        RenderBR {BR} at (103,27) size 0x0
+        RenderText {#text} at (2,57) size 113x14
+          text run at (2,57) width 113: "to a 36px font-size grid."
+        RenderBR {BR} at (115,68) size 0x0
+        RenderText {#text} at (2,98) size 245x14
+          text run at (2,98) width 245: "There should be lots of spacing between these lines."
+      RenderBlock (floating) {DIV} at (274,15) size 199x75 [border: (2px solid #000000)]
+        RenderText {#text} at (2,9) size 173x23
+          text run at (2,9) width 173: "This text should snap"
+        RenderBR {BR} at (175,27) size 0x0
+        RenderText {#text} at (2,50) size 195x23
+          text run at (2,50) width 195: "to a 36px font-size grid."
+        RenderBR {BR} at (197,68) size 0x0
+      RenderText {#text} at (478,10) size 756x246
+        text run at (478,10) width 288: "Here we can see the"
+        text run at (478,51) width 255: "actual lines of the"
+        text run at (478,92) width 263: "grid outside of the"
+        text run at (269,133) width 401: "floating objects. Everything"
+        text run at (10,174) width 717: "should be aligned to these lines, including what is"
+        text run at (10,215) width 300: "inside the two floats."
diff --git a/LayoutTests/platform/mac/fast/line-grid/line-grid-positioned-expected.png b/LayoutTests/platform/mac/fast/line-grid/line-grid-positioned-expected.png
new file mode 100644 (file)
index 0000000..8bfb847
Binary files /dev/null and b/LayoutTests/platform/mac/fast/line-grid/line-grid-positioned-expected.png differ
diff --git a/LayoutTests/platform/mac/fast/line-grid/line-grid-positioned-expected.txt b/LayoutTests/platform/mac/fast/line-grid/line-grid-positioned-expected.txt
new file mode 100644 (file)
index 0000000..455e3dd
--- /dev/null
@@ -0,0 +1,24 @@
+layer at (0,0) size 800x600
+  RenderView at (0,0) size 800x600
+layer at (0,0) size 800x600
+  RenderBlock {HTML} at (0,0) size 800x600
+    RenderBody {BODY} at (8,8) size 784x584
+layer at (10,10) size 269x141
+  RenderBlock (positioned) {DIV} at (10,10) size 269x141 [border: (2px solid #000000)]
+    RenderBlock {DIV} at (12,12) size 245x117
+      RenderText {#text} at (0,21) size 101x14
+        text run at (0,21) width 101: "This text should snap"
+      RenderBR {BR} at (101,32) size 0x0
+      RenderText {#text} at (0,62) size 113x14
+        text run at (0,62) width 113: "to a 36px font-size grid."
+      RenderBR {BR} at (113,73) size 0x0
+      RenderText {#text} at (0,103) size 245x14
+        text run at (0,103) width 245: "There should be lots of spacing between these lines."
+layer at (350,10) size 369x106
+  RenderBlock (positioned) {DIV} at (350,10) size 369x106 [border: (2px solid #000000)]
+    RenderText {#text} at (12,12) size 307x41
+      text run at (12,12) width 307: "This text should snap"
+    RenderBR {BR} at (319,44) size 0x0
+    RenderText {#text} at (12,53) size 345x41
+      text run at (12,53) width 345: "to a 36px font-size grid."
+    RenderBR {BR} at (357,85) size 0x0
index 2d3d3e9..7ba6046 100644 (file)
@@ -1,3 +1,53 @@
+2012-01-12  David Hyatt  <hyatt@apple.com>
+
+        https://bugs.webkit.org/show_bug.cgi?id=76197
+        
+        Implementation of baseline grid alignment. This patch implements line grid tracking in the layout state,
+        and also implements the snapping of lines to baselines. It works with normal flow, positioning and floats and
+        with pagination, as long as the grid is inside the pagination context and not outside.
+
+        Reviewed by Simon Fraser.
+
+        Added a bunch of new tests in fast/line-grid.
+
+        * WebCore.xcodeproj/project.pbxproj:
+        * rendering/InlineFlowBox.h:
+        (WebCore::InlineFlowBox::setHasTextChildren):
+        * rendering/LayoutState.cpp:
+        (WebCore::LayoutState::LayoutState):
+        (WebCore::LayoutState::propagateLineGridInfo):
+        (WebCore::LayoutState::establishLineGrid):
+        * rendering/LayoutState.h:
+        (WebCore::LayoutState::LayoutState):
+        (WebCore::LayoutState::pageLogicalHeight):
+        (WebCore::LayoutState::currentLineGrid):
+        (WebCore::LayoutState::currentLineGridOffset):
+        (WebCore::LayoutState::layoutOffset):
+        (WebCore::LayoutState::needsBlockDirectionLocationSetBeforeLayout):
+        * rendering/RenderBlock.cpp:
+        (WebCore::RenderBlock::layoutBlockChildren):
+        (WebCore::RenderBlock::layoutPositionedObjects):
+        (WebCore::RenderBlock::insertFloatingObject):
+        (WebCore::RenderBlock::positionNewFloats):
+        (WebCore::RenderBlock::pageLogicalTopForOffset):
+        (WebCore::RenderBlock::adjustLinePositionForPagination):
+        * rendering/RenderBlock.h:
+        (WebCore::RenderBlock::lineGridBox):
+        (WebCore::RenderBlock::setLineGridBox):
+        (WebCore::RenderBlock::RenderBlockRareData::RenderBlockRareData):
+        * rendering/RenderBlockLineLayout.cpp:
+        (WebCore::RenderBlock::layoutInlineChildren):
+        (WebCore::RenderBlock::layoutLineGridBox):
+        * rendering/RenderFlowThread.cpp:
+        (WebCore::RenderFlowThread::regionLogicalTopForLine):
+        * rendering/RenderFlowThread.h:
+        * rendering/RenderView.h:
+        (WebCore::RenderView::pushLayoutState):
+        * rendering/RootInlineBox.cpp:
+        (WebCore::RootInlineBox::alignBoxesInBlockDirection):
+        (WebCore::RootInlineBox::lineGridSnapAdjustment):
+        * rendering/RootInlineBox.h:
+
 2012-01-17  Tim Horton  <timothy_horton@apple.com>
 
         -webkit-cross-fade doesn't respect background-size
index b6378e9..2ea5c47 100644 (file)
@@ -192,8 +192,9 @@ public:
 
     bool hasTextChildren() const { return m_hasTextChildren; }
     bool hasTextDescendants() const { return m_hasTextDescendants; }
+    void setHasTextChildren() { m_hasTextChildren = true; setHasTextDescendants(); }
     void setHasTextDescendants() { m_hasTextDescendants = true; }
-
+    
     void checkConsistency() const;
     void setHasBadChildList();
 
index add5b01..63b471d 100644 (file)
@@ -37,6 +37,7 @@ namespace WebCore {
 
 LayoutState::LayoutState(LayoutState* prev, RenderBox* renderer, const LayoutSize& offset, LayoutUnit pageLogicalHeight, bool pageLogicalHeightChanged, ColumnInfo* columnInfo)
     : m_columnInfo(columnInfo)
+    , m_currentLineGrid(0)
     , m_next(prev)
 #ifndef NDEBUG
     , m_renderer(renderer)
@@ -107,7 +108,14 @@ LayoutState::LayoutState(LayoutState* prev, RenderBox* renderer, const LayoutSiz
     m_layoutDelta = m_next->m_layoutDelta;
     
     m_isPaginated = m_pageLogicalHeight || m_columnInfo;
-    
+
+    // Propagate line grid information.
+    propagateLineGridInfo(renderer);
+
+    // If we have a new grid to track, then add it to our set.
+    if (renderer->style()->lineGrid() != RenderStyle::initialLineGrid() && renderer->isBlockFlow())
+        establishLineGrid(toRenderBlock(renderer));
+
     // FIXME: <http://bugs.webkit.org/show_bug.cgi?id=13443> Apply control clip if present.
 }
 
@@ -117,6 +125,7 @@ LayoutState::LayoutState(LayoutState* prev, RenderFlowThread* flowThread, bool r
     , m_pageLogicalHeight(1) // Use a fake height here. That value is not important, just needs to be non-zero.
     , m_pageLogicalHeightChanged(regionsChanged)
     , m_columnInfo(0)
+    , m_currentLineGrid(0)
     , m_next(prev)
 #ifndef NDEBUG
     , m_renderer(flowThread)
@@ -133,6 +142,7 @@ LayoutState::LayoutState(RenderObject* root)
     , m_pageLogicalHeight(0)
     , m_pageLogicalHeightChanged(false)
     , m_columnInfo(0)
+    , m_currentLineGrid(0)
     , m_next(0)
 #ifndef NDEBUG
     , m_renderer(root)
@@ -196,4 +206,39 @@ void LayoutState::addForcedColumnBreak(LayoutUnit childLogicalOffset)
     m_columnInfo->addForcedBreak(pageLogicalOffset(childLogicalOffset));
 }
 
+void LayoutState::propagateLineGridInfo(RenderBox* renderer)
+{
+    // Disable line grids for objects we don't support. For now this includes overflow:scroll/auto, inline blocks and
+    // writing mode roots.
+    if (!m_next || renderer->isUnsplittableForPagination())
+        return;
+
+    m_currentLineGrid = m_next->m_currentLineGrid;
+    m_currentLineGridOffset = m_next->m_currentLineGridOffset;
+}
+
+void LayoutState::establishLineGrid(RenderBlock* block)
+{
+    // First check to see if this grid has been established already.
+    if (m_currentLineGrid) {
+        if (m_currentLineGrid->style()->lineGrid() == block->style()->lineGrid())
+            return;
+        RenderBlock* currentGrid = m_currentLineGrid;
+        for (LayoutState* currentState = m_next; currentState; currentState = currentState->m_next) {
+            if (currentState->m_currentLineGrid == currentGrid)
+                continue;
+            currentGrid = currentState->m_currentLineGrid;
+            if (currentGrid->style()->lineGrid() == block->style()->lineGrid()) {
+                m_currentLineGrid = currentGrid;
+                m_currentLineGridOffset = currentState->m_currentLineGridOffset;
+                return;
+            }
+        }
+    }
+    
+    // We didn't find an already-established grid with this identifier. Our render object establishes the grid.
+    m_currentLineGrid = block;
+    m_currentLineGridOffset = m_layoutOffset; 
+}
+
 } // namespace WebCore
index 2b4df01..6b860b9 100644 (file)
 #define LayoutState_h
 
 #include "LayoutTypes.h"
+#include <wtf/HashMap.h>
 #include <wtf/Noncopyable.h>
 
 namespace WebCore {
 
 class ColumnInfo;
 class RenderArena;
+class RenderBlock;
 class RenderBox;
 class RenderObject;
 class RenderFlowThread;
@@ -46,6 +48,7 @@ public:
         , m_pageLogicalHeight(0)
         , m_pageLogicalHeightChanged(false)
         , m_columnInfo(0)
+        , m_currentLineGrid(0)
         , m_next(0)
 #ifndef NDEBUG
         , m_renderer(0)
@@ -75,13 +78,23 @@ public:
 
     void addForcedColumnBreak(LayoutUnit childLogicalOffset);
     
-    bool pageLogicalHeight() const { return m_pageLogicalHeight; }
+    LayoutUnit pageLogicalHeight() const { return m_pageLogicalHeight; }
     bool pageLogicalHeightChanged() const { return m_pageLogicalHeightChanged; }
 
+    RenderBlock* currentLineGrid() const { return m_currentLineGrid; }
+    LayoutSize currentLineGridOffset() const { return m_currentLineGridOffset; }
+
+    LayoutSize layoutOffset() const { return m_layoutOffset; }
+
+    bool needsBlockDirectionLocationSetBeforeLayout() const { return m_currentLineGrid || (m_isPaginated && m_pageLogicalHeight); }
+
 private:
     // The normal operator new is disallowed.
     void* operator new(size_t) throw();
 
+    void propagateLineGridInfo(RenderBox*);
+    void establishLineGrid(RenderBlock*);
+
 public:
     bool m_clipped;
     bool m_isPaginated;
@@ -105,6 +118,10 @@ public:
     // If the enclosing pagination model is a column model, then this will store column information for easy retrieval/manipulation.
     ColumnInfo* m_columnInfo;
 
+    // The current line grid that we're snapping to and the offset of the start of the grid.
+    RenderBlock* m_currentLineGrid;
+    LayoutSize m_currentLineGridOffset;
+    
     LayoutState* m_next;
 #ifndef NDEBUG
     RenderObject* m_renderer;
index f42f815..3cc1e2c 100755 (executable)
@@ -198,6 +198,9 @@ void RenderBlock::willBeDestroyed()
 
     m_lineBoxes.deleteLineBoxes(renderArena());
 
+    if (lineGridBox())
+        lineGridBox()->destroy(renderArena());
+
     if (UNLIKELY(gDelayedUpdateScrollInfoSet != 0))
         gDelayedUpdateScrollInfoSet->remove(this);
 
@@ -1987,6 +1990,10 @@ void RenderBlock::layoutBlockChildren(bool relayoutChildren, LayoutUnit& maxFloa
     LayoutUnit afterEdge = borderAfter() + paddingAfter() + scrollbarLogicalHeight();
 
     setLogicalHeight(beforeEdge);
+    
+    // Lay out our hypothetical grid line as though it occurs at the top of the block.
+    if (view()->layoutState()->currentLineGrid() == this)
+        layoutLineGridBox();
 
     // The margin struct caches all our current margin collapsing state.  The compact struct caches state when we encounter compacts,
     MarginInfo marginInfo(this, beforeEdge, afterEdge);
@@ -2301,11 +2308,11 @@ bool RenderBlock::layoutPositionedObjects(bool relayoutChildren)
         if (r->needsPositionedMovementLayoutOnly() && r->tryLayoutDoingPositionedMovementOnly())
             r->setNeedsLayout(false);
             
-        // If we are in a flow thread, go ahead and compute a vertical position for our object now.
+        // If we are paginated or in a line grid, go ahead and compute a vertical position for our object now.
         // If it's wrong we'll lay out again.
         LayoutUnit oldLogicalTop = 0;
-        bool checkForPaginationRelayout = r->needsLayout() && view()->layoutState()->isPaginated() && view()->layoutState()->pageLogicalHeight(); 
-        if (checkForPaginationRelayout) {
+        bool needsBlockDirectionLocationSetBeforeLayout = r->needsLayout() && view()->layoutState()->needsBlockDirectionLocationSetBeforeLayout(); 
+        if (needsBlockDirectionLocationSetBeforeLayout) {
             if (isHorizontalWritingMode() == r->isHorizontalWritingMode())
                 r->computeLogicalHeight();
             else
@@ -2316,7 +2323,7 @@ bool RenderBlock::layoutPositionedObjects(bool relayoutChildren)
         r->layoutIfNeeded();
         
         // Lay out again if our estimate was wrong.
-        if (checkForPaginationRelayout && logicalTopForChild(r) != oldLogicalTop) {
+        if (needsBlockDirectionLocationSetBeforeLayout && logicalTopForChild(r) != oldLogicalTop) {
             r->setChildNeedsLayout(true, false);
             r->layoutIfNeeded();
         }
@@ -3307,8 +3314,8 @@ RenderBlock::FloatingObject* RenderBlock::insertFloatingObject(RenderBox* o)
         if (isChildRenderBlock && !o->needsLayout() && view()->layoutState()->pageLogicalHeightChanged())
             o->setChildNeedsLayout(true, false);
             
-        bool affectedByPagination = isChildRenderBlock && view()->layoutState()->m_pageLogicalHeight;
-        if (!affectedByPagination || isWritingModeRoot()) // We are unsplittable if we're a block flow root.
+        bool needsBlockDirectionLocationSetBeforeLayout = isChildRenderBlock && view()->layoutState()->needsBlockDirectionLocationSetBeforeLayout();
+        if (!needsBlockDirectionLocationSetBeforeLayout || isWritingModeRoot()) // We are unsplittable if we're a block flow root.
             o->layoutIfNeeded();
         else {
             o->computeLogicalWidth();
@@ -3488,13 +3495,14 @@ bool RenderBlock::positionNewFloats()
         setLogicalLeftForChild(childBox, floatLogicalLocation.x() + childLogicalLeftMargin);
         setLogicalTopForChild(childBox, floatLogicalLocation.y() + marginBeforeForChild(childBox));
 
-        if (view()->layoutState()->isPaginated()) {
-            RenderBlock* childBlock = childBox->isRenderBlock() ? toRenderBlock(childBox) : 0;
-
-            if (!childBox->needsLayout())
-                childBox->markForPaginationRelayoutIfNeeded();
-            childBox->layoutIfNeeded();
+        LayoutState* layoutState = view()->layoutState();
+        bool isPaginated = layoutState->isPaginated();
+        if (isPaginated && !childBox->needsLayout())
+            childBox->markForPaginationRelayoutIfNeeded();
+        
+        childBox->layoutIfNeeded();
 
+        if (isPaginated) {
             // If we are unsplittable and don't fit, then we need to move down.
             // We include our margins as part of the unsplittable area.
             LayoutUnit newLogicalTop = adjustForUnsplittableChild(childBox, floatLogicalLocation.y(), true);
@@ -3502,6 +3510,7 @@ bool RenderBlock::positionNewFloats()
             // See if we have a pagination strut that is making us move down further.
             // Note that an unsplittable child can't also have a pagination strut, so this is
             // exclusive with the case above.
+            RenderBlock* childBlock = childBox->isRenderBlock() ? toRenderBlock(childBox) : 0;
             if (childBlock && childBlock->paginationStrut()) {
                 newLogicalTop += childBlock->paginationStrut();
                 childBlock->setPaginationStrut(0);
@@ -6392,6 +6401,22 @@ LayoutUnit RenderBlock::applyAfterBreak(RenderBox* child, LayoutUnit logicalOffs
     return logicalOffset;
 }
 
+LayoutUnit RenderBlock::pageLogicalTopForOffset(LayoutUnit offset) const
+{
+    RenderView* renderView = view();
+    LayoutUnit firstPageLogicalTop = isHorizontalWritingMode() ? renderView->layoutState()->m_pageOffset.height() : renderView->layoutState()->m_pageOffset.width();
+    LayoutUnit blockLogicalTop = isHorizontalWritingMode() ? renderView->layoutState()->m_layoutOffset.height() : renderView->layoutState()->m_layoutOffset.width();
+
+    LayoutUnit cumulativeOffset = offset + blockLogicalTop;
+    if (!inRenderFlowThread()) {
+        LayoutUnit pageLogicalHeight = renderView->layoutState()->pageLogicalHeight();
+        if (!pageLogicalHeight)
+            return 0;
+        return cumulativeOffset - (cumulativeOffset - firstPageLogicalTop) % pageLogicalHeight;
+    }
+    return enclosingRenderFlowThread()->regionLogicalTopForLine(cumulativeOffset);
+}
+
 LayoutUnit RenderBlock::pageLogicalHeightForOffset(LayoutUnit offset) const
 {
     RenderView* renderView = view();
@@ -6506,7 +6531,7 @@ void RenderBlock::adjustLinePositionForPagination(RootInlineBox* lineBox, Layout
             delta += remainingLogicalHeight;
             lineBox->setPaginationStrut(remainingLogicalHeight);
         }
-    }  
+    }
 }
 
 LayoutUnit RenderBlock::adjustBlockChildForPagination(LayoutUnit logicalTopAfterClear, LayoutUnit estimateWithoutPagination, RenderBox* child, bool atBeforeSideOfBlock)
index 5792a93..6506dc8 100644 (file)
@@ -239,6 +239,17 @@ public:
     int pageLogicalOffset() const { return m_rareData ? m_rareData->m_pageLogicalOffset : 0; }
     void setPageLogicalOffset(int);
 
+    RootInlineBox* lineGridBox() const { return m_rareData ? m_rareData->m_lineGridBox : 0; }
+    void setLineGridBox(RootInlineBox* box)
+    {
+        if (!m_rareData)
+            m_rareData = adoptPtr(new RenderBlockRareData(this));
+        if (m_rareData->m_lineGridBox)
+            m_rareData->m_lineGridBox->destroy(renderArena());
+        m_rareData->m_lineGridBox = box;
+    }
+    void layoutLineGridBox();
+
     // Accessors for logical width/height and margins in the containing block's block-flow direction.
     enum ApplyLayoutDeltaMode { ApplyLayoutDelta, DoNotApplyLayoutDelta };
     LayoutUnit logicalWidthForChild(const RenderBox* child) { return isHorizontalWritingMode() ? child->width() : child->height(); }
@@ -471,7 +482,7 @@ private:
     virtual void borderFitAdjust(LayoutRect&) const; // Shrink the box in which the border paints if border-fit is set.
 
     virtual void updateBeforeAfterContent(PseudoId);
-
+    
     virtual RootInlineBox* createRootInlineBox(); // Subclassed by SVG and Ruby.
 
     // Called to lay out the legend for a fieldset or the ruby text of a ruby run.
@@ -895,8 +906,12 @@ protected:
     LayoutUnit applyBeforeBreak(RenderBox* child, LayoutUnit logicalOffset); // If the child has a before break, then return a new yPos that shifts to the top of the next page/column.
     LayoutUnit applyAfterBreak(RenderBox* child, LayoutUnit logicalOffset, MarginInfo&); // If the child has an after break, then return a new offset that shifts to the top of the next page/column.
 
+public:
+    LayoutUnit pageLogicalTopForOffset(LayoutUnit offset) const;
     LayoutUnit pageLogicalHeightForOffset(LayoutUnit offset) const;
     LayoutUnit pageRemainingLogicalHeightForOffset(LayoutUnit offset, PageBoundaryRule = IncludePageBoundary) const;
+    
+protected:
     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.
@@ -1017,6 +1032,7 @@ protected:
             : m_margins(positiveMarginBeforeDefault(block), negativeMarginBeforeDefault(block), positiveMarginAfterDefault(block), negativeMarginAfterDefault(block))
             , m_paginationStrut(0)
             , m_pageLogicalOffset(0)
+            , m_lineGridBox(0)
         { 
         }
 
@@ -1039,8 +1055,10 @@ protected:
         }
         
         MarginValues m_margins;
-        int m_paginationStrut;
-        int m_pageLogicalOffset;
+        LayoutUnit m_paginationStrut;
+        LayoutUnit m_pageLogicalOffset;
+        
+        RootInlineBox* m_lineGridBox;
      };
 
     OwnPtr<RenderBlockRareData> m_rareData;
index 77c3ce3..b5a8661 100755 (executable)
@@ -1438,6 +1438,10 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, LayoutUnit& repain
     m_overflow.clear();
 
     setLogicalHeight(borderBefore() + paddingBefore());
+    
+    // Lay out our hypothetical grid line as though it occurs at the top of the block.
+    if (view()->layoutState() && view()->layoutState()->currentLineGrid() == this)
+        layoutLineGridBox();
 
     // Figure out if we should clear out our line boxes.
     // FIXME: Handle resize eventually!
@@ -2757,4 +2761,28 @@ LayoutUnit RenderBlock::startAlignedOffsetForLine(RenderBox* child, LayoutUnit p
     return logicalLeft;
 }
 
+
+void RenderBlock::layoutLineGridBox()
+{
+    if (style()->lineGrid() == RenderStyle::initialLineGrid()) {
+        setLineGridBox(0);
+        return;
+    }
+    
+    setLineGridBox(0);
+
+    RootInlineBox* lineGridBox = new (renderArena()) RootInlineBox(this);
+    lineGridBox->setHasTextChildren(); // Needed to make the line ascent/descent actually be honored in quirks mode.
+    lineGridBox->setConstructed();
+    GlyphOverflowAndFallbackFontsMap textBoxDataMap;
+    VerticalPositionCache verticalPositionCache;
+    lineGridBox->alignBoxesInBlockDirection(logicalHeight(), textBoxDataMap, verticalPositionCache);
+    
+    setLineGridBox(lineGridBox);
+    
+    // FIXME: If any of the characteristics of the box change compared to the old one, then we need to do a deep dirtying
+    // (similar to what happens when the page height changes). Ideally, though, we only do this if someone is actually snapping
+    // to this grid.
+}
+
 }
index 4ddee97..83b4d9f 100644 (file)
@@ -554,6 +554,14 @@ RenderRegion* RenderFlowThread::renderRegionForLine(LayoutUnit position, bool ex
     return lastValidRegion;
 }
 
+LayoutUnit RenderFlowThread::regionLogicalTopForLine(LayoutUnit position) const
+{
+    RenderRegion* region = renderRegionForLine(position);
+    if (!region)
+        return 0;
+    return isHorizontalWritingMode() ? region->regionRect().y() : region->regionRect().x();
+}
+
 LayoutUnit RenderFlowThread::regionLogicalWidthForLine(LayoutUnit position) const
 {
     RenderRegion* region = renderRegionForLine(position, true);
index 5ababf8..f596481 100644 (file)
@@ -100,6 +100,7 @@ public:
 
     void repaintRectangleInRegions(const LayoutRect&, bool immediate);
 
+    LayoutUnit regionLogicalTopForLine(LayoutUnit position) const;
     LayoutUnit regionLogicalWidthForLine(LayoutUnit position) const;
     LayoutUnit regionLogicalHeightForLine(LayoutUnit position) const;
     LayoutUnit regionRemainingLogicalHeightForLine(LayoutUnit position, PageBoundaryRule = IncludePageBoundary) const;
index 728dd8b..8807434 100644 (file)
@@ -210,7 +210,8 @@ private:
     bool pushLayoutState(RenderBox* renderer, const LayoutSize& offset, LayoutUnit pageHeight = 0, bool pageHeightChanged = false, ColumnInfo* colInfo = 0)
     {
         // We push LayoutState even if layoutState is disabled because it stores layoutDelta too.
-        if (!doingFullRepaint() || m_layoutState->isPaginated() || renderer->hasColumns() || renderer->inRenderFlowThread()) {
+        if (!doingFullRepaint() || m_layoutState->isPaginated() || renderer->hasColumns() || renderer->inRenderFlowThread()
+            || m_layoutState->currentLineGrid() || (renderer->style()->lineGrid() != RenderStyle::initialLineGrid() && renderer->isBlockFlow())) {
             m_layoutState = new (renderArena()) LayoutState(m_layoutState, renderer, offset, pageHeight, pageHeightChanged, colInfo);
             return true;
         }
index efdefa7..081b3b7 100644 (file)
@@ -33,6 +33,7 @@
 #include "PaintInfo.h"
 #include "RenderArena.h"
 #include "RenderBlock.h"
+#include "RenderView.h"
 #include "VerticalPositionCache.h"
 #include <wtf/unicode/Unicode.h>
 
@@ -285,6 +286,12 @@ LayoutUnit RootInlineBox::alignBoxesInBlockDirection(LayoutUnit heightOfBlock, G
         heightOfBlock += annotationsAdjustment;
     }
 
+    LayoutUnit gridSnapAdjustment = lineGridSnapAdjustment();
+    if (gridSnapAdjustment) {
+        adjustBlockDirectionPosition(gridSnapAdjustment);
+        heightOfBlock += gridSnapAdjustment;
+    }
+
     return heightOfBlock + maxHeight;
 }
 
@@ -319,6 +326,73 @@ int RootInlineBox::beforeAnnotationsAdjustment() const
     return result;
 }
 
+LayoutUnit RootInlineBox::lineGridSnapAdjustment(LayoutUnit delta) const
+{
+    // If our block doesn't have snapping turned on, do nothing.
+    // FIXME: Implement bounds snapping.
+    if (block()->style()->lineGridSnap() != LineGridSnapBaseline)
+        return 0;
+
+    // Get the current line grid and offset.
+    LayoutState* layoutState = block()->view()->layoutState();
+    RenderBlock* lineGrid = layoutState->currentLineGrid();
+    LayoutSize lineGridOffset = layoutState->currentLineGridOffset();
+    if (!lineGrid || lineGrid->style()->writingMode() != block()->style()->writingMode())
+        return 0;
+
+    // Get the hypothetical line box used to establish the grid.
+    RootInlineBox* lineGridBox = lineGrid->lineGridBox();
+    if (!lineGridBox)
+        return 0;
+    
+    LayoutUnit lineGridBlockOffset = lineGrid->isHorizontalWritingMode() ? lineGridOffset.height() : lineGridOffset.width();
+    LayoutUnit blockOffset = block()->isHorizontalWritingMode() ? layoutState->layoutOffset().height() : layoutState->layoutOffset().width();
+
+    // Now determine our position on the grid. Our baseline needs to be adjusted to the nearest baseline multiple
+    // as established by the line box.
+    // FIXME: Need to handle crazy line-box-contain values that cause the root line box to not be considered. I assume
+    // the grid should honor line-box-contain.
+    LayoutUnit baselineMultiple = lineGridBox->lineBottomWithLeading() - lineGridBox->lineTopWithLeading();
+    if (!baselineMultiple)
+        return 0;
+
+    LayoutUnit lineGridAscent = lineGrid->style()->fontMetrics().ascent(baselineType());
+    LayoutUnit firstBaselinePosition = lineGridBlockOffset + lineGridAscent + lineGridBox->logicalTop();
+    LayoutUnit currentBaselinePosition = blockOffset + logicalTop() + delta + block()->style()->fontMetrics().ascent(baselineType());
+
+    // If we're paginated, see if we're on a page after the first one. If so, the grid resets on subsequent pages.
+    // FIXME: If the grid is an ancestor of the pagination establisher, then this is incorrect.
+    LayoutUnit pageLogicalTop = 0;
+    if (layoutState->isPaginated() && layoutState->pageLogicalHeight()) {
+        pageLogicalTop = block()->pageLogicalTopForOffset(logicalTop() + delta);
+        if (pageLogicalTop > lineGridBlockOffset + lineGridBox->logicalTop())
+            firstBaselinePosition = lineGridAscent + pageLogicalTop + lineGridBox->logicalTop() - lineGrid->borderBefore() - lineGrid->paddingBefore();
+    }
+            
+    // If we're above the first line, just push to the first line.
+    if (currentBaselinePosition < firstBaselinePosition)
+        return delta + firstBaselinePosition - currentBaselinePosition;
+
+    // Otherwise we're in the middle of the grid somewhere. Just push to the next line.
+    LayoutUnit baselineOffset = currentBaselinePosition - firstBaselinePosition;
+    LayoutUnit remainder = baselineOffset % baselineMultiple;
+    LayoutUnit result = delta;
+    if (remainder)
+        result += baselineMultiple - remainder;
+
+    // If we aren't paginated we can return the result.
+    if (!layoutState->isPaginated() || !layoutState->pageLogicalHeight() || result == delta)
+        return result;
+    
+    // We may have shifted to a new page. We need to do a re-snap when that happens.
+    LayoutUnit newPageLogicalTop = block()->pageLogicalTopForOffset(logicalTop() + result);
+    if (newPageLogicalTop == pageLogicalTop)
+        return result;
+    
+    // Put ourselves at the top of the next page to force a snap onto the new grid established by that page.
+    return lineGridSnapAdjustment(newPageLogicalTop - (blockOffset + logicalTop()));
+}
+
 GapRects RootInlineBox::lineSelectionGap(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock, 
                                          LayoutUnit selTop, LayoutUnit selHeight, const PaintInfo* paintInfo)
 {
index 69c1e43..b7487ae 100644 (file)
@@ -176,11 +176,14 @@ public:
 
     Node* getLogicalStartBoxWithNode(InlineBox*&) const;
     Node* getLogicalEndBoxWithNode(InlineBox*&) const;
+
 #ifndef NDEBUG
     virtual const char* boxName() const;
 #endif
 private:
     void setHasEllipsisBox(bool hasEllipsisBox) { m_hasEllipsisBoxOrHyphen = hasEllipsisBox; }
+    
+    LayoutUnit lineGridSnapAdjustment(LayoutUnit delta = 0) const;
 
     int beforeAnnotationsAdjustment() const;