diff --git a/.golden/paginatedRichParagraphLayout/loremIpsum20em.golden b/.golden/paginatedRichParagraphLayout/loremIpsum20em.golden
--- a/.golden/paginatedRichParagraphLayout/loremIpsum20em.golden
+++ b/.golden/paginatedRichParagraphLayout/loremIpsum20em.golden
@@ -1,5 +1,9 @@
 [ (Continue, ParagraphLayout
-    { paragraphRect = Rect {x_origin = 0, y_origin = 0, x_size = 18310, y_size = -2242}
+    { paragraphRect = Rect {x_origin = 0, y_origin = 0, x_size = 19791, y_size = -2242}
+    , paragraphLines =
+        [ Line {lineNumber = 1, lineRect = Rect {x_origin = 0, y_origin = 0, x_size = 19791, y_size = -1121}}
+        , Line {lineNumber = 2, lineRect = Rect {x_origin = 0, y_origin = -1121, x_size = 19791, y_size = -1121}}
+        ]
     , paragraphFragments =
         [ Fragment
             { fragmentUserData = "text"
@@ -105,6 +109,14 @@
 )
 , (Continue, ParagraphLayout
     { paragraphRect = Rect {x_origin = 0, y_origin = 0, x_size = 19791, y_size = -6726}
+    , paragraphLines =
+        [ Line {lineNumber = 3, lineRect = Rect {x_origin = 0, y_origin = 0, x_size = 19791, y_size = -1121}}
+        , Line {lineNumber = 4, lineRect = Rect {x_origin = 0, y_origin = -1121, x_size = 19791, y_size = -1121}}
+        , Line {lineNumber = 5, lineRect = Rect {x_origin = 0, y_origin = -2242, x_size = 19791, y_size = -1121}}
+        , Line {lineNumber = 6, lineRect = Rect {x_origin = 0, y_origin = -3363, x_size = 19791, y_size = -1121}}
+        , Line {lineNumber = 7, lineRect = Rect {x_origin = 0, y_origin = -4484, x_size = 19791, y_size = -1121}}
+        , Line {lineNumber = 8, lineRect = Rect {x_origin = 0, y_origin = -5605, x_size = 19791, y_size = -1121}}
+        ]
     , paragraphFragments =
         [ Fragment
             { fragmentUserData = "text"
@@ -426,7 +438,12 @@
     }
 )
 , (Continue, ParagraphLayout
-    { paragraphRect = Rect {x_origin = 0, y_origin = 0, x_size = 19199, y_size = -3363}
+    { paragraphRect = Rect {x_origin = 0, y_origin = 0, x_size = 19791, y_size = -3363}
+    , paragraphLines =
+        [ Line {lineNumber = 9, lineRect = Rect {x_origin = 0, y_origin = 0, x_size = 19791, y_size = -1121}}
+        , Line {lineNumber = 10, lineRect = Rect {x_origin = 0, y_origin = -1121, x_size = 19791, y_size = -1121}}
+        , Line {lineNumber = 11, lineRect = Rect {x_origin = 0, y_origin = -2242, x_size = 19791, y_size = -1121}}
+        ]
     , paragraphFragments =
         [ Fragment
             { fragmentUserData = "text"
diff --git a/.golden/richParagraphLayout/emptyBoxMiddle.golden b/.golden/richParagraphLayout/emptyBoxMiddle.golden
--- a/.golden/richParagraphLayout/emptyBoxMiddle.golden
+++ b/.golden/richParagraphLayout/emptyBoxMiddle.golden
@@ -1,5 +1,8 @@
 ParagraphLayout
     { paragraphRect = Rect {x_origin = 0, y_origin = 0, x_size = 5193, y_size = -1121}
+    , paragraphLines =
+        [ Line {lineNumber = 1, lineRect = Rect {x_origin = 0, y_origin = 0, x_size = 5193, y_size = -1121}}
+        ]
     , paragraphFragments =
         [ Fragment
             { fragmentUserData = "text1"
diff --git a/.golden/richParagraphLayout/hardBoxBreakLTR.golden b/.golden/richParagraphLayout/hardBoxBreakLTR.golden
--- a/.golden/richParagraphLayout/hardBoxBreakLTR.golden
+++ b/.golden/richParagraphLayout/hardBoxBreakLTR.golden
@@ -1,5 +1,9 @@
 ParagraphLayout
     { paragraphRect = Rect {x_origin = 0, y_origin = 0, x_size = 5855, y_size = -2242}
+    , paragraphLines =
+        [ Line {lineNumber = 1, lineRect = Rect {x_origin = 0, y_origin = 0, x_size = 5855, y_size = -1121}}
+        , Line {lineNumber = 2, lineRect = Rect {x_origin = 0, y_origin = -1121, x_size = 5855, y_size = -1121}}
+        ]
     , paragraphFragments =
         [ Fragment
             { fragmentUserData = "text1"
diff --git a/.golden/richParagraphLayout/hardBoxBreakRTL.golden b/.golden/richParagraphLayout/hardBoxBreakRTL.golden
--- a/.golden/richParagraphLayout/hardBoxBreakRTL.golden
+++ b/.golden/richParagraphLayout/hardBoxBreakRTL.golden
@@ -1,5 +1,9 @@
 ParagraphLayout
     { paragraphRect = Rect {x_origin = 999996545, y_origin = 0, x_size = 3455, y_size = -3000}
+    , paragraphLines =
+        [ Line {lineNumber = 1, lineRect = Rect {x_origin = 999996545, y_origin = 0, x_size = 3455, y_size = -1500}}
+        , Line {lineNumber = 2, lineRect = Rect {x_origin = 999996545, y_origin = -1500, x_size = 3455, y_size = -1500}}
+        ]
     , paragraphFragments =
         [ Fragment
             { fragmentUserData = "text2"
diff --git a/.golden/richParagraphLayout/loremIpsum20em.golden b/.golden/richParagraphLayout/loremIpsum20em.golden
--- a/.golden/richParagraphLayout/loremIpsum20em.golden
+++ b/.golden/richParagraphLayout/loremIpsum20em.golden
@@ -1,5 +1,18 @@
 ParagraphLayout
     { paragraphRect = Rect {x_origin = 0, y_origin = 0, x_size = 19791, y_size = -12331}
+    , paragraphLines =
+        [ Line {lineNumber = 1, lineRect = Rect {x_origin = 0, y_origin = 0, x_size = 19791, y_size = -1121}}
+        , Line {lineNumber = 2, lineRect = Rect {x_origin = 0, y_origin = -1121, x_size = 19791, y_size = -1121}}
+        , Line {lineNumber = 3, lineRect = Rect {x_origin = 0, y_origin = -2242, x_size = 19791, y_size = -1121}}
+        , Line {lineNumber = 4, lineRect = Rect {x_origin = 0, y_origin = -3363, x_size = 19791, y_size = -1121}}
+        , Line {lineNumber = 5, lineRect = Rect {x_origin = 0, y_origin = -4484, x_size = 19791, y_size = -1121}}
+        , Line {lineNumber = 6, lineRect = Rect {x_origin = 0, y_origin = -5605, x_size = 19791, y_size = -1121}}
+        , Line {lineNumber = 7, lineRect = Rect {x_origin = 0, y_origin = -6726, x_size = 19791, y_size = -1121}}
+        , Line {lineNumber = 8, lineRect = Rect {x_origin = 0, y_origin = -7847, x_size = 19791, y_size = -1121}}
+        , Line {lineNumber = 9, lineRect = Rect {x_origin = 0, y_origin = -8968, x_size = 19791, y_size = -1121}}
+        , Line {lineNumber = 10, lineRect = Rect {x_origin = 0, y_origin = -10089, x_size = 19791, y_size = -1121}}
+        , Line {lineNumber = 11, lineRect = Rect {x_origin = 0, y_origin = -11210, x_size = 19791, y_size = -1121}}
+        ]
     , paragraphFragments =
         [ Fragment
             { fragmentUserData = "text"
diff --git a/.golden/richParagraphLayout/loremIpsum20emCentre.golden b/.golden/richParagraphLayout/loremIpsum20emCentre.golden
--- a/.golden/richParagraphLayout/loremIpsum20emCentre.golden
+++ b/.golden/richParagraphLayout/loremIpsum20emCentre.golden
@@ -1,5 +1,18 @@
 ParagraphLayout
     { paragraphRect = Rect {x_origin = 104, y_origin = 0, x_size = 19791, y_size = -12331}
+    , paragraphLines =
+        [ Line {lineNumber = 1, lineRect = Rect {x_origin = 104, y_origin = 0, x_size = 19791, y_size = -1121}}
+        , Line {lineNumber = 2, lineRect = Rect {x_origin = 104, y_origin = -1121, x_size = 19791, y_size = -1121}}
+        , Line {lineNumber = 3, lineRect = Rect {x_origin = 104, y_origin = -2242, x_size = 19791, y_size = -1121}}
+        , Line {lineNumber = 4, lineRect = Rect {x_origin = 104, y_origin = -3363, x_size = 19791, y_size = -1121}}
+        , Line {lineNumber = 5, lineRect = Rect {x_origin = 104, y_origin = -4484, x_size = 19791, y_size = -1121}}
+        , Line {lineNumber = 6, lineRect = Rect {x_origin = 104, y_origin = -5605, x_size = 19791, y_size = -1121}}
+        , Line {lineNumber = 7, lineRect = Rect {x_origin = 104, y_origin = -6726, x_size = 19791, y_size = -1121}}
+        , Line {lineNumber = 8, lineRect = Rect {x_origin = 104, y_origin = -7847, x_size = 19791, y_size = -1121}}
+        , Line {lineNumber = 9, lineRect = Rect {x_origin = 104, y_origin = -8968, x_size = 19791, y_size = -1121}}
+        , Line {lineNumber = 10, lineRect = Rect {x_origin = 104, y_origin = -10089, x_size = 19791, y_size = -1121}}
+        , Line {lineNumber = 11, lineRect = Rect {x_origin = 104, y_origin = -11210, x_size = 19791, y_size = -1121}}
+        ]
     , paragraphFragments =
         [ Fragment
             { fragmentUserData = "text"
diff --git a/.golden/richParagraphLayout/loremIpsum20emRight.golden b/.golden/richParagraphLayout/loremIpsum20emRight.golden
--- a/.golden/richParagraphLayout/loremIpsum20emRight.golden
+++ b/.golden/richParagraphLayout/loremIpsum20emRight.golden
@@ -1,5 +1,18 @@
 ParagraphLayout
     { paragraphRect = Rect {x_origin = 209, y_origin = 0, x_size = 19791, y_size = -12331}
+    , paragraphLines =
+        [ Line {lineNumber = 1, lineRect = Rect {x_origin = 209, y_origin = 0, x_size = 19791, y_size = -1121}}
+        , Line {lineNumber = 2, lineRect = Rect {x_origin = 209, y_origin = -1121, x_size = 19791, y_size = -1121}}
+        , Line {lineNumber = 3, lineRect = Rect {x_origin = 209, y_origin = -2242, x_size = 19791, y_size = -1121}}
+        , Line {lineNumber = 4, lineRect = Rect {x_origin = 209, y_origin = -3363, x_size = 19791, y_size = -1121}}
+        , Line {lineNumber = 5, lineRect = Rect {x_origin = 209, y_origin = -4484, x_size = 19791, y_size = -1121}}
+        , Line {lineNumber = 6, lineRect = Rect {x_origin = 209, y_origin = -5605, x_size = 19791, y_size = -1121}}
+        , Line {lineNumber = 7, lineRect = Rect {x_origin = 209, y_origin = -6726, x_size = 19791, y_size = -1121}}
+        , Line {lineNumber = 8, lineRect = Rect {x_origin = 209, y_origin = -7847, x_size = 19791, y_size = -1121}}
+        , Line {lineNumber = 9, lineRect = Rect {x_origin = 209, y_origin = -8968, x_size = 19791, y_size = -1121}}
+        , Line {lineNumber = 10, lineRect = Rect {x_origin = 209, y_origin = -10089, x_size = 19791, y_size = -1121}}
+        , Line {lineNumber = 11, lineRect = Rect {x_origin = 209, y_origin = -11210, x_size = 19791, y_size = -1121}}
+        ]
     , paragraphFragments =
         [ Fragment
             { fragmentUserData = "text"
diff --git a/.golden/richParagraphLayout/mixedDirectionComplexLTR.golden b/.golden/richParagraphLayout/mixedDirectionComplexLTR.golden
--- a/.golden/richParagraphLayout/mixedDirectionComplexLTR.golden
+++ b/.golden/richParagraphLayout/mixedDirectionComplexLTR.golden
@@ -1,5 +1,8 @@
 ParagraphLayout
     { paragraphRect = Rect {x_origin = 0, y_origin = 0, x_size = 24557, y_size = -1500}
+    , paragraphLines =
+        [ Line {lineNumber = 1, lineRect = Rect {x_origin = 0, y_origin = 0, x_size = 24557, y_size = -1500}}
+        ]
     , paragraphFragments =
         [ Fragment
             { fragmentUserData = "text1"
diff --git a/.golden/richParagraphLayout/mixedDirectionComplexRTL.golden b/.golden/richParagraphLayout/mixedDirectionComplexRTL.golden
--- a/.golden/richParagraphLayout/mixedDirectionComplexRTL.golden
+++ b/.golden/richParagraphLayout/mixedDirectionComplexRTL.golden
@@ -1,5 +1,8 @@
 ParagraphLayout
     { paragraphRect = Rect {x_origin = 999975443, y_origin = 0, x_size = 24557, y_size = -1500}
+    , paragraphLines =
+        [ Line {lineNumber = 1, lineRect = Rect {x_origin = 999975443, y_origin = 0, x_size = 24557, y_size = -1500}}
+        ]
     , paragraphFragments =
         [ Fragment
             { fragmentUserData = "text3"
diff --git a/.golden/richParagraphLayout/mixedDirectionSimpleLTR.golden b/.golden/richParagraphLayout/mixedDirectionSimpleLTR.golden
--- a/.golden/richParagraphLayout/mixedDirectionSimpleLTR.golden
+++ b/.golden/richParagraphLayout/mixedDirectionSimpleLTR.golden
@@ -1,5 +1,8 @@
 ParagraphLayout
     { paragraphRect = Rect {x_origin = 0, y_origin = 0, x_size = 7954, y_size = -1500}
+    , paragraphLines =
+        [ Line {lineNumber = 1, lineRect = Rect {x_origin = 0, y_origin = 0, x_size = 7954, y_size = -1500}}
+        ]
     , paragraphFragments =
         [ Fragment
             { fragmentUserData = "text"
diff --git a/.golden/richParagraphLayout/mixedDirectionSimpleRTL.golden b/.golden/richParagraphLayout/mixedDirectionSimpleRTL.golden
--- a/.golden/richParagraphLayout/mixedDirectionSimpleRTL.golden
+++ b/.golden/richParagraphLayout/mixedDirectionSimpleRTL.golden
@@ -1,5 +1,8 @@
 ParagraphLayout
     { paragraphRect = Rect {x_origin = 999992046, y_origin = 0, x_size = 7954, y_size = -1500}
+    , paragraphLines =
+        [ Line {lineNumber = 1, lineRect = Rect {x_origin = 999992046, y_origin = 0, x_size = 7954, y_size = -1500}}
+        ]
     , paragraphFragments =
         [ Fragment
             { fragmentUserData = "text"
diff --git a/.golden/richParagraphLayout/mixedLineHeight.golden b/.golden/richParagraphLayout/mixedLineHeight.golden
deleted file mode 100644
--- a/.golden/richParagraphLayout/mixedLineHeight.golden
+++ /dev/null
@@ -1,306 +0,0 @@
-ParagraphLayout
-    { paragraphRect = Rect {x_origin = 0, y_origin = 0, x_size = 16708, y_size = -9400}
-    , paragraphFragments =
-        [ Fragment
-            { fragmentUserData = "mediumText"
-            , fragmentLine = 1
-            , fragmentAncestorBoxes =
-                []
-            , fragmentContentRect = Rect {x_origin = 0, y_origin = -90, x_size = 3928, y_size = -1121}
-            , fragmentRect = Rect {x_origin = 0, y_origin = 0, x_size = 3928, y_size = -1300}
-            , fragmentPen = (0, -1022)
-            , fragmentGlyphs =
-                [ (GlyphInfo {codepoint = 80, cluster = 6, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 861, y_advance = 0, x_offset = 0, y_offset = 0})
-                , (GlyphInfo {codepoint = 72, cluster = 7, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 559, y_advance = 0, x_offset = 0, y_offset = 0})
-                , (GlyphInfo {codepoint = 71, cluster = 8, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 589, y_advance = 0, x_offset = 0, y_offset = 0})
-                , (GlyphInfo {codepoint = 76, cluster = 9, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 253, y_advance = 0, x_offset = 0, y_offset = 0})
-                , (GlyphInfo {codepoint = 88, cluster = 10, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 574, y_advance = 0, x_offset = 0, y_offset = 0})
-                , (GlyphInfo {codepoint = 80, cluster = 11, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 861, y_advance = 0, x_offset = 0, y_offset = 0})
-                , (GlyphInfo {codepoint = 3, cluster = 12, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 231, y_advance = 0, x_offset = 0, y_offset = 0})
-                ]
-            }
-        , Fragment
-            { fragmentUserData = "smallText"
-            , fragmentLine = 1
-            , fragmentAncestorBoxes =
-                [ AncestorBox {boxUserData = "smallBox", boxLeftEdge = SpacedEdge 0, boxRightEdge = SpacedEdge 0, boxStartEdge = SpacedEdge 0, boxEndEdge = SpacedEdge 0}
-                ]
-            , fragmentContentRect = Rect {x_origin = 3928, y_origin = 160, x_size = 2606, y_size = -1121}
-            , fragmentRect = Rect {x_origin = 3928, y_origin = 0, x_size = 2606, y_size = -800}
-            , fragmentPen = (0, -772)
-            , fragmentGlyphs =
-                [ (GlyphInfo {codepoint = 86, cluster = 13, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 446, y_advance = 0, x_offset = 0, y_offset = 0})
-                , (GlyphInfo {codepoint = 80, cluster = 14, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 861, y_advance = 0, x_offset = 0, y_offset = 0})
-                , (GlyphInfo {codepoint = 68, cluster = 15, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 522, y_advance = 0, x_offset = 0, y_offset = 0})
-                , (GlyphInfo {codepoint = 79, cluster = 16, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 273, y_advance = 0, x_offset = 0, y_offset = 0})
-                , (GlyphInfo {codepoint = 79, cluster = 17, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 273, y_advance = 0, x_offset = 0, y_offset = 0})
-                , (GlyphInfo {codepoint = 3, cluster = 18, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 231, y_advance = 0, x_offset = 0, y_offset = 0})
-                ]
-            }
-        , Fragment
-            { fragmentUserData = "mediumText"
-            , fragmentLine = 1
-            , fragmentAncestorBoxes =
-                []
-            , fragmentContentRect = Rect {x_origin = 6534, y_origin = -90, x_size = 3928, y_size = -1121}
-            , fragmentRect = Rect {x_origin = 6534, y_origin = 0, x_size = 3928, y_size = -1300}
-            , fragmentPen = (0, -1022)
-            , fragmentGlyphs =
-                [ (GlyphInfo {codepoint = 80, cluster = 19, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 861, y_advance = 0, x_offset = 0, y_offset = 0})
-                , (GlyphInfo {codepoint = 72, cluster = 20, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 559, y_advance = 0, x_offset = 0, y_offset = 0})
-                , (GlyphInfo {codepoint = 71, cluster = 21, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 589, y_advance = 0, x_offset = 0, y_offset = 0})
-                , (GlyphInfo {codepoint = 76, cluster = 22, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 253, y_advance = 0, x_offset = 0, y_offset = 0})
-                , (GlyphInfo {codepoint = 88, cluster = 23, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 574, y_advance = 0, x_offset = 0, y_offset = 0})
-                , (GlyphInfo {codepoint = 80, cluster = 24, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 861, y_advance = 0, x_offset = 0, y_offset = 0})
-                , (GlyphInfo {codepoint = 3, cluster = 25, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 231, y_advance = 0, x_offset = 0, y_offset = 0})
-                ]
-            }
-        , Fragment
-            { fragmentUserData = "largeText"
-            , fragmentLine = 1
-            , fragmentAncestorBoxes =
-                [ AncestorBox {boxUserData = "largeBox", boxLeftEdge = SpacedEdge 0, boxRightEdge = SpacedEdge 0, boxStartEdge = SpacedEdge 0, boxEndEdge = SpacedEdge 0}
-                ]
-            , fragmentContentRect = Rect {x_origin = 10462, y_origin = -290, x_size = 2549, y_size = -1121}
-            , fragmentRect = Rect {x_origin = 10462, y_origin = 0, x_size = 2549, y_size = -1700}
-            , fragmentPen = (0, -1222)
-            , fragmentGlyphs =
-                [ (GlyphInfo {codepoint = 79, cluster = 26, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 273, y_advance = 0, x_offset = 0, y_offset = 0})
-                , (GlyphInfo {codepoint = 68, cluster = 27, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 522, y_advance = 0, x_offset = 0, y_offset = 0})
-                , (GlyphInfo {codepoint = 85, cluster = 28, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 386, y_advance = 0, x_offset = 0, y_offset = 0})
-                , (GlyphInfo {codepoint = 74, cluster = 29, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 578, y_advance = 0, x_offset = 0, y_offset = 0})
-                , (GlyphInfo {codepoint = 72, cluster = 30, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 559, y_advance = 0, x_offset = 0, y_offset = 0})
-                , (GlyphInfo {codepoint = 3, cluster = 31, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 231, y_advance = 0, x_offset = 0, y_offset = 0})
-                ]
-            }
-        , Fragment
-            { fragmentUserData = "mediumText"
-            , fragmentLine = 1
-            , fragmentAncestorBoxes =
-                []
-            , fragmentContentRect = Rect {x_origin = 13011, y_origin = -90, x_size = 3697, y_size = -1121}
-            , fragmentRect = Rect {x_origin = 13011, y_origin = 0, x_size = 3697, y_size = -1300}
-            , fragmentPen = (0, -1022)
-            , fragmentGlyphs =
-                [ (GlyphInfo {codepoint = 80, cluster = 32, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 861, y_advance = 0, x_offset = 0, y_offset = 0})
-                , (GlyphInfo {codepoint = 72, cluster = 33, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 559, y_advance = 0, x_offset = 0, y_offset = 0})
-                , (GlyphInfo {codepoint = 71, cluster = 34, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 589, y_advance = 0, x_offset = 0, y_offset = 0})
-                , (GlyphInfo {codepoint = 76, cluster = 35, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 253, y_advance = 0, x_offset = 0, y_offset = 0})
-                , (GlyphInfo {codepoint = 88, cluster = 36, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 574, y_advance = 0, x_offset = 0, y_offset = 0})
-                , (GlyphInfo {codepoint = 80, cluster = 37, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 861, y_advance = 0, x_offset = 0, y_offset = 0})
-                ]
-            }
-        , Fragment
-            { fragmentUserData = "lineBreak"
-            , fragmentLine = 1
-            , fragmentAncestorBoxes =
-                []
-            , fragmentContentRect = Rect {x_origin = 16708, y_origin = -90, x_size = 0, y_size = -1121}
-            , fragmentRect = Rect {x_origin = 16708, y_origin = 0, x_size = 0, y_size = -1300}
-            , fragmentPen = (0, -1022)
-            , fragmentGlyphs =
-                []
-            }
-        , Fragment
-            { fragmentUserData = "smallText"
-            , fragmentLine = 2
-            , fragmentAncestorBoxes =
-                [ AncestorBox {boxUserData = "smallBox", boxLeftEdge = SpacedEdge 0, boxRightEdge = SpacedEdge 0, boxStartEdge = SpacedEdge 0, boxEndEdge = SpacedEdge 0}
-                ]
-            , fragmentContentRect = Rect {x_origin = 0, y_origin = -1540, x_size = 2606, y_size = -1121}
-            , fragmentRect = Rect {x_origin = 0, y_origin = -1700, x_size = 2606, y_size = -800}
-            , fragmentPen = (0, -772)
-            , fragmentGlyphs =
-                [ (GlyphInfo {codepoint = 86, cluster = 40, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 446, y_advance = 0, x_offset = 0, y_offset = 0})
-                , (GlyphInfo {codepoint = 80, cluster = 41, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 861, y_advance = 0, x_offset = 0, y_offset = 0})
-                , (GlyphInfo {codepoint = 68, cluster = 42, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 522, y_advance = 0, x_offset = 0, y_offset = 0})
-                , (GlyphInfo {codepoint = 79, cluster = 43, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 273, y_advance = 0, x_offset = 0, y_offset = 0})
-                , (GlyphInfo {codepoint = 79, cluster = 44, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 273, y_advance = 0, x_offset = 0, y_offset = 0})
-                , (GlyphInfo {codepoint = 3, cluster = 45, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 231, y_advance = 0, x_offset = 0, y_offset = 0})
-                ]
-            }
-        , Fragment
-            { fragmentUserData = "mediumText"
-            , fragmentLine = 2
-            , fragmentAncestorBoxes =
-                []
-            , fragmentContentRect = Rect {x_origin = 2606, y_origin = -1790, x_size = 3928, y_size = -1121}
-            , fragmentRect = Rect {x_origin = 2606, y_origin = -1700, x_size = 3928, y_size = -1300}
-            , fragmentPen = (0, -1022)
-            , fragmentGlyphs =
-                [ (GlyphInfo {codepoint = 80, cluster = 46, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 861, y_advance = 0, x_offset = 0, y_offset = 0})
-                , (GlyphInfo {codepoint = 72, cluster = 47, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 559, y_advance = 0, x_offset = 0, y_offset = 0})
-                , (GlyphInfo {codepoint = 71, cluster = 48, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 589, y_advance = 0, x_offset = 0, y_offset = 0})
-                , (GlyphInfo {codepoint = 76, cluster = 49, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 253, y_advance = 0, x_offset = 0, y_offset = 0})
-                , (GlyphInfo {codepoint = 88, cluster = 50, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 574, y_advance = 0, x_offset = 0, y_offset = 0})
-                , (GlyphInfo {codepoint = 80, cluster = 51, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 861, y_advance = 0, x_offset = 0, y_offset = 0})
-                , (GlyphInfo {codepoint = 3, cluster = 52, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 231, y_advance = 0, x_offset = 0, y_offset = 0})
-                ]
-            }
-        , Fragment
-            { fragmentUserData = "largeText"
-            , fragmentLine = 2
-            , fragmentAncestorBoxes =
-                [ AncestorBox {boxUserData = "largeBox", boxLeftEdge = SpacedEdge 0, boxRightEdge = SpacedEdge 0, boxStartEdge = SpacedEdge 0, boxEndEdge = SpacedEdge 0}
-                ]
-            , fragmentContentRect = Rect {x_origin = 6534, y_origin = -1990, x_size = 2318, y_size = -1121}
-            , fragmentRect = Rect {x_origin = 6534, y_origin = -1700, x_size = 2318, y_size = -1700}
-            , fragmentPen = (0, -1222)
-            , fragmentGlyphs =
-                [ (GlyphInfo {codepoint = 79, cluster = 53, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 273, y_advance = 0, x_offset = 0, y_offset = 0})
-                , (GlyphInfo {codepoint = 68, cluster = 54, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 522, y_advance = 0, x_offset = 0, y_offset = 0})
-                , (GlyphInfo {codepoint = 85, cluster = 55, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 386, y_advance = 0, x_offset = 0, y_offset = 0})
-                , (GlyphInfo {codepoint = 74, cluster = 56, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 578, y_advance = 0, x_offset = 0, y_offset = 0})
-                , (GlyphInfo {codepoint = 72, cluster = 57, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 559, y_advance = 0, x_offset = 0, y_offset = 0})
-                ]
-            }
-        , Fragment
-            { fragmentUserData = "lineBreak"
-            , fragmentLine = 2
-            , fragmentAncestorBoxes =
-                []
-            , fragmentContentRect = Rect {x_origin = 8852, y_origin = -1790, x_size = 0, y_size = -1121}
-            , fragmentRect = Rect {x_origin = 8852, y_origin = -1700, x_size = 0, y_size = -1300}
-            , fragmentPen = (0, -1022)
-            , fragmentGlyphs =
-                []
-            }
-        , Fragment
-            { fragmentUserData = "mediumText"
-            , fragmentLine = 3
-            , fragmentAncestorBoxes =
-                []
-            , fragmentContentRect = Rect {x_origin = 0, y_origin = -3490, x_size = 3928, y_size = -1121}
-            , fragmentRect = Rect {x_origin = 0, y_origin = -3400, x_size = 3928, y_size = -1300}
-            , fragmentPen = (0, -1022)
-            , fragmentGlyphs =
-                [ (GlyphInfo {codepoint = 80, cluster = 60, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 861, y_advance = 0, x_offset = 0, y_offset = 0})
-                , (GlyphInfo {codepoint = 72, cluster = 61, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 559, y_advance = 0, x_offset = 0, y_offset = 0})
-                , (GlyphInfo {codepoint = 71, cluster = 62, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 589, y_advance = 0, x_offset = 0, y_offset = 0})
-                , (GlyphInfo {codepoint = 76, cluster = 63, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 253, y_advance = 0, x_offset = 0, y_offset = 0})
-                , (GlyphInfo {codepoint = 88, cluster = 64, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 574, y_advance = 0, x_offset = 0, y_offset = 0})
-                , (GlyphInfo {codepoint = 80, cluster = 65, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 861, y_advance = 0, x_offset = 0, y_offset = 0})
-                , (GlyphInfo {codepoint = 3, cluster = 66, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 231, y_advance = 0, x_offset = 0, y_offset = 0})
-                ]
-            }
-        , Fragment
-            { fragmentUserData = "smallText"
-            , fragmentLine = 3
-            , fragmentAncestorBoxes =
-                [ AncestorBox {boxUserData = "smallBox", boxLeftEdge = SpacedEdge 0, boxRightEdge = SpacedEdge 0, boxStartEdge = SpacedEdge 0, boxEndEdge = SpacedEdge 0}
-                ]
-            , fragmentContentRect = Rect {x_origin = 3928, y_origin = -3240, x_size = 2375, y_size = -1121}
-            , fragmentRect = Rect {x_origin = 3928, y_origin = -3400, x_size = 2375, y_size = -800}
-            , fragmentPen = (0, -772)
-            , fragmentGlyphs =
-                [ (GlyphInfo {codepoint = 86, cluster = 67, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 446, y_advance = 0, x_offset = 0, y_offset = 0})
-                , (GlyphInfo {codepoint = 80, cluster = 68, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 861, y_advance = 0, x_offset = 0, y_offset = 0})
-                , (GlyphInfo {codepoint = 68, cluster = 69, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 522, y_advance = 0, x_offset = 0, y_offset = 0})
-                , (GlyphInfo {codepoint = 79, cluster = 70, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 273, y_advance = 0, x_offset = 0, y_offset = 0})
-                , (GlyphInfo {codepoint = 79, cluster = 71, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 273, y_advance = 0, x_offset = 0, y_offset = 0})
-                ]
-            }
-        , Fragment
-            { fragmentUserData = "lineBreak"
-            , fragmentLine = 3
-            , fragmentAncestorBoxes =
-                []
-            , fragmentContentRect = Rect {x_origin = 6303, y_origin = -3490, x_size = 0, y_size = -1121}
-            , fragmentRect = Rect {x_origin = 6303, y_origin = -3400, x_size = 0, y_size = -1300}
-            , fragmentPen = (0, -1022)
-            , fragmentGlyphs =
-                []
-            }
-        , Fragment
-            { fragmentUserData = "largeText"
-            , fragmentLine = 4
-            , fragmentAncestorBoxes =
-                [ AncestorBox {boxUserData = "largeBox", boxLeftEdge = SpacedEdge 0, boxRightEdge = SpacedEdge 0, boxStartEdge = SpacedEdge 0, boxEndEdge = SpacedEdge 0}
-                ]
-            , fragmentContentRect = Rect {x_origin = 0, y_origin = -4990, x_size = 2549, y_size = -1121}
-            , fragmentRect = Rect {x_origin = 0, y_origin = -4700, x_size = 2549, y_size = -1700}
-            , fragmentPen = (0, -1222)
-            , fragmentGlyphs =
-                [ (GlyphInfo {codepoint = 79, cluster = 74, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 273, y_advance = 0, x_offset = 0, y_offset = 0})
-                , (GlyphInfo {codepoint = 68, cluster = 75, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 522, y_advance = 0, x_offset = 0, y_offset = 0})
-                , (GlyphInfo {codepoint = 85, cluster = 76, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 386, y_advance = 0, x_offset = 0, y_offset = 0})
-                , (GlyphInfo {codepoint = 74, cluster = 77, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 578, y_advance = 0, x_offset = 0, y_offset = 0})
-                , (GlyphInfo {codepoint = 72, cluster = 78, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 559, y_advance = 0, x_offset = 0, y_offset = 0})
-                , (GlyphInfo {codepoint = 3, cluster = 79, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 231, y_advance = 0, x_offset = 0, y_offset = 0})
-                ]
-            }
-        , Fragment
-            { fragmentUserData = "mediumText"
-            , fragmentLine = 4
-            , fragmentAncestorBoxes =
-                []
-            , fragmentContentRect = Rect {x_origin = 2549, y_origin = -4790, x_size = 3697, y_size = -1121}
-            , fragmentRect = Rect {x_origin = 2549, y_origin = -4700, x_size = 3697, y_size = -1300}
-            , fragmentPen = (0, -1022)
-            , fragmentGlyphs =
-                [ (GlyphInfo {codepoint = 80, cluster = 80, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 861, y_advance = 0, x_offset = 0, y_offset = 0})
-                , (GlyphInfo {codepoint = 72, cluster = 81, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 559, y_advance = 0, x_offset = 0, y_offset = 0})
-                , (GlyphInfo {codepoint = 71, cluster = 82, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 589, y_advance = 0, x_offset = 0, y_offset = 0})
-                , (GlyphInfo {codepoint = 76, cluster = 83, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 253, y_advance = 0, x_offset = 0, y_offset = 0})
-                , (GlyphInfo {codepoint = 88, cluster = 84, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 574, y_advance = 0, x_offset = 0, y_offset = 0})
-                , (GlyphInfo {codepoint = 80, cluster = 85, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 861, y_advance = 0, x_offset = 0, y_offset = 0})
-                ]
-            }
-        , Fragment
-            { fragmentUserData = "lineBreak"
-            , fragmentLine = 4
-            , fragmentAncestorBoxes =
-                []
-            , fragmentContentRect = Rect {x_origin = 6246, y_origin = -4790, x_size = 0, y_size = -1121}
-            , fragmentRect = Rect {x_origin = 6246, y_origin = -4700, x_size = 0, y_size = -1300}
-            , fragmentPen = (0, -1022)
-            , fragmentGlyphs =
-                []
-            }
-        , Fragment
-            { fragmentUserData = "smallText"
-            , fragmentLine = 5
-            , fragmentAncestorBoxes =
-                [ AncestorBox {boxUserData = "smallBox", boxLeftEdge = SpacedEdge 0, boxRightEdge = SpacedEdge 0, boxStartEdge = SpacedEdge 0, boxEndEdge = SpacedEdge 0}
-                ]
-            , fragmentContentRect = Rect {x_origin = 0, y_origin = -6240, x_size = 2375, y_size = -1121}
-            , fragmentRect = Rect {x_origin = 0, y_origin = -6400, x_size = 2375, y_size = -800}
-            , fragmentPen = (0, -772)
-            , fragmentGlyphs =
-                [ (GlyphInfo {codepoint = 86, cluster = 88, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 446, y_advance = 0, x_offset = 0, y_offset = 0})
-                , (GlyphInfo {codepoint = 80, cluster = 89, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 861, y_advance = 0, x_offset = 0, y_offset = 0})
-                , (GlyphInfo {codepoint = 68, cluster = 90, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 522, y_advance = 0, x_offset = 0, y_offset = 0})
-                , (GlyphInfo {codepoint = 79, cluster = 91, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 273, y_advance = 0, x_offset = 0, y_offset = 0})
-                , (GlyphInfo {codepoint = 79, cluster = 92, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 273, y_advance = 0, x_offset = 0, y_offset = 0})
-                ]
-            }
-        , Fragment
-            { fragmentUserData = "lineBreak"
-            , fragmentLine = 5
-            , fragmentAncestorBoxes =
-                []
-            , fragmentContentRect = Rect {x_origin = 2375, y_origin = -6490, x_size = 0, y_size = -1121}
-            , fragmentRect = Rect {x_origin = 2375, y_origin = -6400, x_size = 0, y_size = -1300}
-            , fragmentPen = (0, -1022)
-            , fragmentGlyphs =
-                []
-            }
-        , Fragment
-            { fragmentUserData = "largeText"
-            , fragmentLine = 6
-            , fragmentAncestorBoxes =
-                [ AncestorBox {boxUserData = "largeBox", boxLeftEdge = SpacedEdge 0, boxRightEdge = SpacedEdge 0, boxStartEdge = SpacedEdge 0, boxEndEdge = SpacedEdge 0}
-                ]
-            , fragmentContentRect = Rect {x_origin = 0, y_origin = -7990, x_size = 2318, y_size = -1121}
-            , fragmentRect = Rect {x_origin = 0, y_origin = -7700, x_size = 2318, y_size = -1700}
-            , fragmentPen = (0, -1222)
-            , fragmentGlyphs =
-                [ (GlyphInfo {codepoint = 79, cluster = 95, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 273, y_advance = 0, x_offset = 0, y_offset = 0})
-                , (GlyphInfo {codepoint = 68, cluster = 96, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 522, y_advance = 0, x_offset = 0, y_offset = 0})
-                , (GlyphInfo {codepoint = 85, cluster = 97, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 386, y_advance = 0, x_offset = 0, y_offset = 0})
-                , (GlyphInfo {codepoint = 74, cluster = 98, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 578, y_advance = 0, x_offset = 0, y_offset = 0})
-                , (GlyphInfo {codepoint = 72, cluster = 99, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 559, y_advance = 0, x_offset = 0, y_offset = 0})
-                ]
-            }
-        ]
-    }
diff --git a/.golden/richParagraphLayout/mixedLineHeightBaseline.golden b/.golden/richParagraphLayout/mixedLineHeightBaseline.golden
new file mode 100644
--- /dev/null
+++ b/.golden/richParagraphLayout/mixedLineHeightBaseline.golden
@@ -0,0 +1,314 @@
+ParagraphLayout
+    { paragraphRect = Rect {x_origin = 0, y_origin = 0, x_size = 16708, y_size = -9400}
+    , paragraphLines =
+        [ Line {lineNumber = 1, lineRect = Rect {x_origin = 0, y_origin = 0, x_size = 16708, y_size = -1700}}
+        , Line {lineNumber = 2, lineRect = Rect {x_origin = 0, y_origin = -1700, x_size = 16708, y_size = -1700}}
+        , Line {lineNumber = 3, lineRect = Rect {x_origin = 0, y_origin = -3400, x_size = 16708, y_size = -1300}}
+        , Line {lineNumber = 4, lineRect = Rect {x_origin = 0, y_origin = -4700, x_size = 16708, y_size = -1700}}
+        , Line {lineNumber = 5, lineRect = Rect {x_origin = 0, y_origin = -6400, x_size = 16708, y_size = -1300}}
+        , Line {lineNumber = 6, lineRect = Rect {x_origin = 0, y_origin = -7700, x_size = 16708, y_size = -1700}}
+        ]
+    , paragraphFragments =
+        [ Fragment
+            { fragmentUserData = "mediumText"
+            , fragmentLine = 1
+            , fragmentAncestorBoxes =
+                []
+            , fragmentContentRect = Rect {x_origin = 0, y_origin = -290, x_size = 3928, y_size = -1121}
+            , fragmentRect = Rect {x_origin = 0, y_origin = -200, x_size = 3928, y_size = -1300}
+            , fragmentPen = (0, -1022)
+            , fragmentGlyphs =
+                [ (GlyphInfo {codepoint = 80, cluster = 6, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 861, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 72, cluster = 7, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 559, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 71, cluster = 8, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 589, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 76, cluster = 9, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 253, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 88, cluster = 10, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 574, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 80, cluster = 11, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 861, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 3, cluster = 12, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 231, y_advance = 0, x_offset = 0, y_offset = 0})
+                ]
+            }
+        , Fragment
+            { fragmentUserData = "smallText"
+            , fragmentLine = 1
+            , fragmentAncestorBoxes =
+                [ AncestorBox {boxUserData = "smallBox", boxLeftEdge = SpacedEdge 0, boxRightEdge = SpacedEdge 0, boxStartEdge = SpacedEdge 0, boxEndEdge = SpacedEdge 0}
+                ]
+            , fragmentContentRect = Rect {x_origin = 3928, y_origin = -290, x_size = 2606, y_size = -1121}
+            , fragmentRect = Rect {x_origin = 3928, y_origin = -450, x_size = 2606, y_size = -800}
+            , fragmentPen = (0, -772)
+            , fragmentGlyphs =
+                [ (GlyphInfo {codepoint = 86, cluster = 13, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 446, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 80, cluster = 14, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 861, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 68, cluster = 15, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 522, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 79, cluster = 16, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 273, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 79, cluster = 17, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 273, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 3, cluster = 18, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 231, y_advance = 0, x_offset = 0, y_offset = 0})
+                ]
+            }
+        , Fragment
+            { fragmentUserData = "mediumText"
+            , fragmentLine = 1
+            , fragmentAncestorBoxes =
+                []
+            , fragmentContentRect = Rect {x_origin = 6534, y_origin = -290, x_size = 3928, y_size = -1121}
+            , fragmentRect = Rect {x_origin = 6534, y_origin = -200, x_size = 3928, y_size = -1300}
+            , fragmentPen = (0, -1022)
+            , fragmentGlyphs =
+                [ (GlyphInfo {codepoint = 80, cluster = 19, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 861, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 72, cluster = 20, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 559, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 71, cluster = 21, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 589, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 76, cluster = 22, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 253, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 88, cluster = 23, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 574, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 80, cluster = 24, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 861, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 3, cluster = 25, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 231, y_advance = 0, x_offset = 0, y_offset = 0})
+                ]
+            }
+        , Fragment
+            { fragmentUserData = "largeText"
+            , fragmentLine = 1
+            , fragmentAncestorBoxes =
+                [ AncestorBox {boxUserData = "largeBox", boxLeftEdge = SpacedEdge 0, boxRightEdge = SpacedEdge 0, boxStartEdge = SpacedEdge 0, boxEndEdge = SpacedEdge 0}
+                ]
+            , fragmentContentRect = Rect {x_origin = 10462, y_origin = -290, x_size = 2549, y_size = -1121}
+            , fragmentRect = Rect {x_origin = 10462, y_origin = 0, x_size = 2549, y_size = -1700}
+            , fragmentPen = (0, -1222)
+            , fragmentGlyphs =
+                [ (GlyphInfo {codepoint = 79, cluster = 26, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 273, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 68, cluster = 27, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 522, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 85, cluster = 28, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 386, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 74, cluster = 29, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 578, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 72, cluster = 30, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 559, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 3, cluster = 31, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 231, y_advance = 0, x_offset = 0, y_offset = 0})
+                ]
+            }
+        , Fragment
+            { fragmentUserData = "mediumText"
+            , fragmentLine = 1
+            , fragmentAncestorBoxes =
+                []
+            , fragmentContentRect = Rect {x_origin = 13011, y_origin = -290, x_size = 3697, y_size = -1121}
+            , fragmentRect = Rect {x_origin = 13011, y_origin = -200, x_size = 3697, y_size = -1300}
+            , fragmentPen = (0, -1022)
+            , fragmentGlyphs =
+                [ (GlyphInfo {codepoint = 80, cluster = 32, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 861, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 72, cluster = 33, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 559, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 71, cluster = 34, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 589, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 76, cluster = 35, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 253, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 88, cluster = 36, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 574, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 80, cluster = 37, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 861, y_advance = 0, x_offset = 0, y_offset = 0})
+                ]
+            }
+        , Fragment
+            { fragmentUserData = "lineBreak"
+            , fragmentLine = 1
+            , fragmentAncestorBoxes =
+                []
+            , fragmentContentRect = Rect {x_origin = 16708, y_origin = -290, x_size = 0, y_size = -1121}
+            , fragmentRect = Rect {x_origin = 16708, y_origin = -200, x_size = 0, y_size = -1300}
+            , fragmentPen = (0, -1022)
+            , fragmentGlyphs =
+                []
+            }
+        , Fragment
+            { fragmentUserData = "smallText"
+            , fragmentLine = 2
+            , fragmentAncestorBoxes =
+                [ AncestorBox {boxUserData = "smallBox", boxLeftEdge = SpacedEdge 0, boxRightEdge = SpacedEdge 0, boxStartEdge = SpacedEdge 0, boxEndEdge = SpacedEdge 0}
+                ]
+            , fragmentContentRect = Rect {x_origin = 0, y_origin = -1990, x_size = 2606, y_size = -1121}
+            , fragmentRect = Rect {x_origin = 0, y_origin = -2150, x_size = 2606, y_size = -800}
+            , fragmentPen = (0, -772)
+            , fragmentGlyphs =
+                [ (GlyphInfo {codepoint = 86, cluster = 40, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 446, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 80, cluster = 41, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 861, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 68, cluster = 42, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 522, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 79, cluster = 43, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 273, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 79, cluster = 44, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 273, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 3, cluster = 45, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 231, y_advance = 0, x_offset = 0, y_offset = 0})
+                ]
+            }
+        , Fragment
+            { fragmentUserData = "mediumText"
+            , fragmentLine = 2
+            , fragmentAncestorBoxes =
+                []
+            , fragmentContentRect = Rect {x_origin = 2606, y_origin = -1990, x_size = 3928, y_size = -1121}
+            , fragmentRect = Rect {x_origin = 2606, y_origin = -1900, x_size = 3928, y_size = -1300}
+            , fragmentPen = (0, -1022)
+            , fragmentGlyphs =
+                [ (GlyphInfo {codepoint = 80, cluster = 46, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 861, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 72, cluster = 47, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 559, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 71, cluster = 48, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 589, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 76, cluster = 49, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 253, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 88, cluster = 50, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 574, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 80, cluster = 51, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 861, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 3, cluster = 52, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 231, y_advance = 0, x_offset = 0, y_offset = 0})
+                ]
+            }
+        , Fragment
+            { fragmentUserData = "largeText"
+            , fragmentLine = 2
+            , fragmentAncestorBoxes =
+                [ AncestorBox {boxUserData = "largeBox", boxLeftEdge = SpacedEdge 0, boxRightEdge = SpacedEdge 0, boxStartEdge = SpacedEdge 0, boxEndEdge = SpacedEdge 0}
+                ]
+            , fragmentContentRect = Rect {x_origin = 6534, y_origin = -1990, x_size = 2318, y_size = -1121}
+            , fragmentRect = Rect {x_origin = 6534, y_origin = -1700, x_size = 2318, y_size = -1700}
+            , fragmentPen = (0, -1222)
+            , fragmentGlyphs =
+                [ (GlyphInfo {codepoint = 79, cluster = 53, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 273, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 68, cluster = 54, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 522, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 85, cluster = 55, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 386, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 74, cluster = 56, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 578, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 72, cluster = 57, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 559, y_advance = 0, x_offset = 0, y_offset = 0})
+                ]
+            }
+        , Fragment
+            { fragmentUserData = "lineBreak"
+            , fragmentLine = 2
+            , fragmentAncestorBoxes =
+                []
+            , fragmentContentRect = Rect {x_origin = 8852, y_origin = -1990, x_size = 0, y_size = -1121}
+            , fragmentRect = Rect {x_origin = 8852, y_origin = -1900, x_size = 0, y_size = -1300}
+            , fragmentPen = (0, -1022)
+            , fragmentGlyphs =
+                []
+            }
+        , Fragment
+            { fragmentUserData = "mediumText"
+            , fragmentLine = 3
+            , fragmentAncestorBoxes =
+                []
+            , fragmentContentRect = Rect {x_origin = 0, y_origin = -3490, x_size = 3928, y_size = -1121}
+            , fragmentRect = Rect {x_origin = 0, y_origin = -3400, x_size = 3928, y_size = -1300}
+            , fragmentPen = (0, -1022)
+            , fragmentGlyphs =
+                [ (GlyphInfo {codepoint = 80, cluster = 60, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 861, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 72, cluster = 61, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 559, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 71, cluster = 62, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 589, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 76, cluster = 63, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 253, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 88, cluster = 64, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 574, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 80, cluster = 65, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 861, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 3, cluster = 66, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 231, y_advance = 0, x_offset = 0, y_offset = 0})
+                ]
+            }
+        , Fragment
+            { fragmentUserData = "smallText"
+            , fragmentLine = 3
+            , fragmentAncestorBoxes =
+                [ AncestorBox {boxUserData = "smallBox", boxLeftEdge = SpacedEdge 0, boxRightEdge = SpacedEdge 0, boxStartEdge = SpacedEdge 0, boxEndEdge = SpacedEdge 0}
+                ]
+            , fragmentContentRect = Rect {x_origin = 3928, y_origin = -3490, x_size = 2375, y_size = -1121}
+            , fragmentRect = Rect {x_origin = 3928, y_origin = -3650, x_size = 2375, y_size = -800}
+            , fragmentPen = (0, -772)
+            , fragmentGlyphs =
+                [ (GlyphInfo {codepoint = 86, cluster = 67, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 446, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 80, cluster = 68, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 861, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 68, cluster = 69, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 522, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 79, cluster = 70, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 273, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 79, cluster = 71, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 273, y_advance = 0, x_offset = 0, y_offset = 0})
+                ]
+            }
+        , Fragment
+            { fragmentUserData = "lineBreak"
+            , fragmentLine = 3
+            , fragmentAncestorBoxes =
+                []
+            , fragmentContentRect = Rect {x_origin = 6303, y_origin = -3490, x_size = 0, y_size = -1121}
+            , fragmentRect = Rect {x_origin = 6303, y_origin = -3400, x_size = 0, y_size = -1300}
+            , fragmentPen = (0, -1022)
+            , fragmentGlyphs =
+                []
+            }
+        , Fragment
+            { fragmentUserData = "largeText"
+            , fragmentLine = 4
+            , fragmentAncestorBoxes =
+                [ AncestorBox {boxUserData = "largeBox", boxLeftEdge = SpacedEdge 0, boxRightEdge = SpacedEdge 0, boxStartEdge = SpacedEdge 0, boxEndEdge = SpacedEdge 0}
+                ]
+            , fragmentContentRect = Rect {x_origin = 0, y_origin = -4990, x_size = 2549, y_size = -1121}
+            , fragmentRect = Rect {x_origin = 0, y_origin = -4700, x_size = 2549, y_size = -1700}
+            , fragmentPen = (0, -1222)
+            , fragmentGlyphs =
+                [ (GlyphInfo {codepoint = 79, cluster = 74, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 273, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 68, cluster = 75, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 522, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 85, cluster = 76, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 386, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 74, cluster = 77, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 578, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 72, cluster = 78, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 559, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 3, cluster = 79, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 231, y_advance = 0, x_offset = 0, y_offset = 0})
+                ]
+            }
+        , Fragment
+            { fragmentUserData = "mediumText"
+            , fragmentLine = 4
+            , fragmentAncestorBoxes =
+                []
+            , fragmentContentRect = Rect {x_origin = 2549, y_origin = -4990, x_size = 3697, y_size = -1121}
+            , fragmentRect = Rect {x_origin = 2549, y_origin = -4900, x_size = 3697, y_size = -1300}
+            , fragmentPen = (0, -1022)
+            , fragmentGlyphs =
+                [ (GlyphInfo {codepoint = 80, cluster = 80, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 861, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 72, cluster = 81, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 559, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 71, cluster = 82, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 589, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 76, cluster = 83, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 253, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 88, cluster = 84, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 574, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 80, cluster = 85, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 861, y_advance = 0, x_offset = 0, y_offset = 0})
+                ]
+            }
+        , Fragment
+            { fragmentUserData = "lineBreak"
+            , fragmentLine = 4
+            , fragmentAncestorBoxes =
+                []
+            , fragmentContentRect = Rect {x_origin = 6246, y_origin = -4990, x_size = 0, y_size = -1121}
+            , fragmentRect = Rect {x_origin = 6246, y_origin = -4900, x_size = 0, y_size = -1300}
+            , fragmentPen = (0, -1022)
+            , fragmentGlyphs =
+                []
+            }
+        , Fragment
+            { fragmentUserData = "smallText"
+            , fragmentLine = 5
+            , fragmentAncestorBoxes =
+                [ AncestorBox {boxUserData = "smallBox", boxLeftEdge = SpacedEdge 0, boxRightEdge = SpacedEdge 0, boxStartEdge = SpacedEdge 0, boxEndEdge = SpacedEdge 0}
+                ]
+            , fragmentContentRect = Rect {x_origin = 0, y_origin = -6490, x_size = 2375, y_size = -1121}
+            , fragmentRect = Rect {x_origin = 0, y_origin = -6650, x_size = 2375, y_size = -800}
+            , fragmentPen = (0, -772)
+            , fragmentGlyphs =
+                [ (GlyphInfo {codepoint = 86, cluster = 88, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 446, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 80, cluster = 89, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 861, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 68, cluster = 90, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 522, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 79, cluster = 91, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 273, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 79, cluster = 92, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 273, y_advance = 0, x_offset = 0, y_offset = 0})
+                ]
+            }
+        , Fragment
+            { fragmentUserData = "lineBreak"
+            , fragmentLine = 5
+            , fragmentAncestorBoxes =
+                []
+            , fragmentContentRect = Rect {x_origin = 2375, y_origin = -6490, x_size = 0, y_size = -1121}
+            , fragmentRect = Rect {x_origin = 2375, y_origin = -6400, x_size = 0, y_size = -1300}
+            , fragmentPen = (0, -1022)
+            , fragmentGlyphs =
+                []
+            }
+        , Fragment
+            { fragmentUserData = "largeText"
+            , fragmentLine = 6
+            , fragmentAncestorBoxes =
+                [ AncestorBox {boxUserData = "largeBox", boxLeftEdge = SpacedEdge 0, boxRightEdge = SpacedEdge 0, boxStartEdge = SpacedEdge 0, boxEndEdge = SpacedEdge 0}
+                ]
+            , fragmentContentRect = Rect {x_origin = 0, y_origin = -7990, x_size = 2318, y_size = -1121}
+            , fragmentRect = Rect {x_origin = 0, y_origin = -7700, x_size = 2318, y_size = -1700}
+            , fragmentPen = (0, -1222)
+            , fragmentGlyphs =
+                [ (GlyphInfo {codepoint = 79, cluster = 95, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 273, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 68, cluster = 96, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 522, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 85, cluster = 97, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 386, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 74, cluster = 98, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 578, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 72, cluster = 99, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 559, y_advance = 0, x_offset = 0, y_offset = 0})
+                ]
+            }
+        ]
+    }
diff --git a/.golden/richParagraphLayout/mixedLineHeightBaseline3.golden b/.golden/richParagraphLayout/mixedLineHeightBaseline3.golden
new file mode 100644
--- /dev/null
+++ b/.golden/richParagraphLayout/mixedLineHeightBaseline3.golden
@@ -0,0 +1,314 @@
+ParagraphLayout
+    { paragraphRect = Rect {x_origin = 0, y_origin = 0, x_size = 16708, y_size = -9400}
+    , paragraphLines =
+        [ Line {lineNumber = 1, lineRect = Rect {x_origin = 0, y_origin = 0, x_size = 16708, y_size = -1700}}
+        , Line {lineNumber = 2, lineRect = Rect {x_origin = 0, y_origin = -1700, x_size = 16708, y_size = -1700}}
+        , Line {lineNumber = 3, lineRect = Rect {x_origin = 0, y_origin = -3400, x_size = 16708, y_size = -1300}}
+        , Line {lineNumber = 4, lineRect = Rect {x_origin = 0, y_origin = -4700, x_size = 16708, y_size = -1700}}
+        , Line {lineNumber = 5, lineRect = Rect {x_origin = 0, y_origin = -6400, x_size = 16708, y_size = -1300}}
+        , Line {lineNumber = 6, lineRect = Rect {x_origin = 0, y_origin = -7700, x_size = 16708, y_size = -1700}}
+        ]
+    , paragraphFragments =
+        [ Fragment
+            { fragmentUserData = "mediumText"
+            , fragmentLine = 1
+            , fragmentAncestorBoxes =
+                []
+            , fragmentContentRect = Rect {x_origin = 0, y_origin = -293, x_size = 3928, y_size = -1121}
+            , fragmentRect = Rect {x_origin = 0, y_origin = -203, x_size = 3928, y_size = -1300}
+            , fragmentPen = (0, -1022)
+            , fragmentGlyphs =
+                [ (GlyphInfo {codepoint = 80, cluster = 6, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 861, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 72, cluster = 7, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 559, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 71, cluster = 8, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 589, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 76, cluster = 9, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 253, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 88, cluster = 10, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 574, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 80, cluster = 11, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 861, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 3, cluster = 12, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 231, y_advance = 0, x_offset = 0, y_offset = 0})
+                ]
+            }
+        , Fragment
+            { fragmentUserData = "smallText"
+            , fragmentLine = 1
+            , fragmentAncestorBoxes =
+                [ AncestorBox {boxUserData = "smallBox", boxLeftEdge = SpacedEdge 0, boxRightEdge = SpacedEdge 0, boxStartEdge = SpacedEdge 0, boxEndEdge = SpacedEdge 0}
+                ]
+            , fragmentContentRect = Rect {x_origin = 3928, y_origin = -290, x_size = 2606, y_size = -1121}
+            , fragmentRect = Rect {x_origin = 3928, y_origin = -450, x_size = 2606, y_size = -800}
+            , fragmentPen = (0, -772)
+            , fragmentGlyphs =
+                [ (GlyphInfo {codepoint = 86, cluster = 13, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 446, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 80, cluster = 14, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 861, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 68, cluster = 15, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 522, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 79, cluster = 16, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 273, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 79, cluster = 17, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 273, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 3, cluster = 18, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 231, y_advance = 0, x_offset = 0, y_offset = 0})
+                ]
+            }
+        , Fragment
+            { fragmentUserData = "mediumText"
+            , fragmentLine = 1
+            , fragmentAncestorBoxes =
+                []
+            , fragmentContentRect = Rect {x_origin = 6534, y_origin = -293, x_size = 3928, y_size = -1121}
+            , fragmentRect = Rect {x_origin = 6534, y_origin = -203, x_size = 3928, y_size = -1300}
+            , fragmentPen = (0, -1022)
+            , fragmentGlyphs =
+                [ (GlyphInfo {codepoint = 80, cluster = 19, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 861, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 72, cluster = 20, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 559, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 71, cluster = 21, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 589, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 76, cluster = 22, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 253, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 88, cluster = 23, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 574, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 80, cluster = 24, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 861, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 3, cluster = 25, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 231, y_advance = 0, x_offset = 0, y_offset = 0})
+                ]
+            }
+        , Fragment
+            { fragmentUserData = "largeText"
+            , fragmentLine = 1
+            , fragmentAncestorBoxes =
+                [ AncestorBox {boxUserData = "largeBox", boxLeftEdge = SpacedEdge 0, boxRightEdge = SpacedEdge 0, boxStartEdge = SpacedEdge 0, boxEndEdge = SpacedEdge 0}
+                ]
+            , fragmentContentRect = Rect {x_origin = 10462, y_origin = -290, x_size = 2549, y_size = -1121}
+            , fragmentRect = Rect {x_origin = 10462, y_origin = 0, x_size = 2549, y_size = -1700}
+            , fragmentPen = (0, -1222)
+            , fragmentGlyphs =
+                [ (GlyphInfo {codepoint = 79, cluster = 26, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 273, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 68, cluster = 27, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 522, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 85, cluster = 28, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 386, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 74, cluster = 29, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 578, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 72, cluster = 30, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 559, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 3, cluster = 31, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 231, y_advance = 0, x_offset = 0, y_offset = 0})
+                ]
+            }
+        , Fragment
+            { fragmentUserData = "mediumText"
+            , fragmentLine = 1
+            , fragmentAncestorBoxes =
+                []
+            , fragmentContentRect = Rect {x_origin = 13011, y_origin = -293, x_size = 3697, y_size = -1121}
+            , fragmentRect = Rect {x_origin = 13011, y_origin = -203, x_size = 3697, y_size = -1300}
+            , fragmentPen = (0, -1022)
+            , fragmentGlyphs =
+                [ (GlyphInfo {codepoint = 80, cluster = 32, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 861, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 72, cluster = 33, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 559, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 71, cluster = 34, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 589, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 76, cluster = 35, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 253, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 88, cluster = 36, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 574, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 80, cluster = 37, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 861, y_advance = 0, x_offset = 0, y_offset = 0})
+                ]
+            }
+        , Fragment
+            { fragmentUserData = "lineBreak"
+            , fragmentLine = 1
+            , fragmentAncestorBoxes =
+                []
+            , fragmentContentRect = Rect {x_origin = 16708, y_origin = -293, x_size = 0, y_size = -1121}
+            , fragmentRect = Rect {x_origin = 16708, y_origin = -203, x_size = 0, y_size = -1300}
+            , fragmentPen = (0, -1022)
+            , fragmentGlyphs =
+                []
+            }
+        , Fragment
+            { fragmentUserData = "smallText"
+            , fragmentLine = 2
+            , fragmentAncestorBoxes =
+                [ AncestorBox {boxUserData = "smallBox", boxLeftEdge = SpacedEdge 0, boxRightEdge = SpacedEdge 0, boxStartEdge = SpacedEdge 0, boxEndEdge = SpacedEdge 0}
+                ]
+            , fragmentContentRect = Rect {x_origin = 0, y_origin = -1990, x_size = 2606, y_size = -1121}
+            , fragmentRect = Rect {x_origin = 0, y_origin = -2150, x_size = 2606, y_size = -800}
+            , fragmentPen = (0, -772)
+            , fragmentGlyphs =
+                [ (GlyphInfo {codepoint = 86, cluster = 40, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 446, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 80, cluster = 41, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 861, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 68, cluster = 42, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 522, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 79, cluster = 43, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 273, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 79, cluster = 44, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 273, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 3, cluster = 45, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 231, y_advance = 0, x_offset = 0, y_offset = 0})
+                ]
+            }
+        , Fragment
+            { fragmentUserData = "mediumText"
+            , fragmentLine = 2
+            , fragmentAncestorBoxes =
+                []
+            , fragmentContentRect = Rect {x_origin = 2606, y_origin = -1993, x_size = 3928, y_size = -1121}
+            , fragmentRect = Rect {x_origin = 2606, y_origin = -1903, x_size = 3928, y_size = -1300}
+            , fragmentPen = (0, -1022)
+            , fragmentGlyphs =
+                [ (GlyphInfo {codepoint = 80, cluster = 46, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 861, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 72, cluster = 47, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 559, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 71, cluster = 48, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 589, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 76, cluster = 49, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 253, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 88, cluster = 50, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 574, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 80, cluster = 51, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 861, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 3, cluster = 52, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 231, y_advance = 0, x_offset = 0, y_offset = 0})
+                ]
+            }
+        , Fragment
+            { fragmentUserData = "largeText"
+            , fragmentLine = 2
+            , fragmentAncestorBoxes =
+                [ AncestorBox {boxUserData = "largeBox", boxLeftEdge = SpacedEdge 0, boxRightEdge = SpacedEdge 0, boxStartEdge = SpacedEdge 0, boxEndEdge = SpacedEdge 0}
+                ]
+            , fragmentContentRect = Rect {x_origin = 6534, y_origin = -1990, x_size = 2318, y_size = -1121}
+            , fragmentRect = Rect {x_origin = 6534, y_origin = -1700, x_size = 2318, y_size = -1700}
+            , fragmentPen = (0, -1222)
+            , fragmentGlyphs =
+                [ (GlyphInfo {codepoint = 79, cluster = 53, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 273, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 68, cluster = 54, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 522, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 85, cluster = 55, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 386, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 74, cluster = 56, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 578, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 72, cluster = 57, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 559, y_advance = 0, x_offset = 0, y_offset = 0})
+                ]
+            }
+        , Fragment
+            { fragmentUserData = "lineBreak"
+            , fragmentLine = 2
+            , fragmentAncestorBoxes =
+                []
+            , fragmentContentRect = Rect {x_origin = 8852, y_origin = -1993, x_size = 0, y_size = -1121}
+            , fragmentRect = Rect {x_origin = 8852, y_origin = -1903, x_size = 0, y_size = -1300}
+            , fragmentPen = (0, -1022)
+            , fragmentGlyphs =
+                []
+            }
+        , Fragment
+            { fragmentUserData = "mediumText"
+            , fragmentLine = 3
+            , fragmentAncestorBoxes =
+                []
+            , fragmentContentRect = Rect {x_origin = 0, y_origin = -3490, x_size = 3928, y_size = -1121}
+            , fragmentRect = Rect {x_origin = 0, y_origin = -3400, x_size = 3928, y_size = -1300}
+            , fragmentPen = (0, -1022)
+            , fragmentGlyphs =
+                [ (GlyphInfo {codepoint = 80, cluster = 60, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 861, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 72, cluster = 61, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 559, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 71, cluster = 62, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 589, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 76, cluster = 63, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 253, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 88, cluster = 64, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 574, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 80, cluster = 65, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 861, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 3, cluster = 66, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 231, y_advance = 0, x_offset = 0, y_offset = 0})
+                ]
+            }
+        , Fragment
+            { fragmentUserData = "smallText"
+            , fragmentLine = 3
+            , fragmentAncestorBoxes =
+                [ AncestorBox {boxUserData = "smallBox", boxLeftEdge = SpacedEdge 0, boxRightEdge = SpacedEdge 0, boxStartEdge = SpacedEdge 0, boxEndEdge = SpacedEdge 0}
+                ]
+            , fragmentContentRect = Rect {x_origin = 3928, y_origin = -3487, x_size = 2375, y_size = -1121}
+            , fragmentRect = Rect {x_origin = 3928, y_origin = -3647, x_size = 2375, y_size = -800}
+            , fragmentPen = (0, -772)
+            , fragmentGlyphs =
+                [ (GlyphInfo {codepoint = 86, cluster = 67, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 446, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 80, cluster = 68, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 861, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 68, cluster = 69, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 522, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 79, cluster = 70, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 273, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 79, cluster = 71, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 273, y_advance = 0, x_offset = 0, y_offset = 0})
+                ]
+            }
+        , Fragment
+            { fragmentUserData = "lineBreak"
+            , fragmentLine = 3
+            , fragmentAncestorBoxes =
+                []
+            , fragmentContentRect = Rect {x_origin = 6303, y_origin = -3490, x_size = 0, y_size = -1121}
+            , fragmentRect = Rect {x_origin = 6303, y_origin = -3400, x_size = 0, y_size = -1300}
+            , fragmentPen = (0, -1022)
+            , fragmentGlyphs =
+                []
+            }
+        , Fragment
+            { fragmentUserData = "largeText"
+            , fragmentLine = 4
+            , fragmentAncestorBoxes =
+                [ AncestorBox {boxUserData = "largeBox", boxLeftEdge = SpacedEdge 0, boxRightEdge = SpacedEdge 0, boxStartEdge = SpacedEdge 0, boxEndEdge = SpacedEdge 0}
+                ]
+            , fragmentContentRect = Rect {x_origin = 0, y_origin = -4990, x_size = 2549, y_size = -1121}
+            , fragmentRect = Rect {x_origin = 0, y_origin = -4700, x_size = 2549, y_size = -1700}
+            , fragmentPen = (0, -1222)
+            , fragmentGlyphs =
+                [ (GlyphInfo {codepoint = 79, cluster = 74, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 273, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 68, cluster = 75, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 522, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 85, cluster = 76, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 386, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 74, cluster = 77, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 578, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 72, cluster = 78, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 559, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 3, cluster = 79, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 231, y_advance = 0, x_offset = 0, y_offset = 0})
+                ]
+            }
+        , Fragment
+            { fragmentUserData = "mediumText"
+            , fragmentLine = 4
+            , fragmentAncestorBoxes =
+                []
+            , fragmentContentRect = Rect {x_origin = 2549, y_origin = -4993, x_size = 3697, y_size = -1121}
+            , fragmentRect = Rect {x_origin = 2549, y_origin = -4903, x_size = 3697, y_size = -1300}
+            , fragmentPen = (0, -1022)
+            , fragmentGlyphs =
+                [ (GlyphInfo {codepoint = 80, cluster = 80, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 861, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 72, cluster = 81, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 559, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 71, cluster = 82, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 589, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 76, cluster = 83, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 253, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 88, cluster = 84, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 574, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 80, cluster = 85, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 861, y_advance = 0, x_offset = 0, y_offset = 0})
+                ]
+            }
+        , Fragment
+            { fragmentUserData = "lineBreak"
+            , fragmentLine = 4
+            , fragmentAncestorBoxes =
+                []
+            , fragmentContentRect = Rect {x_origin = 6246, y_origin = -4993, x_size = 0, y_size = -1121}
+            , fragmentRect = Rect {x_origin = 6246, y_origin = -4903, x_size = 0, y_size = -1300}
+            , fragmentPen = (0, -1022)
+            , fragmentGlyphs =
+                []
+            }
+        , Fragment
+            { fragmentUserData = "smallText"
+            , fragmentLine = 5
+            , fragmentAncestorBoxes =
+                [ AncestorBox {boxUserData = "smallBox", boxLeftEdge = SpacedEdge 0, boxRightEdge = SpacedEdge 0, boxStartEdge = SpacedEdge 0, boxEndEdge = SpacedEdge 0}
+                ]
+            , fragmentContentRect = Rect {x_origin = 0, y_origin = -6487, x_size = 2375, y_size = -1121}
+            , fragmentRect = Rect {x_origin = 0, y_origin = -6647, x_size = 2375, y_size = -800}
+            , fragmentPen = (0, -772)
+            , fragmentGlyphs =
+                [ (GlyphInfo {codepoint = 86, cluster = 88, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 446, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 80, cluster = 89, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 861, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 68, cluster = 90, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 522, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 79, cluster = 91, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 273, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 79, cluster = 92, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 273, y_advance = 0, x_offset = 0, y_offset = 0})
+                ]
+            }
+        , Fragment
+            { fragmentUserData = "lineBreak"
+            , fragmentLine = 5
+            , fragmentAncestorBoxes =
+                []
+            , fragmentContentRect = Rect {x_origin = 2375, y_origin = -6490, x_size = 0, y_size = -1121}
+            , fragmentRect = Rect {x_origin = 2375, y_origin = -6400, x_size = 0, y_size = -1300}
+            , fragmentPen = (0, -1022)
+            , fragmentGlyphs =
+                []
+            }
+        , Fragment
+            { fragmentUserData = "largeText"
+            , fragmentLine = 6
+            , fragmentAncestorBoxes =
+                [ AncestorBox {boxUserData = "largeBox", boxLeftEdge = SpacedEdge 0, boxRightEdge = SpacedEdge 0, boxStartEdge = SpacedEdge 0, boxEndEdge = SpacedEdge 0}
+                ]
+            , fragmentContentRect = Rect {x_origin = 0, y_origin = -7990, x_size = 2318, y_size = -1121}
+            , fragmentRect = Rect {x_origin = 0, y_origin = -7700, x_size = 2318, y_size = -1700}
+            , fragmentPen = (0, -1222)
+            , fragmentGlyphs =
+                [ (GlyphInfo {codepoint = 79, cluster = 95, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 273, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 68, cluster = 96, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 522, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 85, cluster = 97, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 386, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 74, cluster = 98, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 578, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 72, cluster = 99, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 559, y_advance = 0, x_offset = 0, y_offset = 0})
+                ]
+            }
+        ]
+    }
diff --git a/.golden/richParagraphLayout/mixedLineHeightBottom.golden b/.golden/richParagraphLayout/mixedLineHeightBottom.golden
new file mode 100644
--- /dev/null
+++ b/.golden/richParagraphLayout/mixedLineHeightBottom.golden
@@ -0,0 +1,314 @@
+ParagraphLayout
+    { paragraphRect = Rect {x_origin = 0, y_origin = 0, x_size = 16708, y_size = -9400}
+    , paragraphLines =
+        [ Line {lineNumber = 1, lineRect = Rect {x_origin = 0, y_origin = 0, x_size = 16708, y_size = -1700}}
+        , Line {lineNumber = 2, lineRect = Rect {x_origin = 0, y_origin = -1700, x_size = 16708, y_size = -1700}}
+        , Line {lineNumber = 3, lineRect = Rect {x_origin = 0, y_origin = -3400, x_size = 16708, y_size = -1300}}
+        , Line {lineNumber = 4, lineRect = Rect {x_origin = 0, y_origin = -4700, x_size = 16708, y_size = -1700}}
+        , Line {lineNumber = 5, lineRect = Rect {x_origin = 0, y_origin = -6400, x_size = 16708, y_size = -1300}}
+        , Line {lineNumber = 6, lineRect = Rect {x_origin = 0, y_origin = -7700, x_size = 16708, y_size = -1700}}
+        ]
+    , paragraphFragments =
+        [ Fragment
+            { fragmentUserData = "mediumText"
+            , fragmentLine = 1
+            , fragmentAncestorBoxes =
+                []
+            , fragmentContentRect = Rect {x_origin = 0, y_origin = -490, x_size = 3928, y_size = -1121}
+            , fragmentRect = Rect {x_origin = 0, y_origin = -400, x_size = 3928, y_size = -1300}
+            , fragmentPen = (0, -1022)
+            , fragmentGlyphs =
+                [ (GlyphInfo {codepoint = 80, cluster = 6, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 861, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 72, cluster = 7, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 559, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 71, cluster = 8, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 589, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 76, cluster = 9, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 253, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 88, cluster = 10, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 574, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 80, cluster = 11, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 861, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 3, cluster = 12, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 231, y_advance = 0, x_offset = 0, y_offset = 0})
+                ]
+            }
+        , Fragment
+            { fragmentUserData = "smallText"
+            , fragmentLine = 1
+            , fragmentAncestorBoxes =
+                [ AncestorBox {boxUserData = "smallBox", boxLeftEdge = SpacedEdge 0, boxRightEdge = SpacedEdge 0, boxStartEdge = SpacedEdge 0, boxEndEdge = SpacedEdge 0}
+                ]
+            , fragmentContentRect = Rect {x_origin = 3928, y_origin = -740, x_size = 2606, y_size = -1121}
+            , fragmentRect = Rect {x_origin = 3928, y_origin = -900, x_size = 2606, y_size = -800}
+            , fragmentPen = (0, -772)
+            , fragmentGlyphs =
+                [ (GlyphInfo {codepoint = 86, cluster = 13, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 446, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 80, cluster = 14, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 861, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 68, cluster = 15, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 522, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 79, cluster = 16, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 273, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 79, cluster = 17, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 273, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 3, cluster = 18, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 231, y_advance = 0, x_offset = 0, y_offset = 0})
+                ]
+            }
+        , Fragment
+            { fragmentUserData = "mediumText"
+            , fragmentLine = 1
+            , fragmentAncestorBoxes =
+                []
+            , fragmentContentRect = Rect {x_origin = 6534, y_origin = -490, x_size = 3928, y_size = -1121}
+            , fragmentRect = Rect {x_origin = 6534, y_origin = -400, x_size = 3928, y_size = -1300}
+            , fragmentPen = (0, -1022)
+            , fragmentGlyphs =
+                [ (GlyphInfo {codepoint = 80, cluster = 19, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 861, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 72, cluster = 20, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 559, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 71, cluster = 21, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 589, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 76, cluster = 22, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 253, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 88, cluster = 23, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 574, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 80, cluster = 24, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 861, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 3, cluster = 25, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 231, y_advance = 0, x_offset = 0, y_offset = 0})
+                ]
+            }
+        , Fragment
+            { fragmentUserData = "largeText"
+            , fragmentLine = 1
+            , fragmentAncestorBoxes =
+                [ AncestorBox {boxUserData = "largeBox", boxLeftEdge = SpacedEdge 0, boxRightEdge = SpacedEdge 0, boxStartEdge = SpacedEdge 0, boxEndEdge = SpacedEdge 0}
+                ]
+            , fragmentContentRect = Rect {x_origin = 10462, y_origin = -290, x_size = 2549, y_size = -1121}
+            , fragmentRect = Rect {x_origin = 10462, y_origin = 0, x_size = 2549, y_size = -1700}
+            , fragmentPen = (0, -1222)
+            , fragmentGlyphs =
+                [ (GlyphInfo {codepoint = 79, cluster = 26, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 273, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 68, cluster = 27, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 522, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 85, cluster = 28, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 386, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 74, cluster = 29, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 578, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 72, cluster = 30, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 559, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 3, cluster = 31, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 231, y_advance = 0, x_offset = 0, y_offset = 0})
+                ]
+            }
+        , Fragment
+            { fragmentUserData = "mediumText"
+            , fragmentLine = 1
+            , fragmentAncestorBoxes =
+                []
+            , fragmentContentRect = Rect {x_origin = 13011, y_origin = -490, x_size = 3697, y_size = -1121}
+            , fragmentRect = Rect {x_origin = 13011, y_origin = -400, x_size = 3697, y_size = -1300}
+            , fragmentPen = (0, -1022)
+            , fragmentGlyphs =
+                [ (GlyphInfo {codepoint = 80, cluster = 32, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 861, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 72, cluster = 33, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 559, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 71, cluster = 34, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 589, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 76, cluster = 35, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 253, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 88, cluster = 36, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 574, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 80, cluster = 37, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 861, y_advance = 0, x_offset = 0, y_offset = 0})
+                ]
+            }
+        , Fragment
+            { fragmentUserData = "lineBreak"
+            , fragmentLine = 1
+            , fragmentAncestorBoxes =
+                []
+            , fragmentContentRect = Rect {x_origin = 16708, y_origin = -490, x_size = 0, y_size = -1121}
+            , fragmentRect = Rect {x_origin = 16708, y_origin = -400, x_size = 0, y_size = -1300}
+            , fragmentPen = (0, -1022)
+            , fragmentGlyphs =
+                []
+            }
+        , Fragment
+            { fragmentUserData = "smallText"
+            , fragmentLine = 2
+            , fragmentAncestorBoxes =
+                [ AncestorBox {boxUserData = "smallBox", boxLeftEdge = SpacedEdge 0, boxRightEdge = SpacedEdge 0, boxStartEdge = SpacedEdge 0, boxEndEdge = SpacedEdge 0}
+                ]
+            , fragmentContentRect = Rect {x_origin = 0, y_origin = -2440, x_size = 2606, y_size = -1121}
+            , fragmentRect = Rect {x_origin = 0, y_origin = -2600, x_size = 2606, y_size = -800}
+            , fragmentPen = (0, -772)
+            , fragmentGlyphs =
+                [ (GlyphInfo {codepoint = 86, cluster = 40, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 446, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 80, cluster = 41, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 861, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 68, cluster = 42, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 522, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 79, cluster = 43, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 273, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 79, cluster = 44, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 273, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 3, cluster = 45, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 231, y_advance = 0, x_offset = 0, y_offset = 0})
+                ]
+            }
+        , Fragment
+            { fragmentUserData = "mediumText"
+            , fragmentLine = 2
+            , fragmentAncestorBoxes =
+                []
+            , fragmentContentRect = Rect {x_origin = 2606, y_origin = -2190, x_size = 3928, y_size = -1121}
+            , fragmentRect = Rect {x_origin = 2606, y_origin = -2100, x_size = 3928, y_size = -1300}
+            , fragmentPen = (0, -1022)
+            , fragmentGlyphs =
+                [ (GlyphInfo {codepoint = 80, cluster = 46, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 861, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 72, cluster = 47, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 559, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 71, cluster = 48, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 589, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 76, cluster = 49, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 253, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 88, cluster = 50, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 574, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 80, cluster = 51, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 861, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 3, cluster = 52, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 231, y_advance = 0, x_offset = 0, y_offset = 0})
+                ]
+            }
+        , Fragment
+            { fragmentUserData = "largeText"
+            , fragmentLine = 2
+            , fragmentAncestorBoxes =
+                [ AncestorBox {boxUserData = "largeBox", boxLeftEdge = SpacedEdge 0, boxRightEdge = SpacedEdge 0, boxStartEdge = SpacedEdge 0, boxEndEdge = SpacedEdge 0}
+                ]
+            , fragmentContentRect = Rect {x_origin = 6534, y_origin = -1990, x_size = 2318, y_size = -1121}
+            , fragmentRect = Rect {x_origin = 6534, y_origin = -1700, x_size = 2318, y_size = -1700}
+            , fragmentPen = (0, -1222)
+            , fragmentGlyphs =
+                [ (GlyphInfo {codepoint = 79, cluster = 53, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 273, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 68, cluster = 54, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 522, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 85, cluster = 55, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 386, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 74, cluster = 56, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 578, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 72, cluster = 57, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 559, y_advance = 0, x_offset = 0, y_offset = 0})
+                ]
+            }
+        , Fragment
+            { fragmentUserData = "lineBreak"
+            , fragmentLine = 2
+            , fragmentAncestorBoxes =
+                []
+            , fragmentContentRect = Rect {x_origin = 8852, y_origin = -2190, x_size = 0, y_size = -1121}
+            , fragmentRect = Rect {x_origin = 8852, y_origin = -2100, x_size = 0, y_size = -1300}
+            , fragmentPen = (0, -1022)
+            , fragmentGlyphs =
+                []
+            }
+        , Fragment
+            { fragmentUserData = "mediumText"
+            , fragmentLine = 3
+            , fragmentAncestorBoxes =
+                []
+            , fragmentContentRect = Rect {x_origin = 0, y_origin = -3490, x_size = 3928, y_size = -1121}
+            , fragmentRect = Rect {x_origin = 0, y_origin = -3400, x_size = 3928, y_size = -1300}
+            , fragmentPen = (0, -1022)
+            , fragmentGlyphs =
+                [ (GlyphInfo {codepoint = 80, cluster = 60, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 861, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 72, cluster = 61, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 559, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 71, cluster = 62, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 589, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 76, cluster = 63, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 253, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 88, cluster = 64, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 574, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 80, cluster = 65, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 861, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 3, cluster = 66, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 231, y_advance = 0, x_offset = 0, y_offset = 0})
+                ]
+            }
+        , Fragment
+            { fragmentUserData = "smallText"
+            , fragmentLine = 3
+            , fragmentAncestorBoxes =
+                [ AncestorBox {boxUserData = "smallBox", boxLeftEdge = SpacedEdge 0, boxRightEdge = SpacedEdge 0, boxStartEdge = SpacedEdge 0, boxEndEdge = SpacedEdge 0}
+                ]
+            , fragmentContentRect = Rect {x_origin = 3928, y_origin = -3740, x_size = 2375, y_size = -1121}
+            , fragmentRect = Rect {x_origin = 3928, y_origin = -3900, x_size = 2375, y_size = -800}
+            , fragmentPen = (0, -772)
+            , fragmentGlyphs =
+                [ (GlyphInfo {codepoint = 86, cluster = 67, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 446, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 80, cluster = 68, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 861, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 68, cluster = 69, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 522, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 79, cluster = 70, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 273, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 79, cluster = 71, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 273, y_advance = 0, x_offset = 0, y_offset = 0})
+                ]
+            }
+        , Fragment
+            { fragmentUserData = "lineBreak"
+            , fragmentLine = 3
+            , fragmentAncestorBoxes =
+                []
+            , fragmentContentRect = Rect {x_origin = 6303, y_origin = -3490, x_size = 0, y_size = -1121}
+            , fragmentRect = Rect {x_origin = 6303, y_origin = -3400, x_size = 0, y_size = -1300}
+            , fragmentPen = (0, -1022)
+            , fragmentGlyphs =
+                []
+            }
+        , Fragment
+            { fragmentUserData = "largeText"
+            , fragmentLine = 4
+            , fragmentAncestorBoxes =
+                [ AncestorBox {boxUserData = "largeBox", boxLeftEdge = SpacedEdge 0, boxRightEdge = SpacedEdge 0, boxStartEdge = SpacedEdge 0, boxEndEdge = SpacedEdge 0}
+                ]
+            , fragmentContentRect = Rect {x_origin = 0, y_origin = -4990, x_size = 2549, y_size = -1121}
+            , fragmentRect = Rect {x_origin = 0, y_origin = -4700, x_size = 2549, y_size = -1700}
+            , fragmentPen = (0, -1222)
+            , fragmentGlyphs =
+                [ (GlyphInfo {codepoint = 79, cluster = 74, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 273, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 68, cluster = 75, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 522, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 85, cluster = 76, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 386, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 74, cluster = 77, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 578, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 72, cluster = 78, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 559, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 3, cluster = 79, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 231, y_advance = 0, x_offset = 0, y_offset = 0})
+                ]
+            }
+        , Fragment
+            { fragmentUserData = "mediumText"
+            , fragmentLine = 4
+            , fragmentAncestorBoxes =
+                []
+            , fragmentContentRect = Rect {x_origin = 2549, y_origin = -5190, x_size = 3697, y_size = -1121}
+            , fragmentRect = Rect {x_origin = 2549, y_origin = -5100, x_size = 3697, y_size = -1300}
+            , fragmentPen = (0, -1022)
+            , fragmentGlyphs =
+                [ (GlyphInfo {codepoint = 80, cluster = 80, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 861, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 72, cluster = 81, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 559, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 71, cluster = 82, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 589, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 76, cluster = 83, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 253, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 88, cluster = 84, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 574, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 80, cluster = 85, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 861, y_advance = 0, x_offset = 0, y_offset = 0})
+                ]
+            }
+        , Fragment
+            { fragmentUserData = "lineBreak"
+            , fragmentLine = 4
+            , fragmentAncestorBoxes =
+                []
+            , fragmentContentRect = Rect {x_origin = 6246, y_origin = -5190, x_size = 0, y_size = -1121}
+            , fragmentRect = Rect {x_origin = 6246, y_origin = -5100, x_size = 0, y_size = -1300}
+            , fragmentPen = (0, -1022)
+            , fragmentGlyphs =
+                []
+            }
+        , Fragment
+            { fragmentUserData = "smallText"
+            , fragmentLine = 5
+            , fragmentAncestorBoxes =
+                [ AncestorBox {boxUserData = "smallBox", boxLeftEdge = SpacedEdge 0, boxRightEdge = SpacedEdge 0, boxStartEdge = SpacedEdge 0, boxEndEdge = SpacedEdge 0}
+                ]
+            , fragmentContentRect = Rect {x_origin = 0, y_origin = -6740, x_size = 2375, y_size = -1121}
+            , fragmentRect = Rect {x_origin = 0, y_origin = -6900, x_size = 2375, y_size = -800}
+            , fragmentPen = (0, -772)
+            , fragmentGlyphs =
+                [ (GlyphInfo {codepoint = 86, cluster = 88, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 446, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 80, cluster = 89, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 861, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 68, cluster = 90, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 522, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 79, cluster = 91, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 273, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 79, cluster = 92, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 273, y_advance = 0, x_offset = 0, y_offset = 0})
+                ]
+            }
+        , Fragment
+            { fragmentUserData = "lineBreak"
+            , fragmentLine = 5
+            , fragmentAncestorBoxes =
+                []
+            , fragmentContentRect = Rect {x_origin = 2375, y_origin = -6490, x_size = 0, y_size = -1121}
+            , fragmentRect = Rect {x_origin = 2375, y_origin = -6400, x_size = 0, y_size = -1300}
+            , fragmentPen = (0, -1022)
+            , fragmentGlyphs =
+                []
+            }
+        , Fragment
+            { fragmentUserData = "largeText"
+            , fragmentLine = 6
+            , fragmentAncestorBoxes =
+                [ AncestorBox {boxUserData = "largeBox", boxLeftEdge = SpacedEdge 0, boxRightEdge = SpacedEdge 0, boxStartEdge = SpacedEdge 0, boxEndEdge = SpacedEdge 0}
+                ]
+            , fragmentContentRect = Rect {x_origin = 0, y_origin = -7990, x_size = 2318, y_size = -1121}
+            , fragmentRect = Rect {x_origin = 0, y_origin = -7700, x_size = 2318, y_size = -1700}
+            , fragmentPen = (0, -1222)
+            , fragmentGlyphs =
+                [ (GlyphInfo {codepoint = 79, cluster = 95, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 273, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 68, cluster = 96, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 522, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 85, cluster = 97, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 386, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 74, cluster = 98, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 578, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 72, cluster = 99, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 559, y_advance = 0, x_offset = 0, y_offset = 0})
+                ]
+            }
+        ]
+    }
diff --git a/.golden/richParagraphLayout/mixedLineHeightTop.golden b/.golden/richParagraphLayout/mixedLineHeightTop.golden
new file mode 100644
--- /dev/null
+++ b/.golden/richParagraphLayout/mixedLineHeightTop.golden
@@ -0,0 +1,314 @@
+ParagraphLayout
+    { paragraphRect = Rect {x_origin = 0, y_origin = 0, x_size = 16708, y_size = -9400}
+    , paragraphLines =
+        [ Line {lineNumber = 1, lineRect = Rect {x_origin = 0, y_origin = 0, x_size = 16708, y_size = -1700}}
+        , Line {lineNumber = 2, lineRect = Rect {x_origin = 0, y_origin = -1700, x_size = 16708, y_size = -1700}}
+        , Line {lineNumber = 3, lineRect = Rect {x_origin = 0, y_origin = -3400, x_size = 16708, y_size = -1300}}
+        , Line {lineNumber = 4, lineRect = Rect {x_origin = 0, y_origin = -4700, x_size = 16708, y_size = -1700}}
+        , Line {lineNumber = 5, lineRect = Rect {x_origin = 0, y_origin = -6400, x_size = 16708, y_size = -1300}}
+        , Line {lineNumber = 6, lineRect = Rect {x_origin = 0, y_origin = -7700, x_size = 16708, y_size = -1700}}
+        ]
+    , paragraphFragments =
+        [ Fragment
+            { fragmentUserData = "mediumText"
+            , fragmentLine = 1
+            , fragmentAncestorBoxes =
+                []
+            , fragmentContentRect = Rect {x_origin = 0, y_origin = -90, x_size = 3928, y_size = -1121}
+            , fragmentRect = Rect {x_origin = 0, y_origin = 0, x_size = 3928, y_size = -1300}
+            , fragmentPen = (0, -1022)
+            , fragmentGlyphs =
+                [ (GlyphInfo {codepoint = 80, cluster = 6, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 861, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 72, cluster = 7, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 559, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 71, cluster = 8, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 589, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 76, cluster = 9, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 253, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 88, cluster = 10, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 574, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 80, cluster = 11, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 861, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 3, cluster = 12, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 231, y_advance = 0, x_offset = 0, y_offset = 0})
+                ]
+            }
+        , Fragment
+            { fragmentUserData = "smallText"
+            , fragmentLine = 1
+            , fragmentAncestorBoxes =
+                [ AncestorBox {boxUserData = "smallBox", boxLeftEdge = SpacedEdge 0, boxRightEdge = SpacedEdge 0, boxStartEdge = SpacedEdge 0, boxEndEdge = SpacedEdge 0}
+                ]
+            , fragmentContentRect = Rect {x_origin = 3928, y_origin = 160, x_size = 2606, y_size = -1121}
+            , fragmentRect = Rect {x_origin = 3928, y_origin = 0, x_size = 2606, y_size = -800}
+            , fragmentPen = (0, -772)
+            , fragmentGlyphs =
+                [ (GlyphInfo {codepoint = 86, cluster = 13, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 446, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 80, cluster = 14, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 861, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 68, cluster = 15, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 522, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 79, cluster = 16, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 273, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 79, cluster = 17, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 273, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 3, cluster = 18, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 231, y_advance = 0, x_offset = 0, y_offset = 0})
+                ]
+            }
+        , Fragment
+            { fragmentUserData = "mediumText"
+            , fragmentLine = 1
+            , fragmentAncestorBoxes =
+                []
+            , fragmentContentRect = Rect {x_origin = 6534, y_origin = -90, x_size = 3928, y_size = -1121}
+            , fragmentRect = Rect {x_origin = 6534, y_origin = 0, x_size = 3928, y_size = -1300}
+            , fragmentPen = (0, -1022)
+            , fragmentGlyphs =
+                [ (GlyphInfo {codepoint = 80, cluster = 19, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 861, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 72, cluster = 20, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 559, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 71, cluster = 21, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 589, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 76, cluster = 22, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 253, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 88, cluster = 23, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 574, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 80, cluster = 24, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 861, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 3, cluster = 25, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 231, y_advance = 0, x_offset = 0, y_offset = 0})
+                ]
+            }
+        , Fragment
+            { fragmentUserData = "largeText"
+            , fragmentLine = 1
+            , fragmentAncestorBoxes =
+                [ AncestorBox {boxUserData = "largeBox", boxLeftEdge = SpacedEdge 0, boxRightEdge = SpacedEdge 0, boxStartEdge = SpacedEdge 0, boxEndEdge = SpacedEdge 0}
+                ]
+            , fragmentContentRect = Rect {x_origin = 10462, y_origin = -290, x_size = 2549, y_size = -1121}
+            , fragmentRect = Rect {x_origin = 10462, y_origin = 0, x_size = 2549, y_size = -1700}
+            , fragmentPen = (0, -1222)
+            , fragmentGlyphs =
+                [ (GlyphInfo {codepoint = 79, cluster = 26, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 273, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 68, cluster = 27, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 522, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 85, cluster = 28, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 386, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 74, cluster = 29, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 578, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 72, cluster = 30, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 559, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 3, cluster = 31, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 231, y_advance = 0, x_offset = 0, y_offset = 0})
+                ]
+            }
+        , Fragment
+            { fragmentUserData = "mediumText"
+            , fragmentLine = 1
+            , fragmentAncestorBoxes =
+                []
+            , fragmentContentRect = Rect {x_origin = 13011, y_origin = -90, x_size = 3697, y_size = -1121}
+            , fragmentRect = Rect {x_origin = 13011, y_origin = 0, x_size = 3697, y_size = -1300}
+            , fragmentPen = (0, -1022)
+            , fragmentGlyphs =
+                [ (GlyphInfo {codepoint = 80, cluster = 32, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 861, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 72, cluster = 33, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 559, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 71, cluster = 34, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 589, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 76, cluster = 35, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 253, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 88, cluster = 36, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 574, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 80, cluster = 37, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 861, y_advance = 0, x_offset = 0, y_offset = 0})
+                ]
+            }
+        , Fragment
+            { fragmentUserData = "lineBreak"
+            , fragmentLine = 1
+            , fragmentAncestorBoxes =
+                []
+            , fragmentContentRect = Rect {x_origin = 16708, y_origin = -90, x_size = 0, y_size = -1121}
+            , fragmentRect = Rect {x_origin = 16708, y_origin = 0, x_size = 0, y_size = -1300}
+            , fragmentPen = (0, -1022)
+            , fragmentGlyphs =
+                []
+            }
+        , Fragment
+            { fragmentUserData = "smallText"
+            , fragmentLine = 2
+            , fragmentAncestorBoxes =
+                [ AncestorBox {boxUserData = "smallBox", boxLeftEdge = SpacedEdge 0, boxRightEdge = SpacedEdge 0, boxStartEdge = SpacedEdge 0, boxEndEdge = SpacedEdge 0}
+                ]
+            , fragmentContentRect = Rect {x_origin = 0, y_origin = -1540, x_size = 2606, y_size = -1121}
+            , fragmentRect = Rect {x_origin = 0, y_origin = -1700, x_size = 2606, y_size = -800}
+            , fragmentPen = (0, -772)
+            , fragmentGlyphs =
+                [ (GlyphInfo {codepoint = 86, cluster = 40, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 446, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 80, cluster = 41, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 861, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 68, cluster = 42, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 522, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 79, cluster = 43, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 273, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 79, cluster = 44, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 273, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 3, cluster = 45, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 231, y_advance = 0, x_offset = 0, y_offset = 0})
+                ]
+            }
+        , Fragment
+            { fragmentUserData = "mediumText"
+            , fragmentLine = 2
+            , fragmentAncestorBoxes =
+                []
+            , fragmentContentRect = Rect {x_origin = 2606, y_origin = -1790, x_size = 3928, y_size = -1121}
+            , fragmentRect = Rect {x_origin = 2606, y_origin = -1700, x_size = 3928, y_size = -1300}
+            , fragmentPen = (0, -1022)
+            , fragmentGlyphs =
+                [ (GlyphInfo {codepoint = 80, cluster = 46, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 861, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 72, cluster = 47, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 559, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 71, cluster = 48, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 589, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 76, cluster = 49, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 253, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 88, cluster = 50, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 574, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 80, cluster = 51, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 861, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 3, cluster = 52, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 231, y_advance = 0, x_offset = 0, y_offset = 0})
+                ]
+            }
+        , Fragment
+            { fragmentUserData = "largeText"
+            , fragmentLine = 2
+            , fragmentAncestorBoxes =
+                [ AncestorBox {boxUserData = "largeBox", boxLeftEdge = SpacedEdge 0, boxRightEdge = SpacedEdge 0, boxStartEdge = SpacedEdge 0, boxEndEdge = SpacedEdge 0}
+                ]
+            , fragmentContentRect = Rect {x_origin = 6534, y_origin = -1990, x_size = 2318, y_size = -1121}
+            , fragmentRect = Rect {x_origin = 6534, y_origin = -1700, x_size = 2318, y_size = -1700}
+            , fragmentPen = (0, -1222)
+            , fragmentGlyphs =
+                [ (GlyphInfo {codepoint = 79, cluster = 53, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 273, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 68, cluster = 54, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 522, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 85, cluster = 55, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 386, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 74, cluster = 56, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 578, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 72, cluster = 57, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 559, y_advance = 0, x_offset = 0, y_offset = 0})
+                ]
+            }
+        , Fragment
+            { fragmentUserData = "lineBreak"
+            , fragmentLine = 2
+            , fragmentAncestorBoxes =
+                []
+            , fragmentContentRect = Rect {x_origin = 8852, y_origin = -1790, x_size = 0, y_size = -1121}
+            , fragmentRect = Rect {x_origin = 8852, y_origin = -1700, x_size = 0, y_size = -1300}
+            , fragmentPen = (0, -1022)
+            , fragmentGlyphs =
+                []
+            }
+        , Fragment
+            { fragmentUserData = "mediumText"
+            , fragmentLine = 3
+            , fragmentAncestorBoxes =
+                []
+            , fragmentContentRect = Rect {x_origin = 0, y_origin = -3490, x_size = 3928, y_size = -1121}
+            , fragmentRect = Rect {x_origin = 0, y_origin = -3400, x_size = 3928, y_size = -1300}
+            , fragmentPen = (0, -1022)
+            , fragmentGlyphs =
+                [ (GlyphInfo {codepoint = 80, cluster = 60, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 861, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 72, cluster = 61, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 559, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 71, cluster = 62, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 589, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 76, cluster = 63, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 253, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 88, cluster = 64, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 574, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 80, cluster = 65, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 861, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 3, cluster = 66, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 231, y_advance = 0, x_offset = 0, y_offset = 0})
+                ]
+            }
+        , Fragment
+            { fragmentUserData = "smallText"
+            , fragmentLine = 3
+            , fragmentAncestorBoxes =
+                [ AncestorBox {boxUserData = "smallBox", boxLeftEdge = SpacedEdge 0, boxRightEdge = SpacedEdge 0, boxStartEdge = SpacedEdge 0, boxEndEdge = SpacedEdge 0}
+                ]
+            , fragmentContentRect = Rect {x_origin = 3928, y_origin = -3240, x_size = 2375, y_size = -1121}
+            , fragmentRect = Rect {x_origin = 3928, y_origin = -3400, x_size = 2375, y_size = -800}
+            , fragmentPen = (0, -772)
+            , fragmentGlyphs =
+                [ (GlyphInfo {codepoint = 86, cluster = 67, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 446, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 80, cluster = 68, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 861, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 68, cluster = 69, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 522, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 79, cluster = 70, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 273, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 79, cluster = 71, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 273, y_advance = 0, x_offset = 0, y_offset = 0})
+                ]
+            }
+        , Fragment
+            { fragmentUserData = "lineBreak"
+            , fragmentLine = 3
+            , fragmentAncestorBoxes =
+                []
+            , fragmentContentRect = Rect {x_origin = 6303, y_origin = -3490, x_size = 0, y_size = -1121}
+            , fragmentRect = Rect {x_origin = 6303, y_origin = -3400, x_size = 0, y_size = -1300}
+            , fragmentPen = (0, -1022)
+            , fragmentGlyphs =
+                []
+            }
+        , Fragment
+            { fragmentUserData = "largeText"
+            , fragmentLine = 4
+            , fragmentAncestorBoxes =
+                [ AncestorBox {boxUserData = "largeBox", boxLeftEdge = SpacedEdge 0, boxRightEdge = SpacedEdge 0, boxStartEdge = SpacedEdge 0, boxEndEdge = SpacedEdge 0}
+                ]
+            , fragmentContentRect = Rect {x_origin = 0, y_origin = -4990, x_size = 2549, y_size = -1121}
+            , fragmentRect = Rect {x_origin = 0, y_origin = -4700, x_size = 2549, y_size = -1700}
+            , fragmentPen = (0, -1222)
+            , fragmentGlyphs =
+                [ (GlyphInfo {codepoint = 79, cluster = 74, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 273, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 68, cluster = 75, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 522, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 85, cluster = 76, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 386, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 74, cluster = 77, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 578, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 72, cluster = 78, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 559, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 3, cluster = 79, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 231, y_advance = 0, x_offset = 0, y_offset = 0})
+                ]
+            }
+        , Fragment
+            { fragmentUserData = "mediumText"
+            , fragmentLine = 4
+            , fragmentAncestorBoxes =
+                []
+            , fragmentContentRect = Rect {x_origin = 2549, y_origin = -4790, x_size = 3697, y_size = -1121}
+            , fragmentRect = Rect {x_origin = 2549, y_origin = -4700, x_size = 3697, y_size = -1300}
+            , fragmentPen = (0, -1022)
+            , fragmentGlyphs =
+                [ (GlyphInfo {codepoint = 80, cluster = 80, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 861, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 72, cluster = 81, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 559, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 71, cluster = 82, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 589, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 76, cluster = 83, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 253, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 88, cluster = 84, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 574, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 80, cluster = 85, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 861, y_advance = 0, x_offset = 0, y_offset = 0})
+                ]
+            }
+        , Fragment
+            { fragmentUserData = "lineBreak"
+            , fragmentLine = 4
+            , fragmentAncestorBoxes =
+                []
+            , fragmentContentRect = Rect {x_origin = 6246, y_origin = -4790, x_size = 0, y_size = -1121}
+            , fragmentRect = Rect {x_origin = 6246, y_origin = -4700, x_size = 0, y_size = -1300}
+            , fragmentPen = (0, -1022)
+            , fragmentGlyphs =
+                []
+            }
+        , Fragment
+            { fragmentUserData = "smallText"
+            , fragmentLine = 5
+            , fragmentAncestorBoxes =
+                [ AncestorBox {boxUserData = "smallBox", boxLeftEdge = SpacedEdge 0, boxRightEdge = SpacedEdge 0, boxStartEdge = SpacedEdge 0, boxEndEdge = SpacedEdge 0}
+                ]
+            , fragmentContentRect = Rect {x_origin = 0, y_origin = -6240, x_size = 2375, y_size = -1121}
+            , fragmentRect = Rect {x_origin = 0, y_origin = -6400, x_size = 2375, y_size = -800}
+            , fragmentPen = (0, -772)
+            , fragmentGlyphs =
+                [ (GlyphInfo {codepoint = 86, cluster = 88, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 446, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 80, cluster = 89, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 861, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 68, cluster = 90, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 522, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 79, cluster = 91, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 273, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 79, cluster = 92, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 273, y_advance = 0, x_offset = 0, y_offset = 0})
+                ]
+            }
+        , Fragment
+            { fragmentUserData = "lineBreak"
+            , fragmentLine = 5
+            , fragmentAncestorBoxes =
+                []
+            , fragmentContentRect = Rect {x_origin = 2375, y_origin = -6490, x_size = 0, y_size = -1121}
+            , fragmentRect = Rect {x_origin = 2375, y_origin = -6400, x_size = 0, y_size = -1300}
+            , fragmentPen = (0, -1022)
+            , fragmentGlyphs =
+                []
+            }
+        , Fragment
+            { fragmentUserData = "largeText"
+            , fragmentLine = 6
+            , fragmentAncestorBoxes =
+                [ AncestorBox {boxUserData = "largeBox", boxLeftEdge = SpacedEdge 0, boxRightEdge = SpacedEdge 0, boxStartEdge = SpacedEdge 0, boxEndEdge = SpacedEdge 0}
+                ]
+            , fragmentContentRect = Rect {x_origin = 0, y_origin = -7990, x_size = 2318, y_size = -1121}
+            , fragmentRect = Rect {x_origin = 0, y_origin = -7700, x_size = 2318, y_size = -1700}
+            , fragmentPen = (0, -1222)
+            , fragmentGlyphs =
+                [ (GlyphInfo {codepoint = 79, cluster = 95, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 273, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 68, cluster = 96, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 522, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 85, cluster = 97, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 386, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 74, cluster = 98, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 578, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 72, cluster = 99, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 559, y_advance = 0, x_offset = 0, y_offset = 0})
+                ]
+            }
+        ]
+    }
diff --git a/.golden/richParagraphLayout/mixedScript.golden b/.golden/richParagraphLayout/mixedScript.golden
--- a/.golden/richParagraphLayout/mixedScript.golden
+++ b/.golden/richParagraphLayout/mixedScript.golden
@@ -1,5 +1,8 @@
 ParagraphLayout
     { paragraphRect = Rect {x_origin = 0, y_origin = 0, x_size = 15283, y_size = -1121}
+    , paragraphLines =
+        [ Line {lineNumber = 1, lineRect = Rect {x_origin = 0, y_origin = 0, x_size = 15283, y_size = -1121}}
+        ]
     , paragraphFragments =
         [ Fragment
             { fragmentUserData = "text1"
diff --git a/.golden/richParagraphLayout/mixedScriptWrap.golden b/.golden/richParagraphLayout/mixedScriptWrap.golden
--- a/.golden/richParagraphLayout/mixedScriptWrap.golden
+++ b/.golden/richParagraphLayout/mixedScriptWrap.golden
@@ -1,5 +1,11 @@
 ParagraphLayout
     { paragraphRect = Rect {x_origin = 0, y_origin = 0, x_size = 4897, y_size = -4484}
+    , paragraphLines =
+        [ Line {lineNumber = 1, lineRect = Rect {x_origin = 0, y_origin = 0, x_size = 4897, y_size = -1121}}
+        , Line {lineNumber = 2, lineRect = Rect {x_origin = 0, y_origin = -1121, x_size = 4897, y_size = -1121}}
+        , Line {lineNumber = 3, lineRect = Rect {x_origin = 0, y_origin = -2242, x_size = 4897, y_size = -1121}}
+        , Line {lineNumber = 4, lineRect = Rect {x_origin = 0, y_origin = -3363, x_size = 4897, y_size = -1121}}
+        ]
     , paragraphFragments =
         [ Fragment
             { fragmentUserData = "text1"
diff --git a/.golden/richParagraphLayout/mixedSizes.golden b/.golden/richParagraphLayout/mixedSizes.golden
--- a/.golden/richParagraphLayout/mixedSizes.golden
+++ b/.golden/richParagraphLayout/mixedSizes.golden
@@ -1,5 +1,8 @@
 ParagraphLayout
     { paragraphRect = Rect {x_origin = 0, y_origin = 0, x_size = 8634, y_size = -1121}
+    , paragraphLines =
+        [ Line {lineNumber = 1, lineRect = Rect {x_origin = 0, y_origin = 0, x_size = 8634, y_size = -1121}}
+        ]
     , paragraphFragments =
         [ Fragment
             { fragmentUserData = "bigText1"
diff --git a/.golden/richParagraphLayout/nestedBoxes.golden b/.golden/richParagraphLayout/nestedBoxes.golden
--- a/.golden/richParagraphLayout/nestedBoxes.golden
+++ b/.golden/richParagraphLayout/nestedBoxes.golden
@@ -1,5 +1,8 @@
 ParagraphLayout
     { paragraphRect = Rect {x_origin = 0, y_origin = 0, x_size = 14576, y_size = -1121}
+    , paragraphLines =
+        [ Line {lineNumber = 1, lineRect = Rect {x_origin = 0, y_origin = 0, x_size = 14576, y_size = -1121}}
+        ]
     , paragraphFragments =
         [ Fragment
             { fragmentUserData = "text1"
diff --git a/.golden/richParagraphLayout/neutralDirectionLTR.golden b/.golden/richParagraphLayout/neutralDirectionLTR.golden
--- a/.golden/richParagraphLayout/neutralDirectionLTR.golden
+++ b/.golden/richParagraphLayout/neutralDirectionLTR.golden
@@ -1,5 +1,8 @@
 ParagraphLayout
     { paragraphRect = Rect {x_origin = 0, y_origin = 0, x_size = 2003, y_size = -1500}
+    , paragraphLines =
+        [ Line {lineNumber = 1, lineRect = Rect {x_origin = 0, y_origin = 0, x_size = 2003, y_size = -1500}}
+        ]
     , paragraphFragments =
         [ Fragment
             { fragmentUserData = "text"
diff --git a/.golden/richParagraphLayout/neutralDirectionRTL.golden b/.golden/richParagraphLayout/neutralDirectionRTL.golden
--- a/.golden/richParagraphLayout/neutralDirectionRTL.golden
+++ b/.golden/richParagraphLayout/neutralDirectionRTL.golden
@@ -1,5 +1,8 @@
 ParagraphLayout
     { paragraphRect = Rect {x_origin = 999997997, y_origin = 0, x_size = 2003, y_size = -1500}
+    , paragraphLines =
+        [ Line {lineNumber = 1, lineRect = Rect {x_origin = 999997997, y_origin = 0, x_size = 2003, y_size = -1500}}
+        ]
     , paragraphFragments =
         [ Fragment
             { fragmentUserData = "text"
diff --git a/.golden/richParagraphLayout/newline1Paragraph.golden b/.golden/richParagraphLayout/newline1Paragraph.golden
--- a/.golden/richParagraphLayout/newline1Paragraph.golden
+++ b/.golden/richParagraphLayout/newline1Paragraph.golden
@@ -1,5 +1,8 @@
 ParagraphLayout
     { paragraphRect = Rect {x_origin = 1000000000, y_origin = 0, x_size = 0, y_size = -1500}
+    , paragraphLines =
+        [ Line {lineNumber = 1, lineRect = Rect {x_origin = 1000000000, y_origin = 0, x_size = 0, y_size = -1500}}
+        ]
     , paragraphFragments =
         [ Fragment
             { fragmentUserData = "text"
diff --git a/.golden/richParagraphLayout/newline1TextParagraph.golden b/.golden/richParagraphLayout/newline1TextParagraph.golden
--- a/.golden/richParagraphLayout/newline1TextParagraph.golden
+++ b/.golden/richParagraphLayout/newline1TextParagraph.golden
@@ -1,5 +1,9 @@
 ParagraphLayout
     { paragraphRect = Rect {x_origin = 999999649, y_origin = 0, x_size = 351, y_size = -3000}
+    , paragraphLines =
+        [ Line {lineNumber = 1, lineRect = Rect {x_origin = 999999649, y_origin = 0, x_size = 351, y_size = -1500}}
+        , Line {lineNumber = 2, lineRect = Rect {x_origin = 999999649, y_origin = -1500, x_size = 351, y_size = -1500}}
+        ]
     , paragraphFragments =
         [ Fragment
             { fragmentUserData = "text"
diff --git a/.golden/richParagraphLayout/newline2Paragraph.golden b/.golden/richParagraphLayout/newline2Paragraph.golden
--- a/.golden/richParagraphLayout/newline2Paragraph.golden
+++ b/.golden/richParagraphLayout/newline2Paragraph.golden
@@ -1,5 +1,9 @@
 ParagraphLayout
     { paragraphRect = Rect {x_origin = 1000000000, y_origin = 0, x_size = 0, y_size = -3000}
+    , paragraphLines =
+        [ Line {lineNumber = 1, lineRect = Rect {x_origin = 1000000000, y_origin = 0, x_size = 0, y_size = -1500}}
+        , Line {lineNumber = 2, lineRect = Rect {x_origin = 1000000000, y_origin = -1500, x_size = 0, y_size = -1500}}
+        ]
     , paragraphFragments =
         [ Fragment
             { fragmentUserData = "text"
diff --git a/.golden/richParagraphLayout/newline2TextParagraph.golden b/.golden/richParagraphLayout/newline2TextParagraph.golden
--- a/.golden/richParagraphLayout/newline2TextParagraph.golden
+++ b/.golden/richParagraphLayout/newline2TextParagraph.golden
@@ -1,5 +1,10 @@
 ParagraphLayout
     { paragraphRect = Rect {x_origin = 999999649, y_origin = 0, x_size = 351, y_size = -4500}
+    , paragraphLines =
+        [ Line {lineNumber = 1, lineRect = Rect {x_origin = 999999649, y_origin = 0, x_size = 351, y_size = -1500}}
+        , Line {lineNumber = 2, lineRect = Rect {x_origin = 999999649, y_origin = -1500, x_size = 351, y_size = -1500}}
+        , Line {lineNumber = 3, lineRect = Rect {x_origin = 999999649, y_origin = -3000, x_size = 351, y_size = -1500}}
+        ]
     , paragraphFragments =
         [ Fragment
             { fragmentUserData = "text"
diff --git a/.golden/richParagraphLayout/offsetMiddleDownInnerText.golden b/.golden/richParagraphLayout/offsetMiddleDownInnerText.golden
new file mode 100644
--- /dev/null
+++ b/.golden/richParagraphLayout/offsetMiddleDownInnerText.golden
@@ -0,0 +1,25 @@
+ParagraphLayout
+    { paragraphRect = Rect {x_origin = 0, y_origin = 0, x_size = 2477, y_size = -1621}
+    , paragraphLines =
+        [ Line {lineNumber = 1, lineRect = Rect {x_origin = 0, y_origin = 0, x_size = 2477, y_size = -1621}}
+        ]
+    , paragraphFragments =
+        [ Fragment
+            { fragmentUserData = "inner"
+            , fragmentLine = 1
+            , fragmentAncestorBoxes =
+                [ AncestorBox {boxUserData = "box", boxLeftEdge = SpacedEdge 0, boxRightEdge = SpacedEdge 0, boxStartEdge = SpacedEdge 0, boxEndEdge = SpacedEdge 0}
+                ]
+            , fragmentContentRect = Rect {x_origin = 0, y_origin = -500, x_size = 2477, y_size = -1121}
+            , fragmentRect = Rect {x_origin = 0, y_origin = -500, x_size = 2477, y_size = -1121}
+            , fragmentPen = (0, -932)
+            , fragmentGlyphs =
+                [ (GlyphInfo {codepoint = 87, cluster = 5, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 402, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 75, cluster = 6, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 571, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 85, cluster = 7, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 386, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 72, cluster = 8, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 559, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 72, cluster = 9, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 559, y_advance = 0, x_offset = 0, y_offset = 0})
+                ]
+            }
+        ]
+    }
diff --git a/.golden/richParagraphLayout/offsetMiddleDownOuterText.golden b/.golden/richParagraphLayout/offsetMiddleDownOuterText.golden
new file mode 100644
--- /dev/null
+++ b/.golden/richParagraphLayout/offsetMiddleDownOuterText.golden
@@ -0,0 +1,59 @@
+ParagraphLayout
+    { paragraphRect = Rect {x_origin = 0, y_origin = 0, x_size = 8030, y_size = -1621}
+    , paragraphLines =
+        [ Line {lineNumber = 1, lineRect = Rect {x_origin = 0, y_origin = 0, x_size = 8030, y_size = -1621}}
+        ]
+    , paragraphFragments =
+        [ Fragment
+            { fragmentUserData = "outer start"
+            , fragmentLine = 1
+            , fragmentAncestorBoxes =
+                []
+            , fragmentContentRect = Rect {x_origin = 0, y_origin = 0, x_size = 3942, y_size = -1121}
+            , fragmentRect = Rect {x_origin = 0, y_origin = 0, x_size = 3942, y_size = -1121}
+            , fragmentPen = (0, -932)
+            , fragmentGlyphs =
+                [ (GlyphInfo {codepoint = 82, cluster = 5, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 590, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 81, cluster = 6, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 574, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 72, cluster = 7, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 559, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 3, cluster = 8, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 231, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 87, cluster = 9, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 402, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 90, cluster = 10, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 765, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 82, cluster = 11, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 590, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 3, cluster = 12, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 231, y_advance = 0, x_offset = 0, y_offset = 0})
+                ]
+            }
+        , Fragment
+            { fragmentUserData = "inner"
+            , fragmentLine = 1
+            , fragmentAncestorBoxes =
+                [ AncestorBox {boxUserData = "box", boxLeftEdge = SpacedEdge 0, boxRightEdge = SpacedEdge 0, boxStartEdge = SpacedEdge 0, boxEndEdge = SpacedEdge 0}
+                ]
+            , fragmentContentRect = Rect {x_origin = 3942, y_origin = -500, x_size = 0, y_size = -1121}
+            , fragmentRect = Rect {x_origin = 3942, y_origin = -500, x_size = 0, y_size = -1121}
+            , fragmentPen = (0, -932)
+            , fragmentGlyphs =
+                []
+            }
+        , Fragment
+            { fragmentUserData = "outer end"
+            , fragmentLine = 1
+            , fragmentAncestorBoxes =
+                []
+            , fragmentContentRect = Rect {x_origin = 3942, y_origin = 0, x_size = 4088, y_size = -1121}
+            , fragmentRect = Rect {x_origin = 3942, y_origin = 0, x_size = 4088, y_size = -1121}
+            , fragmentPen = (0, -932)
+            , fragmentGlyphs =
+                [ (GlyphInfo {codepoint = 3, cluster = 13, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 231, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 73, cluster = 14, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 386, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 82, cluster = 15, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 590, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 88, cluster = 16, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 574, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 85, cluster = 17, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 386, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 3, cluster = 18, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 231, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 428, cluster = 19, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 643, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 89, cluster = 21, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 488, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 72, cluster = 22, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 559, y_advance = 0, x_offset = 0, y_offset = 0})
+                ]
+            }
+        ]
+    }
diff --git a/.golden/richParagraphLayout/offsetMiddleDownOuterTextWrap.golden b/.golden/richParagraphLayout/offsetMiddleDownOuterTextWrap.golden
new file mode 100644
--- /dev/null
+++ b/.golden/richParagraphLayout/offsetMiddleDownOuterTextWrap.golden
@@ -0,0 +1,91 @@
+ParagraphLayout
+    { paragraphRect = Rect {x_origin = 0, y_origin = 0, x_size = 1936, y_size = -4984}
+    , paragraphLines =
+        [ Line {lineNumber = 1, lineRect = Rect {x_origin = 0, y_origin = 0, x_size = 1936, y_size = -1121}}
+        , Line {lineNumber = 2, lineRect = Rect {x_origin = 0, y_origin = -1121, x_size = 1936, y_size = -1621}}
+        , Line {lineNumber = 3, lineRect = Rect {x_origin = 0, y_origin = -2742, x_size = 1936, y_size = -1121}}
+        , Line {lineNumber = 4, lineRect = Rect {x_origin = 0, y_origin = -3863, x_size = 1936, y_size = -1121}}
+        ]
+    , paragraphFragments =
+        [ Fragment
+            { fragmentUserData = "outer start"
+            , fragmentLine = 1
+            , fragmentAncestorBoxes =
+                []
+            , fragmentContentRect = Rect {x_origin = 0, y_origin = 0, x_size = 1723, y_size = -1121}
+            , fragmentRect = Rect {x_origin = 0, y_origin = 0, x_size = 1723, y_size = -1121}
+            , fragmentPen = (0, -932)
+            , fragmentGlyphs =
+                [ (GlyphInfo {codepoint = 82, cluster = 5, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 590, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 81, cluster = 6, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 574, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 72, cluster = 7, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 559, y_advance = 0, x_offset = 0, y_offset = 0})
+                ]
+            }
+        , Fragment
+            { fragmentUserData = "outer start"
+            , fragmentLine = 2
+            , fragmentAncestorBoxes =
+                []
+            , fragmentContentRect = Rect {x_origin = 0, y_origin = -1121, x_size = 1757, y_size = -1121}
+            , fragmentRect = Rect {x_origin = 0, y_origin = -1121, x_size = 1757, y_size = -1121}
+            , fragmentPen = (0, -932)
+            , fragmentGlyphs =
+                [ (GlyphInfo {codepoint = 87, cluster = 9, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 402, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 90, cluster = 10, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 765, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 82, cluster = 11, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 590, y_advance = 0, x_offset = 0, y_offset = 0})
+                ]
+            }
+        , Fragment
+            { fragmentUserData = "inner"
+            , fragmentLine = 2
+            , fragmentAncestorBoxes =
+                [ AncestorBox {boxUserData = "box", boxLeftEdge = SpacedEdge 0, boxRightEdge = SpacedEdge 0, boxStartEdge = SpacedEdge 0, boxEndEdge = SpacedEdge 0}
+                ]
+            , fragmentContentRect = Rect {x_origin = 1757, y_origin = -1621, x_size = 0, y_size = -1121}
+            , fragmentRect = Rect {x_origin = 1757, y_origin = -1621, x_size = 0, y_size = -1121}
+            , fragmentPen = (0, -932)
+            , fragmentGlyphs =
+                []
+            }
+        , Fragment
+            { fragmentUserData = "outer end"
+            , fragmentLine = 2
+            , fragmentAncestorBoxes =
+                []
+            , fragmentContentRect = Rect {x_origin = 1757, y_origin = -1121, x_size = 0, y_size = -1121}
+            , fragmentRect = Rect {x_origin = 1757, y_origin = -1121, x_size = 0, y_size = -1121}
+            , fragmentPen = (0, -932)
+            , fragmentGlyphs =
+                []
+            }
+        , Fragment
+            { fragmentUserData = "outer end"
+            , fragmentLine = 3
+            , fragmentAncestorBoxes =
+                []
+            , fragmentContentRect = Rect {x_origin = 0, y_origin = -2742, x_size = 1936, y_size = -1121}
+            , fragmentRect = Rect {x_origin = 0, y_origin = -2742, x_size = 1936, y_size = -1121}
+            , fragmentPen = (0, -932)
+            , fragmentGlyphs =
+                [ (GlyphInfo {codepoint = 73, cluster = 14, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 386, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 82, cluster = 15, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 590, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 88, cluster = 16, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 574, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 85, cluster = 17, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 386, y_advance = 0, x_offset = 0, y_offset = 0})
+                ]
+            }
+        , Fragment
+            { fragmentUserData = "outer end"
+            , fragmentLine = 4
+            , fragmentAncestorBoxes =
+                []
+            , fragmentContentRect = Rect {x_origin = 0, y_origin = -3863, x_size = 1690, y_size = -1121}
+            , fragmentRect = Rect {x_origin = 0, y_origin = -3863, x_size = 1690, y_size = -1121}
+            , fragmentPen = (0, -932)
+            , fragmentGlyphs =
+                [ (GlyphInfo {codepoint = 428, cluster = 19, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 643, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 89, cluster = 21, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 488, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 72, cluster = 22, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 559, y_advance = 0, x_offset = 0, y_offset = 0})
+                ]
+            }
+        ]
+    }
diff --git a/.golden/richParagraphLayout/offsetMiddleUpInnerText.golden b/.golden/richParagraphLayout/offsetMiddleUpInnerText.golden
new file mode 100644
--- /dev/null
+++ b/.golden/richParagraphLayout/offsetMiddleUpInnerText.golden
@@ -0,0 +1,25 @@
+ParagraphLayout
+    { paragraphRect = Rect {x_origin = 0, y_origin = 0, x_size = 2477, y_size = -1621}
+    , paragraphLines =
+        [ Line {lineNumber = 1, lineRect = Rect {x_origin = 0, y_origin = 0, x_size = 2477, y_size = -1621}}
+        ]
+    , paragraphFragments =
+        [ Fragment
+            { fragmentUserData = "inner"
+            , fragmentLine = 1
+            , fragmentAncestorBoxes =
+                [ AncestorBox {boxUserData = "box", boxLeftEdge = SpacedEdge 0, boxRightEdge = SpacedEdge 0, boxStartEdge = SpacedEdge 0, boxEndEdge = SpacedEdge 0}
+                ]
+            , fragmentContentRect = Rect {x_origin = 0, y_origin = 0, x_size = 2477, y_size = -1121}
+            , fragmentRect = Rect {x_origin = 0, y_origin = 0, x_size = 2477, y_size = -1121}
+            , fragmentPen = (0, -932)
+            , fragmentGlyphs =
+                [ (GlyphInfo {codepoint = 87, cluster = 5, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 402, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 75, cluster = 6, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 571, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 85, cluster = 7, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 386, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 72, cluster = 8, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 559, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 72, cluster = 9, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 559, y_advance = 0, x_offset = 0, y_offset = 0})
+                ]
+            }
+        ]
+    }
diff --git a/.golden/richParagraphLayout/offsetMiddleUpOuterText.golden b/.golden/richParagraphLayout/offsetMiddleUpOuterText.golden
new file mode 100644
--- /dev/null
+++ b/.golden/richParagraphLayout/offsetMiddleUpOuterText.golden
@@ -0,0 +1,59 @@
+ParagraphLayout
+    { paragraphRect = Rect {x_origin = 0, y_origin = 0, x_size = 8030, y_size = -1621}
+    , paragraphLines =
+        [ Line {lineNumber = 1, lineRect = Rect {x_origin = 0, y_origin = 0, x_size = 8030, y_size = -1621}}
+        ]
+    , paragraphFragments =
+        [ Fragment
+            { fragmentUserData = "outer start"
+            , fragmentLine = 1
+            , fragmentAncestorBoxes =
+                []
+            , fragmentContentRect = Rect {x_origin = 0, y_origin = -500, x_size = 3942, y_size = -1121}
+            , fragmentRect = Rect {x_origin = 0, y_origin = -500, x_size = 3942, y_size = -1121}
+            , fragmentPen = (0, -932)
+            , fragmentGlyphs =
+                [ (GlyphInfo {codepoint = 82, cluster = 5, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 590, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 81, cluster = 6, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 574, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 72, cluster = 7, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 559, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 3, cluster = 8, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 231, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 87, cluster = 9, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 402, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 90, cluster = 10, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 765, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 82, cluster = 11, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 590, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 3, cluster = 12, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 231, y_advance = 0, x_offset = 0, y_offset = 0})
+                ]
+            }
+        , Fragment
+            { fragmentUserData = "inner"
+            , fragmentLine = 1
+            , fragmentAncestorBoxes =
+                [ AncestorBox {boxUserData = "box", boxLeftEdge = SpacedEdge 0, boxRightEdge = SpacedEdge 0, boxStartEdge = SpacedEdge 0, boxEndEdge = SpacedEdge 0}
+                ]
+            , fragmentContentRect = Rect {x_origin = 3942, y_origin = 0, x_size = 0, y_size = -1121}
+            , fragmentRect = Rect {x_origin = 3942, y_origin = 0, x_size = 0, y_size = -1121}
+            , fragmentPen = (0, -932)
+            , fragmentGlyphs =
+                []
+            }
+        , Fragment
+            { fragmentUserData = "outer end"
+            , fragmentLine = 1
+            , fragmentAncestorBoxes =
+                []
+            , fragmentContentRect = Rect {x_origin = 3942, y_origin = -500, x_size = 4088, y_size = -1121}
+            , fragmentRect = Rect {x_origin = 3942, y_origin = -500, x_size = 4088, y_size = -1121}
+            , fragmentPen = (0, -932)
+            , fragmentGlyphs =
+                [ (GlyphInfo {codepoint = 3, cluster = 13, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 231, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 73, cluster = 14, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 386, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 82, cluster = 15, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 590, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 88, cluster = 16, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 574, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 85, cluster = 17, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 386, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 3, cluster = 18, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 231, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 428, cluster = 19, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 643, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 89, cluster = 21, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 488, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 72, cluster = 22, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 559, y_advance = 0, x_offset = 0, y_offset = 0})
+                ]
+            }
+        ]
+    }
diff --git a/.golden/richParagraphLayout/offsetMiddleUpOuterTextWrap.golden b/.golden/richParagraphLayout/offsetMiddleUpOuterTextWrap.golden
new file mode 100644
--- /dev/null
+++ b/.golden/richParagraphLayout/offsetMiddleUpOuterTextWrap.golden
@@ -0,0 +1,91 @@
+ParagraphLayout
+    { paragraphRect = Rect {x_origin = 0, y_origin = 0, x_size = 1936, y_size = -4984}
+    , paragraphLines =
+        [ Line {lineNumber = 1, lineRect = Rect {x_origin = 0, y_origin = 0, x_size = 1936, y_size = -1121}}
+        , Line {lineNumber = 2, lineRect = Rect {x_origin = 0, y_origin = -1121, x_size = 1936, y_size = -1621}}
+        , Line {lineNumber = 3, lineRect = Rect {x_origin = 0, y_origin = -2742, x_size = 1936, y_size = -1121}}
+        , Line {lineNumber = 4, lineRect = Rect {x_origin = 0, y_origin = -3863, x_size = 1936, y_size = -1121}}
+        ]
+    , paragraphFragments =
+        [ Fragment
+            { fragmentUserData = "outer start"
+            , fragmentLine = 1
+            , fragmentAncestorBoxes =
+                []
+            , fragmentContentRect = Rect {x_origin = 0, y_origin = 0, x_size = 1723, y_size = -1121}
+            , fragmentRect = Rect {x_origin = 0, y_origin = 0, x_size = 1723, y_size = -1121}
+            , fragmentPen = (0, -932)
+            , fragmentGlyphs =
+                [ (GlyphInfo {codepoint = 82, cluster = 5, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 590, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 81, cluster = 6, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 574, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 72, cluster = 7, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 559, y_advance = 0, x_offset = 0, y_offset = 0})
+                ]
+            }
+        , Fragment
+            { fragmentUserData = "outer start"
+            , fragmentLine = 2
+            , fragmentAncestorBoxes =
+                []
+            , fragmentContentRect = Rect {x_origin = 0, y_origin = -1621, x_size = 1757, y_size = -1121}
+            , fragmentRect = Rect {x_origin = 0, y_origin = -1621, x_size = 1757, y_size = -1121}
+            , fragmentPen = (0, -932)
+            , fragmentGlyphs =
+                [ (GlyphInfo {codepoint = 87, cluster = 9, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 402, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 90, cluster = 10, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 765, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 82, cluster = 11, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 590, y_advance = 0, x_offset = 0, y_offset = 0})
+                ]
+            }
+        , Fragment
+            { fragmentUserData = "inner"
+            , fragmentLine = 2
+            , fragmentAncestorBoxes =
+                [ AncestorBox {boxUserData = "box", boxLeftEdge = SpacedEdge 0, boxRightEdge = SpacedEdge 0, boxStartEdge = SpacedEdge 0, boxEndEdge = SpacedEdge 0}
+                ]
+            , fragmentContentRect = Rect {x_origin = 1757, y_origin = -1121, x_size = 0, y_size = -1121}
+            , fragmentRect = Rect {x_origin = 1757, y_origin = -1121, x_size = 0, y_size = -1121}
+            , fragmentPen = (0, -932)
+            , fragmentGlyphs =
+                []
+            }
+        , Fragment
+            { fragmentUserData = "outer end"
+            , fragmentLine = 2
+            , fragmentAncestorBoxes =
+                []
+            , fragmentContentRect = Rect {x_origin = 1757, y_origin = -1621, x_size = 0, y_size = -1121}
+            , fragmentRect = Rect {x_origin = 1757, y_origin = -1621, x_size = 0, y_size = -1121}
+            , fragmentPen = (0, -932)
+            , fragmentGlyphs =
+                []
+            }
+        , Fragment
+            { fragmentUserData = "outer end"
+            , fragmentLine = 3
+            , fragmentAncestorBoxes =
+                []
+            , fragmentContentRect = Rect {x_origin = 0, y_origin = -2742, x_size = 1936, y_size = -1121}
+            , fragmentRect = Rect {x_origin = 0, y_origin = -2742, x_size = 1936, y_size = -1121}
+            , fragmentPen = (0, -932)
+            , fragmentGlyphs =
+                [ (GlyphInfo {codepoint = 73, cluster = 14, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 386, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 82, cluster = 15, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 590, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 88, cluster = 16, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 574, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 85, cluster = 17, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 386, y_advance = 0, x_offset = 0, y_offset = 0})
+                ]
+            }
+        , Fragment
+            { fragmentUserData = "outer end"
+            , fragmentLine = 4
+            , fragmentAncestorBoxes =
+                []
+            , fragmentContentRect = Rect {x_origin = 0, y_origin = -3863, x_size = 1690, y_size = -1121}
+            , fragmentRect = Rect {x_origin = 0, y_origin = -3863, x_size = 1690, y_size = -1121}
+            , fragmentPen = (0, -932)
+            , fragmentGlyphs =
+                [ (GlyphInfo {codepoint = 428, cluster = 19, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 643, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 89, cluster = 21, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 488, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 72, cluster = 22, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 559, y_advance = 0, x_offset = 0, y_offset = 0})
+                ]
+            }
+        ]
+    }
diff --git a/.golden/richParagraphLayout/offsetTextlessBoxDown.golden b/.golden/richParagraphLayout/offsetTextlessBoxDown.golden
new file mode 100644
--- /dev/null
+++ b/.golden/richParagraphLayout/offsetTextlessBoxDown.golden
@@ -0,0 +1,38 @@
+ParagraphLayout
+    { paragraphRect = Rect {x_origin = 0, y_origin = 0, x_size = 2624, y_size = -1621}
+    , paragraphLines =
+        [ Line {lineNumber = 1, lineRect = Rect {x_origin = 0, y_origin = 0, x_size = 2624, y_size = -1621}}
+        ]
+    , paragraphFragments =
+        [ Fragment
+            { fragmentUserData = "outer"
+            , fragmentLine = 1
+            , fragmentAncestorBoxes =
+                []
+            , fragmentContentRect = Rect {x_origin = 0, y_origin = 0, x_size = 1797, y_size = -1121}
+            , fragmentRect = Rect {x_origin = 0, y_origin = 0, x_size = 1797, y_size = -1121}
+            , fragmentPen = (0, -932)
+            , fragmentGlyphs =
+                [ (GlyphInfo {codepoint = 82, cluster = 6, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 590, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 88, cluster = 7, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 574, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 87, cluster = 8, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 402, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 3, cluster = 9, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 231, y_advance = 0, x_offset = 0, y_offset = 0})
+                ]
+            }
+        , Fragment
+            { fragmentUserData = "inner"
+            , fragmentLine = 1
+            , fragmentAncestorBoxes =
+                [ AncestorBox {boxUserData = "text box", boxLeftEdge = SpacedEdge 0, boxRightEdge = SpacedEdge 0, boxStartEdge = SpacedEdge 0, boxEndEdge = SpacedEdge 0}
+                , AncestorBox {boxUserData = "textless box", boxLeftEdge = SpacedEdge 0, boxRightEdge = SpacedEdge 0, boxStartEdge = SpacedEdge 0, boxEndEdge = SpacedEdge 0}
+                ]
+            , fragmentContentRect = Rect {x_origin = 1797, y_origin = -500, x_size = 827, y_size = -1121}
+            , fragmentRect = Rect {x_origin = 1797, y_origin = -500, x_size = 827, y_size = -1121}
+            , fragmentPen = (0, -932)
+            , fragmentGlyphs =
+                [ (GlyphInfo {codepoint = 76, cluster = 10, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 253, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 81, cluster = 11, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 574, y_advance = 0, x_offset = 0, y_offset = 0})
+                ]
+            }
+        ]
+    }
diff --git a/.golden/richParagraphLayout/offsetTextlessBoxUp.golden b/.golden/richParagraphLayout/offsetTextlessBoxUp.golden
new file mode 100644
--- /dev/null
+++ b/.golden/richParagraphLayout/offsetTextlessBoxUp.golden
@@ -0,0 +1,38 @@
+ParagraphLayout
+    { paragraphRect = Rect {x_origin = 0, y_origin = 0, x_size = 2624, y_size = -1621}
+    , paragraphLines =
+        [ Line {lineNumber = 1, lineRect = Rect {x_origin = 0, y_origin = 0, x_size = 2624, y_size = -1621}}
+        ]
+    , paragraphFragments =
+        [ Fragment
+            { fragmentUserData = "outer"
+            , fragmentLine = 1
+            , fragmentAncestorBoxes =
+                []
+            , fragmentContentRect = Rect {x_origin = 0, y_origin = -500, x_size = 1797, y_size = -1121}
+            , fragmentRect = Rect {x_origin = 0, y_origin = -500, x_size = 1797, y_size = -1121}
+            , fragmentPen = (0, -932)
+            , fragmentGlyphs =
+                [ (GlyphInfo {codepoint = 82, cluster = 6, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 590, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 88, cluster = 7, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 574, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 87, cluster = 8, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 402, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 3, cluster = 9, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 231, y_advance = 0, x_offset = 0, y_offset = 0})
+                ]
+            }
+        , Fragment
+            { fragmentUserData = "inner"
+            , fragmentLine = 1
+            , fragmentAncestorBoxes =
+                [ AncestorBox {boxUserData = "text box", boxLeftEdge = SpacedEdge 0, boxRightEdge = SpacedEdge 0, boxStartEdge = SpacedEdge 0, boxEndEdge = SpacedEdge 0}
+                , AncestorBox {boxUserData = "textless box", boxLeftEdge = SpacedEdge 0, boxRightEdge = SpacedEdge 0, boxStartEdge = SpacedEdge 0, boxEndEdge = SpacedEdge 0}
+                ]
+            , fragmentContentRect = Rect {x_origin = 1797, y_origin = -500, x_size = 827, y_size = -1121}
+            , fragmentRect = Rect {x_origin = 1797, y_origin = -500, x_size = 827, y_size = -1121}
+            , fragmentPen = (0, -932)
+            , fragmentGlyphs =
+                [ (GlyphInfo {codepoint = 76, cluster = 10, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 253, y_advance = 0, x_offset = 0, y_offset = 0})
+                , (GlyphInfo {codepoint = 81, cluster = 11, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 574, y_advance = 0, x_offset = 0, y_offset = 0})
+                ]
+            }
+        ]
+    }
diff --git a/.golden/richParagraphLayout/spaceBoxCollapsed.golden b/.golden/richParagraphLayout/spaceBoxCollapsed.golden
--- a/.golden/richParagraphLayout/spaceBoxCollapsed.golden
+++ b/.golden/richParagraphLayout/spaceBoxCollapsed.golden
@@ -1,5 +1,15 @@
 ParagraphLayout
     { paragraphRect = Rect {x_origin = 0, y_origin = 0, x_size = 590, y_size = -8968}
+    , paragraphLines =
+        [ Line {lineNumber = 1, lineRect = Rect {x_origin = 0, y_origin = 0, x_size = 590, y_size = -1121}}
+        , Line {lineNumber = 2, lineRect = Rect {x_origin = 0, y_origin = -1121, x_size = 590, y_size = -1121}}
+        , Line {lineNumber = 3, lineRect = Rect {x_origin = 0, y_origin = -2242, x_size = 590, y_size = -1121}}
+        , Line {lineNumber = 4, lineRect = Rect {x_origin = 0, y_origin = -3363, x_size = 590, y_size = -1121}}
+        , Line {lineNumber = 5, lineRect = Rect {x_origin = 0, y_origin = -4484, x_size = 590, y_size = -1121}}
+        , Line {lineNumber = 6, lineRect = Rect {x_origin = 0, y_origin = -5605, x_size = 590, y_size = -1121}}
+        , Line {lineNumber = 7, lineRect = Rect {x_origin = 0, y_origin = -6726, x_size = 590, y_size = -1121}}
+        , Line {lineNumber = 8, lineRect = Rect {x_origin = 0, y_origin = -7847, x_size = 590, y_size = -1121}}
+        ]
     , paragraphFragments =
         [ Fragment
             { fragmentUserData = "text1"
diff --git a/.golden/richParagraphLayout/spaceBoxMiddle.golden b/.golden/richParagraphLayout/spaceBoxMiddle.golden
--- a/.golden/richParagraphLayout/spaceBoxMiddle.golden
+++ b/.golden/richParagraphLayout/spaceBoxMiddle.golden
@@ -1,5 +1,8 @@
 ParagraphLayout
     { paragraphRect = Rect {x_origin = 0, y_origin = 0, x_size = 4635, y_size = -1121}
+    , paragraphLines =
+        [ Line {lineNumber = 1, lineRect = Rect {x_origin = 0, y_origin = 0, x_size = 4635, y_size = -1121}}
+        ]
     , paragraphFragments =
         [ Fragment
             { fragmentUserData = "text1"
diff --git a/.golden/richParagraphLayout/spaceBoxPreserved.golden b/.golden/richParagraphLayout/spaceBoxPreserved.golden
--- a/.golden/richParagraphLayout/spaceBoxPreserved.golden
+++ b/.golden/richParagraphLayout/spaceBoxPreserved.golden
@@ -1,5 +1,16 @@
 ParagraphLayout
     { paragraphRect = Rect {x_origin = 0, y_origin = 0, x_size = 590, y_size = -10089}
+    , paragraphLines =
+        [ Line {lineNumber = 1, lineRect = Rect {x_origin = 0, y_origin = 0, x_size = 590, y_size = -1121}}
+        , Line {lineNumber = 2, lineRect = Rect {x_origin = 0, y_origin = -1121, x_size = 590, y_size = -1121}}
+        , Line {lineNumber = 3, lineRect = Rect {x_origin = 0, y_origin = -2242, x_size = 590, y_size = -1121}}
+        , Line {lineNumber = 4, lineRect = Rect {x_origin = 0, y_origin = -3363, x_size = 590, y_size = -1121}}
+        , Line {lineNumber = 5, lineRect = Rect {x_origin = 0, y_origin = -4484, x_size = 590, y_size = -1121}}
+        , Line {lineNumber = 6, lineRect = Rect {x_origin = 0, y_origin = -5605, x_size = 590, y_size = -1121}}
+        , Line {lineNumber = 7, lineRect = Rect {x_origin = 0, y_origin = -6726, x_size = 590, y_size = -1121}}
+        , Line {lineNumber = 8, lineRect = Rect {x_origin = 0, y_origin = -7847, x_size = 590, y_size = -1121}}
+        , Line {lineNumber = 9, lineRect = Rect {x_origin = 0, y_origin = -8968, x_size = 590, y_size = -1121}}
+        ]
     , paragraphFragments =
         [ Fragment
             { fragmentUserData = "text1"
diff --git a/.golden/shapedRuns/mixedVerticalAlignment.fontInfo b/.golden/shapedRuns/mixedVerticalAlignment.fontInfo
new file mode 100644
--- /dev/null
+++ b/.golden/shapedRuns/mixedVerticalAlignment.fontInfo
@@ -0,0 +1,1 @@
+assets/fonts/ubuntu/Ubuntu-R.ttf 0 32,32 32,32
diff --git a/.golden/shapedRuns/mixedVerticalAlignment.golden b/.golden/shapedRuns/mixedVerticalAlignment.golden
new file mode 100644
--- /dev/null
+++ b/.golden/shapedRuns/mixedVerticalAlignment.golden
@@ -0,0 +1,117 @@
+[ (0, -57, 
+    [ (GlyphInfo {codepoint = 88, cluster = 6, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 18, y_advance = 0, x_offset = 0, y_offset = 0})
+    , (GlyphInfo {codepoint = 83, cluster = 7, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 19, y_advance = 0, x_offset = 0, y_offset = 0})
+    , (GlyphInfo {codepoint = 3, cluster = 8, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 7, y_advance = 0, x_offset = 0, y_offset = 0})
+    ])
+, (44, -48, 
+    [ (GlyphInfo {codepoint = 75, cluster = 9, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 18, y_advance = 0, x_offset = 0, y_offset = 0})
+    , (GlyphInfo {codepoint = 76, cluster = 10, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 8, y_advance = 0, x_offset = 0, y_offset = 0})
+    , (GlyphInfo {codepoint = 74, cluster = 11, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 18, y_advance = 0, x_offset = 0, y_offset = 0})
+    , (GlyphInfo {codepoint = 75, cluster = 12, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 18, y_advance = 0, x_offset = 0, y_offset = 0})
+    , (GlyphInfo {codepoint = 3, cluster = 13, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 7, y_advance = 0, x_offset = 0, y_offset = 0})
+    ])
+, (113, -42, 
+    [ (GlyphInfo {codepoint = 68, cluster = 14, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 17, y_advance = 0, x_offset = 0, y_offset = 0})
+    , (GlyphInfo {codepoint = 81, cluster = 15, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 18, y_advance = 0, x_offset = 0, y_offset = 0})
+    , (GlyphInfo {codepoint = 71, cluster = 16, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 19, y_advance = 0, x_offset = 0, y_offset = 0})
+    , (GlyphInfo {codepoint = 3, cluster = 17, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 7, y_advance = 0, x_offset = 0, y_offset = 0})
+    ])
+, (174, -40, 
+    [ (GlyphInfo {codepoint = 75, cluster = 18, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 18, y_advance = 0, x_offset = 0, y_offset = 0})
+    , (GlyphInfo {codepoint = 76, cluster = 19, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 8, y_advance = 0, x_offset = 0, y_offset = 0})
+    , (GlyphInfo {codepoint = 74, cluster = 20, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 18, y_advance = 0, x_offset = 0, y_offset = 0})
+    , (GlyphInfo {codepoint = 75, cluster = 21, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 18, y_advance = 0, x_offset = 0, y_offset = 0})
+    , (GlyphInfo {codepoint = 72, cluster = 22, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 18, y_advance = 0, x_offset = 0, y_offset = 0})
+    , (GlyphInfo {codepoint = 85, cluster = 23, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 12, y_advance = 0, x_offset = 0, y_offset = 0})
+    , (GlyphInfo {codepoint = 3, cluster = 24, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 7, y_advance = 0, x_offset = 0, y_offset = 0})
+    ])
+, (273, -57, 
+    [ (GlyphInfo {codepoint = 71, cluster = 25, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 19, y_advance = 0, x_offset = 0, y_offset = 0})
+    , (GlyphInfo {codepoint = 82, cluster = 26, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 19, y_advance = 0, x_offset = 0, y_offset = 0})
+    , (GlyphInfo {codepoint = 90, cluster = 27, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 25, y_advance = 0, x_offset = 0, y_offset = 0})
+    , (GlyphInfo {codepoint = 81, cluster = 28, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 18, y_advance = 0, x_offset = 0, y_offset = 0})
+    , (GlyphInfo {codepoint = 3, cluster = 29, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 7, y_advance = 0, x_offset = 0, y_offset = 0})
+    ])
+, (361, -66, 
+    [ (GlyphInfo {codepoint = 79, cluster = 30, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 9, y_advance = 0, x_offset = 0, y_offset = 0})
+    , (GlyphInfo {codepoint = 82, cluster = 31, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 19, y_advance = 0, x_offset = 0, y_offset = 0})
+    , (GlyphInfo {codepoint = 90, cluster = 32, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 25, y_advance = 0, x_offset = 0, y_offset = 0})
+    , (GlyphInfo {codepoint = 3, cluster = 33, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 7, y_advance = 0, x_offset = 0, y_offset = 0})
+    ])
+, (421, -72, 
+    [ (GlyphInfo {codepoint = 68, cluster = 34, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 17, y_advance = 0, x_offset = 0, y_offset = 0})
+    , (GlyphInfo {codepoint = 81, cluster = 35, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 18, y_advance = 0, x_offset = 0, y_offset = 0})
+    , (GlyphInfo {codepoint = 71, cluster = 36, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 19, y_advance = 0, x_offset = 0, y_offset = 0})
+    , (GlyphInfo {codepoint = 3, cluster = 37, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 7, y_advance = 0, x_offset = 0, y_offset = 0})
+    ])
+, (482, -74, 
+    [ (GlyphInfo {codepoint = 79, cluster = 38, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 9, y_advance = 0, x_offset = 0, y_offset = 0})
+    , (GlyphInfo {codepoint = 82, cluster = 39, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 19, y_advance = 0, x_offset = 0, y_offset = 0})
+    , (GlyphInfo {codepoint = 90, cluster = 40, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 25, y_advance = 0, x_offset = 0, y_offset = 0})
+    , (GlyphInfo {codepoint = 72, cluster = 41, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 18, y_advance = 0, x_offset = 0, y_offset = 0})
+    , (GlyphInfo {codepoint = 85, cluster = 42, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 12, y_advance = 0, x_offset = 0, y_offset = 0})
+    , (GlyphInfo {codepoint = 3, cluster = 43, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 7, y_advance = 0, x_offset = 0, y_offset = 0})
+    ])
+, (572, -12, 
+    [ (GlyphInfo {codepoint = 59, cluster = 44, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 20, y_advance = 0, x_offset = 0, y_offset = 0})
+    , (GlyphInfo {codepoint = 3, cluster = 45, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 7, y_advance = 0, x_offset = 0, y_offset = 0})
+    ])
+, (599, -92, 
+    [ (GlyphInfo {codepoint = 59, cluster = 46, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 20, y_advance = 0, x_offset = 0, y_offset = 0})
+    , (GlyphInfo {codepoint = 3, cluster = 47, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 7, y_advance = 0, x_offset = 0, y_offset = 0})
+    ])
+, (626, -57, 
+    [ (GlyphInfo {codepoint = 86, cluster = 48, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 14, y_advance = 0, x_offset = 0, y_offset = 0})
+    , (GlyphInfo {codepoint = 87, cluster = 49, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 13, y_advance = 0, x_offset = 0, y_offset = 0})
+    , (GlyphInfo {codepoint = 85, cluster = 50, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 12, y_advance = 0, x_offset = 0, y_offset = 0})
+    , (GlyphInfo {codepoint = 72, cluster = 51, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 18, y_advance = 0, x_offset = 0, y_offset = 0})
+    , (GlyphInfo {codepoint = 87, cluster = 52, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 13, y_advance = 0, x_offset = 0, y_offset = 0})
+    , (GlyphInfo {codepoint = 70, cluster = 53, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 15, y_advance = 0, x_offset = 0, y_offset = 0})
+    , (GlyphInfo {codepoint = 75, cluster = 54, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 18, y_advance = 0, x_offset = 0, y_offset = 0})
+    , (GlyphInfo {codepoint = 76, cluster = 55, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 8, y_advance = 0, x_offset = 0, y_offset = 0})
+    , (GlyphInfo {codepoint = 81, cluster = 56, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 18, y_advance = 0, x_offset = 0, y_offset = 0})
+    , (GlyphInfo {codepoint = 74, cluster = 57, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 18, y_advance = 0, x_offset = 0, y_offset = 0})
+    , (GlyphInfo {codepoint = 3, cluster = 58, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 7, y_advance = 0, x_offset = 0, y_offset = 0})
+    ])
+, (780, -48, 
+    [ (GlyphInfo {codepoint = 87, cluster = 59, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 13, y_advance = 0, x_offset = 0, y_offset = 0})
+    , (GlyphInfo {codepoint = 68, cluster = 60, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 17, y_advance = 0, x_offset = 0, y_offset = 0})
+    , (GlyphInfo {codepoint = 79, cluster = 61, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 9, y_advance = 0, x_offset = 0, y_offset = 0})
+    , (GlyphInfo {codepoint = 79, cluster = 62, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 9, y_advance = 0, x_offset = 0, y_offset = 0})
+    , (GlyphInfo {codepoint = 3, cluster = 63, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 7, y_advance = 0, x_offset = 0, y_offset = 0})
+    ])
+, (835, -30, 
+    [ (GlyphInfo {codepoint = 70, cluster = 64, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 15, y_advance = 0, x_offset = 0, y_offset = 0})
+    , (GlyphInfo {codepoint = 79, cluster = 65, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 9, y_advance = 0, x_offset = 0, y_offset = 0})
+    , (GlyphInfo {codepoint = 76, cluster = 66, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 8, y_advance = 0, x_offset = 0, y_offset = 0})
+    , (GlyphInfo {codepoint = 80, cluster = 67, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 28, y_advance = 0, x_offset = 0, y_offset = 0})
+    , (GlyphInfo {codepoint = 68, cluster = 68, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 17, y_advance = 0, x_offset = 0, y_offset = 0})
+    , (GlyphInfo {codepoint = 91, cluster = 69, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 16, y_advance = 0, x_offset = 0, y_offset = 0})
+    , (GlyphInfo {codepoint = 3, cluster = 70, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 7, y_advance = 0, x_offset = 0, y_offset = 0})
+    ])
+, (935, -42, 
+    [ (GlyphInfo {codepoint = 83, cluster = 71, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 19, y_advance = 0, x_offset = 0, y_offset = 0})
+    , (GlyphInfo {codepoint = 85, cluster = 72, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 12, y_advance = 0, x_offset = 0, y_offset = 0})
+    , (GlyphInfo {codepoint = 72, cluster = 73, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 18, y_advance = 0, x_offset = 0, y_offset = 0})
+    , (GlyphInfo {codepoint = 70, cluster = 74, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 15, y_advance = 0, x_offset = 0, y_offset = 0})
+    , (GlyphInfo {codepoint = 72, cluster = 75, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 18, y_advance = 0, x_offset = 0, y_offset = 0})
+    , (GlyphInfo {codepoint = 71, cluster = 76, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 19, y_advance = 0, x_offset = 0, y_offset = 0})
+    , (GlyphInfo {codepoint = 76, cluster = 77, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 8, y_advance = 0, x_offset = 0, y_offset = 0})
+    , (GlyphInfo {codepoint = 81, cluster = 78, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 18, y_advance = 0, x_offset = 0, y_offset = 0})
+    , (GlyphInfo {codepoint = 74, cluster = 79, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 18, y_advance = 0, x_offset = 0, y_offset = 0})
+    , (GlyphInfo {codepoint = 3, cluster = 80, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 7, y_advance = 0, x_offset = 0, y_offset = 0})
+    ])
+, (1087, -30, 
+    [ (GlyphInfo {codepoint = 87, cluster = 81, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 13, y_advance = 0, x_offset = 0, y_offset = 0})
+    , (GlyphInfo {codepoint = 75, cluster = 82, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 18, y_advance = 0, x_offset = 0, y_offset = 0})
+    , (GlyphInfo {codepoint = 72, cluster = 83, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 18, y_advance = 0, x_offset = 0, y_offset = 0})
+    , (GlyphInfo {codepoint = 3, cluster = 84, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 7, y_advance = 0, x_offset = 0, y_offset = 0})
+    ])
+, (1143, -74, 
+    [ (GlyphInfo {codepoint = 70, cluster = 85, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 15, y_advance = 0, x_offset = 0, y_offset = 0})
+    , (GlyphInfo {codepoint = 85, cluster = 86, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 12, y_advance = 0, x_offset = 0, y_offset = 0})
+    , (GlyphInfo {codepoint = 68, cluster = 87, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 17, y_advance = 0, x_offset = 0, y_offset = 0})
+    , (GlyphInfo {codepoint = 86, cluster = 88, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 14, y_advance = 0, x_offset = 0, y_offset = 0})
+    , (GlyphInfo {codepoint = 75, cluster = 89, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False}, GlyphPos {x_advance = 18, y_advance = 0, x_offset = 0, y_offset = 0})
+    ])
+]
diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,29 @@
 # Revision history for Balkón
 
+## 1.3.0.0 -- 2023-07-03
+
+* Added options for vertical box alignment:
+  line top, line bottom, baseline with optional offset.
+
+    * For backwards compatibility, line top alignment remains the default.
+      Consider updating your code to use baseline alignment instead.
+
+* Added `paragraphLines` to the rich text `ParagraphLayout`.
+  This describes the dimensions of each line of wrapped text,
+  including situations when the line contains more space than
+  what is necessary to contain its fragments.
+  This new field must be passed to pagination.
+
+* The width of a rich text `ParagraphLayout` will now remain unchanged
+  after pagination.
+
+* Lines will now be sized to fit all ancestor boxes of all fragments
+  on the line, as well as the root box, even if some of those boxes
+  do not directly contain any text.
+  Each box effectively contains an invisible "strut", which is required by CSS.
+
+* Added options to override text ascender and descender metrics.
+
 ## 1.2.0.0 -- 2023-06-28
 
 * Added options for horizontal paragraph alignment:
diff --git a/TESTING.md b/TESTING.md
--- a/TESTING.md
+++ b/TESTING.md
@@ -150,3 +150,71 @@
          of blank space below the top of the window that is not large enough to
          insert another line of text.
 
+## Script 4: Verify visual output for vertical alignment
+
+Goals:
+
+  - To verify the correct effect of vertical alignment of inline boxes.
+
+Prerequisites:
+
+  - Access to files from the Git repository of Balkón.
+
+  - Successfully built Typograffiti.
+    See previous script.
+
+  - Successfully verified visual output for a whole paragraph.
+    See previous script.
+
+  - A horizontal on-screen ruler to check baseline alignment.
+    In a stacking window manager, the edge of another window can
+    fulfil this role.
+
+Steps:
+
+  1. Run Typograffiti with the font path, face index, pixel size,
+     and scale set according to the contents of the file
+     `.golden/shapedRuns/mixedVerticalAlignment.fontInfo` from Balkón,
+     and with input set to be read from the file
+     `.golden/shapedRuns/mixedVerticalAlignment.golden` from Balkón.
+
+  2. Verify that text is displayed in the output window.
+
+  3. If necessary, resize the window so that the whole line can be seen.
+     Note that there will be one instance of a letter "X" partially overflowing
+     the top edge of the window, which is intentional.
+
+  4. Verify all of the following:
+
+      a. There is a line of text displayed, whose (vertically displaced) words
+         read, left to right: "up high and higher down low and lower X X
+         stretching tall climax preceding the crash"
+
+      b. The baselines of the words "up", "down", and "stretching" are aligned
+         to each other.
+
+      c. The baselines of the words "lower" and "crash" are aligned
+         to each other.
+
+      d. The baselines of the words "climax" and "the" are aligned
+         to each other.
+
+      e. In the sequence of words "up high and higher", each word is placed
+         higher than its preceding word.
+
+      f. In the sequence of words "down low and lower", each word is placed
+         lower than its preceding word.
+
+      g. The words "climax" and "the" are placed at the top of the window,
+         with only a small amount of blank space below the top of the window.
+
+      h. The word "higher" is placed lower than the words "climax" and "the".
+
+      i. The first letter "X" is placed higher than any of the words,
+         and the centre of the letter's shape approximately intersects the top
+         edge of the window, making only approximately half of it visible.
+
+      j. The second letter "X" is placed lower than any of the words,
+         and the letter's shape intersects the baseline of the words
+         "lower" and "crash".
+
diff --git a/balkon.cabal b/balkon.cabal
--- a/balkon.cabal
+++ b/balkon.cabal
@@ -14,7 +14,7 @@
 -- PVP summary:     +-+------- breaking API changes
 --                  | | +----- non-breaking API additions
 --                  | | | +--- code changes with no API change
-version:            1.2.0.0
+version:            1.3.0.0
 
 stability:          experimental
 
@@ -111,6 +111,7 @@
         Data.Text.ParagraphLayout.Internal.BoxOptions,
         Data.Text.ParagraphLayout.Internal.Break,
         Data.Text.ParagraphLayout.Internal.Fragment,
+        Data.Text.ParagraphLayout.Internal.Line,
         Data.Text.ParagraphLayout.Internal.LineHeight,
         Data.Text.ParagraphLayout.Internal.LinePagination,
         Data.Text.ParagraphLayout.Internal.Paginable,
@@ -144,7 +145,8 @@
         Data.Text.ParagraphLayout.Internal.ProtoLine,
         Data.Text.ParagraphLayout.Internal.ProtoRun,
         Data.Text.ParagraphLayout.Internal.Script,
-        Data.Text.ParagraphLayout.Internal.SplitList
+        Data.Text.ParagraphLayout.Internal.SplitList,
+        Data.Text.ParagraphLayout.Internal.VerticalOffsets
 
     build-depends:
         base >=4.12 && < 4.16,
diff --git a/lib/Data/Text/ParagraphLayout/Rich.hs b/lib/Data/Text/ParagraphLayout/Rich.hs
--- a/lib/Data/Text/ParagraphLayout/Rich.hs
+++ b/lib/Data/Text/ParagraphLayout/Rich.hs
@@ -14,6 +14,11 @@
         )
     , BoxCollapse (AllowBoxCollapse, AvoidBoxCollapse)
     , BoxSpacing (BoxSpacingLeftRight)
+    , VerticalAlignment
+        ( AlignLineTop
+        , AlignLineBottom
+        , AlignBaseline
+        )
     , LineHeight (Absolute, Normal)
     , ParagraphOptions
     , defaultParagraphOptions
@@ -39,11 +44,14 @@
     -- as well as updating specific option fields.
     , boxSpacing
     , boxCollapse
+    , boxVerticalAlignment
     , activateBoxSpacing
     -- ** Text options
     -- | These are record selectors that can be used for reading
     -- as well as updating specific option fields.
     , textFont
+    , textAscender
+    , textDescender
     , textLineHeight
     , textLanguage
     , textDirection
@@ -53,8 +61,18 @@
     , paragraphText
     -- * Output layout
     , layoutRich
-    , ParagraphLayout (ParagraphLayout, paragraphRect, paragraphFragments)
+    , ParagraphLayout
+        ( ParagraphLayout
+        , paragraphRect
+        , paragraphLines
+        , paragraphFragments
+        )
     , paragraphSafeWidth
+    , Line
+        ( Line
+        , lineNumber
+        , lineRect
+        )
     , Fragment
         ( Fragment
         , fragmentUserData
@@ -81,6 +99,7 @@
 import Data.Text.ParagraphLayout.Internal.AncestorBox
 import Data.Text.ParagraphLayout.Internal.BoxOptions
 import Data.Text.ParagraphLayout.Internal.Fragment
+import Data.Text.ParagraphLayout.Internal.Line
 import Data.Text.ParagraphLayout.Internal.LineHeight
 import Data.Text.ParagraphLayout.Internal.ParagraphAlignment
 import Data.Text.ParagraphLayout.Internal.ParagraphOptions
diff --git a/src/Data/Text/ParagraphLayout/Internal/BoxOptions.hs b/src/Data/Text/ParagraphLayout/Internal/BoxOptions.hs
--- a/src/Data/Text/ParagraphLayout/Internal/BoxOptions.hs
+++ b/src/Data/Text/ParagraphLayout/Internal/BoxOptions.hs
@@ -2,6 +2,7 @@
     ( BoxCollapse (..)
     , BoxOptions (..)
     , BoxSpacing (..)
+    , VerticalAlignment (..)
     , activateBoxSpacing
     , defaultBoxOptions
     )
@@ -14,6 +15,10 @@
 -- This record type is likely to be extended in the future.
 -- Use `defaultBoxOptions` and update it with specific record selectors
 -- instead of constructing `BoxOptions` directly.
+--
+-- In order to get CSS defaults, use:
+--
+-- > defaultBoxOptions { boxVerticalAlignment = AlignBaseline 0 }
 data BoxOptions = BoxOptions
 
     { boxSpacing :: BoxSpacing
@@ -30,7 +35,8 @@
     -- ^ Determines how this box affects the height of a line that would
     -- otherwise be empty.
 
-    -- TODO: textVerticalAlign
+    , boxVerticalAlignment :: VerticalAlignment
+    -- ^ Determines how fragments are aligned vertically within a line.
 
     }
     deriving (Eq)
@@ -92,11 +98,59 @@
 
     deriving (Eq, Read, Show)
 
--- | `BoxOptions` with default values.
+-- | Determines how the contents of a line should be aligned vertically,
+-- that is, how fragments should fill (and possibly extend) the vertical space
+-- inside a line.
+--
+-- Vertical alignment takes place after line breaking.
+data VerticalAlignment
+
+    = AlignLineTop
+    -- ^ Align the top of this box with the top of the line.
+    --
+    -- The /top of this box/ is the topmost coordinate of any fragment
+    -- descended from this box, except for fragments that are descended from
+    -- another box with `AlignLineTop` or `AlignLineBottom` closer to them.
+    --
+    -- t`Data.Text.ParagraphLayout.Rich.LineHeight` is included
+    -- when considering the /top/ coordinates of descended fragments,
+    -- and thus, leading is included.
+    --
+    -- This behaviour is equivalent to @vertical-align: top@ in CSS.
+
+    | AlignLineBottom
+    -- ^ Align the bottom of this box with the bottom of the line.
+    --
+    -- The /bottom of this box/ is the bottommost coordinate of any fragment
+    -- descended from this box, except for fragments that are descended from
+    -- another box with `AlignLineTop` or `AlignLineBottom` closer to them.
+    --
+    -- t`Data.Text.ParagraphLayout.Rich.LineHeight` is included
+    -- when considering the /bottom/ coordinates of descended fragments,
+    -- and thus, leading is included.
+    --
+    -- This behaviour is equivalent to @vertical-align: bottom@ in CSS.
+
+    | AlignBaseline Int32
+    -- ^ Align the baseline of this box with the baseline of its parent box,
+    -- optionally shifting it by a specified amount upwards.
+    --
+    -- @`AlignBaseline` 0@ is equivalent to @vertical-align: baseline@ in CSS.
+    --
+    -- @`AlignBaseline` x@ is equivalent to @vertical-align: \<length\>@ in CSS,
+    -- after an appropriate unit conversion.
+
+    deriving (Eq, Read, Show)
+
+-- | `BoxOptions` with backwards-compatible values.
+--
+-- Note that this sets `boxVerticalAlignment` to `AlignLineTop`,
+-- whereas the CSS default should be `AlignBaseline 0`.
 defaultBoxOptions :: BoxOptions
 defaultBoxOptions = BoxOptions
     { boxSpacing = BoxSpacingLeftRight 0 0
     , boxCollapse = AllowBoxCollapse
+    , boxVerticalAlignment = AlignLineTop
     }
 
 -- | Shorthand for updating `boxSpacing` and setting `boxCollapse`
diff --git a/src/Data/Text/ParagraphLayout/Internal/Layout.hs b/src/Data/Text/ParagraphLayout/Internal/Layout.hs
--- a/src/Data/Text/ParagraphLayout/Internal/Layout.hs
+++ b/src/Data/Text/ParagraphLayout/Internal/Layout.hs
@@ -11,16 +11,15 @@
 import Data.List.NonEmpty (NonEmpty ((:|)), nonEmpty, (<|))
 import qualified Data.List.NonEmpty as NonEmpty
 import Data.Maybe (fromMaybe)
+import Data.Semigroup (sconcat)
 import Data.Text.Foreign (lengthWord8)
 import Data.Text.Glyphize
     ( Buffer (..)
     , ContentType (ContentTypeUnicode)
     , Direction (DirLTR, DirRTL, DirTTB, DirBTT)
-    , FontExtents (..)
     , GlyphInfo
     , GlyphPos
     , defaultBuffer
-    , fontExtentsForDir
     , shape
     )
 import qualified Data.Text.ICU as BreakStatus (Line (Hard))
@@ -29,9 +28,10 @@
 import Data.Text.ParagraphLayout.Internal.AncestorBox
 import Data.Text.ParagraphLayout.Internal.ApplyBoxes
 import Data.Text.ParagraphLayout.Internal.BiDiReorder
+import Data.Text.ParagraphLayout.Internal.BoxOptions
 import Data.Text.ParagraphLayout.Internal.Break
 import Data.Text.ParagraphLayout.Internal.Fragment
-import Data.Text.ParagraphLayout.Internal.LineHeight
+import Data.Text.ParagraphLayout.Internal.Line
 import Data.Text.ParagraphLayout.Internal.ParagraphAlignment
 import Data.Text.ParagraphLayout.Internal.ParagraphExtents
 import qualified Data.Text.ParagraphLayout.Internal.ProtoFragment as PF
@@ -43,6 +43,7 @@
 import Data.Text.ParagraphLayout.Internal.SplitList
 import Data.Text.ParagraphLayout.Internal.TextContainer
 import Data.Text.ParagraphLayout.Internal.TextOptions
+import qualified Data.Text.ParagraphLayout.Internal.VerticalOffsets as VO
 import Data.Text.ParagraphLayout.Internal.WithSpan
 
 -- This is redundant.
@@ -55,17 +56,22 @@
 -- | Create a multi-line layout from the given runs, splitting them as
 -- necessary to fit within the requested line width.
 --
--- The output is a flat list of fragments positioned in both dimensions.
+-- The first output component is a flat list of fragments positioned
+-- in both dimensions.
+--
+-- The second output component is a list of lines containing the
+-- positioned content.
 layoutAndAlignLines
     :: Direction
     -> ParagraphAlignment
     -> Int32
     -> NonEmpty (WithSpan d Run)
-    -> [FragmentWithSpan d]
-layoutAndAlignLines dir align maxWidth runs = frags
+    -> ([FragmentWithSpan d], [Line])
+layoutAndAlignLines dir align maxWidth runs = (frags, ls)
     where
         frags = concatMap toList fragsInLines
-        (_, fragsInLines) = mapAccumL positionLine originY numberedLines
+        (fragsInLines, ls) = unzip fragsAndLines
+        (_, fragsAndLines) = mapAccumL positionLine originY numberedLines
         positionLine = positionLineH dir align maxWidth
         numberedLines = zip [1 ..] canonicalLines
         canonicalLines = fmap reorderProtoFragments visibleLines
@@ -98,28 +104,86 @@
 -- | Position all the given horizontal fragments on the same line,
 -- using @originY@ as its top edge, and return the bottom edge for continuation.
 --
--- Glyphs will be aligned by their ascent line, similar to the behaviour of
--- @vertical-align: top@ in CSS.
---
--- TODO: For rich text, allow other types of vertical alignment.
+-- Also return a `Line` structure with a defined vertical dimensions
+-- but undefined horizontal dimensions.
 positionLineH
     :: Direction
     -> ParagraphAlignment
     -> Int32
     -> Int32
     -> (Int, PL.ProtoLine NonEmpty d)
-    -> (Int32, NonEmpty (FragmentWithSpan d))
-positionLineH dir align maxWidth originY (num, pl) = (nextY, frags)
+    -> (Int32, (NonEmpty (FragmentWithSpan d), Line))
+positionLineH dir align maxWidth originY (num, pl) =
+    (nextY, (frags, line))
     where
-        nextY = minimum $ fmap y_min rects
-        rects = fmap (\ (WithSpan _ r) -> fragmentRect r) frags
-        (_, frags) = mapAccumL (positionFragmentH num originY) originX wpfs
-        wpfs = PL.applyBoxes pl
+        line = Line { lineNumber = num, lineRect = Rect 0 originY 0 sizeY }
+        sizeY = nextY - originY
+        (_, frags) = mapAccumL (positionFragmentH num) originX wpfs
+        wpfs = PL.applyBoxes alignedLine
+        (nextY, alignedLine) = verticalAlignment originY pl
         originX = paragraphOriginX + if lineWidth > maxWidth
             then overflowingLineOffset dir (lineWidth - maxWidth)
             else fittingLineOffset align dir (maxWidth - lineWidth)
         lineWidth = PL.width pl
 
+-- | Update vertical positions of all fragments on the line so that they
+-- respect vertical alignment settings and fit on a line whose top coordinate
+-- is @originY@. Also returns the bottom coordinate of the line.
+verticalAlignment :: Int32 -> PL.ProtoLine NonEmpty d ->
+    (Int32, PL.ProtoLine NonEmpty d)
+verticalAlignment originY pl = (bottomY, PL.mapFragments setOrigin pl)
+    where
+        setOrigin rs pf =
+            PF.mapVerticalOffsets (VO.alignBaseline (fragOffset rs)) pf
+
+        fragOffset rs = case spanVO rs of
+            (Nothing, vo) -> rootOffset + VO.baseline vo
+            (Just b, vo) -> case boxVerticalAlignment $ RB.boxOptions b of
+                AlignLineTop -> boxTopOffset b + VO.baseline vo
+                AlignLineBottom -> boxBottomOffset b + VO.baseline vo
+                _ -> error "verticalAlignment: wrong box used as anchor"
+
+        bottomY = originY - finalLineHeight
+        finalLineHeight = fittingTop - fittingBottom
+
+        -- Firefox-like behaviour:
+        -- First extend the line upwards to fit bottom-aligned boxes,
+        -- then extend the line downwards to fit top-aligned boxes.
+        fittingTop = maximum $ (:) rootTop $
+            map ((rootBottom +) . boxHeight) bottomAlignedBoxes
+        fittingBottom = minimum $ (:) rootBottom $
+            map ((fittingTop -) . boxHeight) topAlignedBoxes
+
+        rootTop = maximum $ fmap (VO.layoutTop . snd) rootVOs
+        rootBottom = minimum $ fmap (VO.layoutBottom . snd) rootVOs
+        rootVOs = filter VO.underRoot $ toList allVOs
+        rootOffset = originY - fittingTop
+
+        boxHeight b = boxTop b - boxBottom b
+        boxTop b = maximum $ map (VO.layoutTop . snd) $ boxVOs b
+        boxBottom b = minimum $ map (VO.layoutBottom . snd) $ boxVOs b
+        boxVOs b = filter (VO.underBox b) $ toList allVOs
+        -- How much to shift from baseline 0 so that layoutTop = originY?
+        boxTopOffset b = originY - boxTop b
+        -- How much to shift from baseline 0 so that layoutBottom = bottomY?
+        boxBottomOffset b = bottomY - boxBottom b
+
+        boxesOnLine = foldr RB.union [] $ fmap fragBoxes $ PL.protoFragments pl
+        topAlignedBoxes = filter topAligned boxesOnLine
+        bottomAlignedBoxes = filter bottomAligned boxesOnLine
+        topAligned rb =
+            boxVerticalAlignment (RB.boxOptions rb) == AlignLineTop
+        bottomAligned rb =
+            boxVerticalAlignment (RB.boxOptions rb) == AlignLineBottom
+        fragBoxes (WithSpan rs _) = RS.spanBoxes rs
+        -- Struts may get duplicated in `allVOs`.
+        -- This should not be a problem since we are using idempotent functions.
+        allVOs = sconcat $ fmap fragStruttedVOs $ PL.protoFragments pl
+        fragStruttedVOs (WithSpan rs _) = spanStruttedVOs rs
+        spanVO rs = NonEmpty.head $ spanStruttedVOs rs
+        spanStruttedVOs rs =
+            VO.strutted (RS.spanTextOptions rs) (RS.spanBoxes rs)
+
 -- | Inline offset of the first fragment on a line that overflows.
 overflowingLineOffset :: Direction -> Int32 -> Int32
 overflowingLineOffset DirLTR _ = 0
@@ -154,12 +218,11 @@
 centreAlignOffset :: Int32 -> Int32
 centreAlignOffset slack = slack `div` 2
 
--- | Position the given horizontal fragment on a line,
--- using @originY@ as its top edge and @originX@ as its left edge,
--- returning the X coordinate of its right edge for continuation.
-positionFragmentH :: Int -> Int32 -> Int32 -> ProtoFragmentWithBoxes d ->
+-- | Position the given horizontal fragment on a line, using @originX@ as its
+-- left edge, returning the X coordinate of its right edge for continuation.
+positionFragmentH :: Int -> Int32 -> ProtoFragmentWithBoxes d ->
     (Int32, FragmentWithSpan d)
-positionFragmentH line originY originX (WithBoxes lbs (WithSpan rs pf) rbs) =
+positionFragmentH line originX (WithBoxes lbs (WithSpan rs pf) rbs) =
     (nextX, WithSpan rs frag)
     where
         nextX = contentX + contentWidth + rightSpacing
@@ -178,20 +241,17 @@
             }
         userData = RS.spanUserData rs
         bs = ancestorBoxes lbs rbs rs
-        contentRect = Rect contentX contentY contentWidth (-normalLineHeight)
-        contentY = originY + penY + ascent
-        rect = Rect contentX originY contentWidth (-lineHeight)
+        contentRect = Rect contentX fontTop contentWidth (fontBottom - fontTop)
+        rect = Rect contentX layoutTop contentWidth (layoutBottom - layoutTop)
         penX = 0
-        penY = descent + leading `div` 2 - lineHeight
-        lineHeight = case textLineHeight opts of
-            Normal -> normalLineHeight
-            Absolute h -> h
-        leading = lineHeight - normalLineHeight
-        normalLineHeight = ascent + descent
-        ascent = ascender extents
-        descent = - descender extents
-        extents = fontExtentsForDir (textFont opts) (Just $ PF.direction pf)
-        opts = RS.spanTextOptions rs
+        penY = baseline - layoutTop
+        VO.VerticalOffsets
+            { VO.layoutTop = layoutTop
+            , VO.fontTop = fontTop
+            , VO.baseline = baseline
+            , VO.fontBottom = fontBottom
+            , VO.layoutBottom = layoutBottom
+            } = PF.verticalOffsets pf
 
 ancestorBoxes
     :: [RB.ResolvedBox d]
@@ -361,10 +421,11 @@
 layoutRunH :: WithSpan d Run -> ProtoFragmentWithSpan d
 layoutRunH (WithSpan rs run) = WithSpan rs pf
     where
-        pf = PF.protoFragmentH dir lvl glyphs hard
+        pf = PF.protoFragmentH dir lvl vo glyphs hard
         glyphs = shapeRun (WithSpan rs run)
         dir = runDirection run
         lvl = runLevel run
+        vo = VO.fromText (RS.spanTextOptions rs)
         hard = runHardBreak run
 
 -- | Calculate layout for the given run independently of its position.
diff --git a/src/Data/Text/ParagraphLayout/Internal/Line.hs b/src/Data/Text/ParagraphLayout/Internal/Line.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Text/ParagraphLayout/Internal/Line.hs
@@ -0,0 +1,25 @@
+module Data.Text.ParagraphLayout.Internal.Line (Line (..), shiftLine)
+where
+
+import Data.Int (Int32)
+
+import Data.Text.ParagraphLayout.Internal.Rect
+
+-- | Information about a line in a laid out paragraph.
+data Line = Line
+    { lineNumber :: Int
+    -- ^ Logical number of the line box, starting at 1 for a given paragraph.
+    , lineRect :: Rect Int32
+    -- ^ Dimensions of the line box (CSS), containing all fragments on a given
+    -- line, and matching the width of the whole paragraph.
+    }
+    deriving (Eq, Read, Show)
+
+-- | Add @dx@ and @dy@ to the line's `x_origin` and `y_origin`,
+-- respectively.
+shiftLine :: Int32 -> Int32 -> Line -> Line
+shiftLine dx dy l = l'
+    where
+        l' = l { lineRect = r' }
+        r' = r { x_origin = x_origin r + dx, y_origin = y_origin r + dy }
+        r = lineRect l
diff --git a/src/Data/Text/ParagraphLayout/Internal/LineHeight.hs b/src/Data/Text/ParagraphLayout/Internal/LineHeight.hs
--- a/src/Data/Text/ParagraphLayout/Internal/LineHeight.hs
+++ b/src/Data/Text/ParagraphLayout/Internal/LineHeight.hs
@@ -7,10 +7,15 @@
 data LineHeight
 
     = Normal
-    -- ^ Determine the preferred line height automatically using its ascent and
-    -- descent metrics.
+    -- ^ The amount of vertical space taken up by the text in the layout
+    -- will be exactly the distance between its font's ascender and descender
+    -- line, with no further adjustment.
 
     | Absolute Int32
-    -- ^ Set the preferred line height independently of the font.
+    -- ^ The amount of vertical space taken up by the text in the layout
+    -- will be exactly the provided value. If this value is different from
+    -- the distance between the font's ascender and descender line, the
+    -- difference will be split in two equal parts (within a rounding error)
+    -- and applied as /half-leading/ both above and below the glyphs.
 
     deriving (Eq, Read, Show)
diff --git a/src/Data/Text/ParagraphLayout/Internal/LinePagination.hs b/src/Data/Text/ParagraphLayout/Internal/LinePagination.hs
--- a/src/Data/Text/ParagraphLayout/Internal/LinePagination.hs
+++ b/src/Data/Text/ParagraphLayout/Internal/LinePagination.hs
@@ -12,7 +12,7 @@
 --   (Preceding context may limit the space available on the given page, but it
 --   is assumed that the space on every following page can be used in full.)
 module Data.Text.ParagraphLayout.Internal.LinePagination
-    ( Line
+    ( LineHeight
     , lineHeight
     , PageContinuity (Break, Continue)
     , bestSplit
@@ -30,13 +30,13 @@
 -- Lines are assumed to be tightly packed without overlaps,
 -- so that the vertical space taken up by multiple lines
 -- is equal to the sum of the height of each line.
-class Line a where
+class LineHeight a where
     lineHeight :: a -> Int32
 
--- | A trivial instance of `Line` that is just a height.
+-- | A trivial instance of `LineHeight` that is just a height.
 --
 -- For testing purposes.
-instance Line Int32 where
+instance LineHeight Int32 where
     lineHeight = id
 
 -- | Represents the best place to place a chunk of paginated content.
@@ -72,7 +72,7 @@
 --
 -- The third component of the output contains all remaining lines. If non-empty,
 -- these can be passed to this function again to produce more pages.
-paginateLines :: Line a
+paginateLines :: LineHeight a
     => Word
     -- ^ Minimum number of lines to keep before a page break ("orphans"),
     -- if possible.
@@ -136,7 +136,7 @@
 -- as possible while satisfying the given constraints.
 --
 -- This is a low-level function that makes no compromises.
-bestSplit :: Line a
+bestSplit :: LineHeight a
     => Word
     -- ^ Number of lines at the beginning ("orphans") to keep together.
     -> Word
@@ -156,7 +156,7 @@
 -- not exceed @h@, the first @o@ lines ("orphans") are kept together,
 -- and the last @w@ lines ("widows") are kept together.
 constrainedSplits
-    :: Line a => Word -> Word -> Int32 -> [a] -> NonEmpty ([a], [a])
+    :: LineHeight a => Word -> Word -> Int32 -> [a] -> NonEmpty ([a], [a])
 constrainedSplits o w h ls = zeroSplit :| dropWhileEnd violating splits
     where
         zeroSplit :| splits = fittingSplits h ls
@@ -168,7 +168,7 @@
 -- | Split a list of lines in every possible way, from shortest prefix
 -- to longest, as long as the total of line heights in the prefix does
 -- not exceed @h@.
-fittingSplits :: Line a => Int32 -> [a] -> NonEmpty ([a], [a])
+fittingSplits :: LineHeight a => Int32 -> [a] -> NonEmpty ([a], [a])
 fittingSplits h ls = fmap snd $ zeroSplit :| takeWhile fitting splits
     where
         zeroSplit :| splits = splitsWithTotal ls
@@ -176,7 +176,7 @@
 
 -- | Split a list of lines in every possible way, from shortest prefix
 -- to longest, and keep a running total of line heights in the prefix.
-splitsWithTotal :: Line a => [a] -> NonEmpty (Int32, ([a], [a]))
+splitsWithTotal :: LineHeight a => [a] -> NonEmpty (Int32, ([a], [a]))
 splitsWithTotal ls = zeroSplit :| splits
     where
         zeroSplit = (zeroTotal, (zeroClosed, ls))
@@ -184,7 +184,7 @@
         zeroClosed = []
         zeroTotal = 0
 
-splitsWithTotal' :: Line a => Int32 -> [a] -> [a] -> [(Int32, ([a], [a]))]
+splitsWithTotal' :: LineHeight a => Int32 -> [a] -> [a] -> [(Int32, ([a], [a]))]
 splitsWithTotal' _ _ [] = []
 splitsWithTotal' total closed (x : xs) = split : splits
     where
diff --git a/src/Data/Text/ParagraphLayout/Internal/Paginable.hs b/src/Data/Text/ParagraphLayout/Internal/Paginable.hs
--- a/src/Data/Text/ParagraphLayout/Internal/Paginable.hs
+++ b/src/Data/Text/ParagraphLayout/Internal/Paginable.hs
@@ -67,7 +67,7 @@
     paginate :: PageOptions -> pl -> (PageContinuity, pl, Maybe pl)
 
 -- | Internal implementation of paginating a simple list of generic lines.
-instance Line a => Paginable [a] where
+instance LineHeight a => Paginable [a] where
     paginate opts ls = case paginateLines o w h1 h2 ls of
         (c, p, []) -> (c, p, Nothing)
         (c, p, rest) -> (c, p, Just rest)
@@ -87,7 +87,7 @@
 instance Paginable (Rich.ParagraphLayout d) where
     paginate = paginateLayout
 
-paginateLayout :: (Line a, LineNumbers a, GenericLayout a) =>
+paginateLayout :: (LineHeight a, LineNumbers a, GenericLayout a) =>
    PageOptions -> a -> (PageContinuity, a, Maybe a)
 paginateLayout opts pl =
     case paginate opts (cutLines pl) of
diff --git a/src/Data/Text/ParagraphLayout/Internal/ParagraphLine.hs b/src/Data/Text/ParagraphLayout/Internal/ParagraphLine.hs
--- a/src/Data/Text/ParagraphLayout/Internal/ParagraphLine.hs
+++ b/src/Data/Text/ParagraphLayout/Internal/ParagraphLine.hs
@@ -34,13 +34,12 @@
     -- | Keep only fragments with the given line number.
     limitFragments :: Int -> pl -> pl
 
-    -- | Add @dx@ and @dy@ to each fragment's `x_origin` and `y_origin`,
-    -- respectively.
-    shiftFragments :: Int32 -> Int32 -> pl -> pl
+    -- | Shift all contents of the paragraph by @dx, dy@.
+    shiftContents :: Int32 -> Int32 -> pl -> pl
 
-    -- | Combine fragments from two layouts into one,
+    -- | Combine contents from two layouts into one,
     -- without any adjustment of coordinates.
-    appendFragments :: pl -> pl -> pl
+    appendContents :: pl -> pl -> pl
 
 instance GenericLayout (P.ParagraphLayout d) where
     empty = P.emptyParagraphLayout
@@ -48,17 +47,17 @@
     topDistance pl = topFragmentOrigin $ P.paragraphFragments pl
     leftDistance pl = leftmostFragmentOrigin $ P.paragraphFragments pl
     limitFragments n = P.filterFragments (fragmentIsOnLine n)
-    shiftFragments dx dy = P.mapFragments (shiftFragment dx dy)
-    appendFragments = P.appendFragments
+    shiftContents dx dy = P.mapFragments (shiftFragment dx dy)
+    appendContents = P.appendFragments
 
 instance GenericLayout (R.ParagraphLayout d) where
     empty = R.emptyParagraphLayout
     rect = R.paragraphRect
-    topDistance pl = topFragmentOrigin $ R.paragraphFragments pl
+    topDistance = R.topDistance
     leftDistance pl = leftmostFragmentOrigin $ R.paragraphFragments pl
-    limitFragments n = R.filterFragments (fragmentIsOnLine n)
-    shiftFragments dx dy = R.mapFragments (shiftFragment dx dy)
-    appendFragments = R.appendFragments
+    limitFragments n = R.filterLine n
+    shiftContents dx dy = R.shiftContents dx dy
+    appendContents = R.appendContents
 
 -- | Split the given paragraph layout into single-line layouts.
 cutLines :: (GenericLayout pl, LineNumbers pl) => pl -> [pl]
@@ -70,11 +69,11 @@
 
 -- | Add a constant to each fragment's `y_origin` so that their maximum is zero.
 trimTop :: GenericLayout pl => pl -> pl
-trimTop pl = shiftFragments 0 (-topDistance pl) pl
+trimTop pl = shiftContents 0 (-topDistance pl) pl
 
 -- | Add a constant to each fragment's `x_origin` so that their minimum is zero.
 trimLeft :: GenericLayout pl => pl -> pl
-trimLeft pl = shiftFragments (-leftDistance pl) 0 pl
+trimLeft pl = shiftContents (-leftDistance pl) 0 pl
 
 topFragmentOrigin :: [Fragment d] -> Int32
 topFragmentOrigin frags = maximum $ map (y_origin . fragmentRect) frags
@@ -91,7 +90,7 @@
 mergeLine pl nextLine = pl'
     where
         -- Quadratic time complexity. TODO: Consider optimising.
-        pl' = appendFragments pl $ shiftFragments 0 y nextLine
+        pl' = appendContents pl $ shiftContents 0 y nextLine
         y = y_terminus $ rect pl
 
 fragmentIsOnLine :: Int -> Fragment d -> Bool
diff --git a/src/Data/Text/ParagraphLayout/Internal/Plain/ParagraphLayout.hs b/src/Data/Text/ParagraphLayout/Internal/Plain/ParagraphLayout.hs
--- a/src/Data/Text/ParagraphLayout/Internal/Plain/ParagraphLayout.hs
+++ b/src/Data/Text/ParagraphLayout/Internal/Plain/ParagraphLayout.hs
@@ -30,7 +30,7 @@
 instance LineNumbers (ParagraphLayout d) where
     lineNumbersWithDuplication pl = map fragmentLine $ paragraphFragments pl
 
-instance Line (ParagraphLayout d) where
+instance LineHeight (ParagraphLayout d) where
     lineHeight pl = height $ paragraphRect pl
 
 -- | Wrap the given `SpanLayout`s and compute their containing rectangle.
diff --git a/src/Data/Text/ParagraphLayout/Internal/ProtoFragment.hs b/src/Data/Text/ParagraphLayout/Internal/ProtoFragment.hs
--- a/src/Data/Text/ParagraphLayout/Internal/ProtoFragment.hs
+++ b/src/Data/Text/ParagraphLayout/Internal/ProtoFragment.hs
@@ -1,6 +1,7 @@
 module Data.Text.ParagraphLayout.Internal.ProtoFragment
-    ( ProtoFragment (direction, advance, glyphs, hardBreak)
+    ( ProtoFragment (direction, verticalOffsets, advance, glyphs, hardBreak)
     , protoFragmentH
+    , mapVerticalOffsets
     )
 where
 
@@ -8,6 +9,7 @@
 import Data.Text.Glyphize (Direction (..), GlyphInfo, GlyphPos (x_advance))
 
 import qualified Data.Text.ParagraphLayout.Internal.BiDiLevels as BiDi
+import qualified Data.Text.ParagraphLayout.Internal.VerticalOffsets as VO
 
 -- | A box fragment which has not been positioned yet.
 data ProtoFragment = ProtoFragment
@@ -16,6 +18,8 @@
     , level :: BiDi.Level
     -- ^ BiDi embedding level.
     -- Should be even for LTR fragments and odd for RTL fragments.
+    , verticalOffsets :: VO.VerticalOffsets
+    -- ^ Vertical offsets used for aligning the fragment within its line.
     , advance :: Int32
     -- ^ Total advance of glyphs in this fragment,
     -- depending on the text direction.
@@ -26,11 +30,24 @@
 
 -- | Construct a `ProtoFragment`, automatically calculating the total advance
 -- for a horizontal text direction.
-protoFragmentH :: Direction -> BiDi.Level -> [(GlyphInfo, GlyphPos)] -> Bool ->
-    ProtoFragment
-protoFragmentH dir lvl gs hard = ProtoFragment dir lvl adv gs hard
+protoFragmentH
+    :: Direction
+    -> BiDi.Level
+    -> VO.VerticalOffsets
+    -> [(GlyphInfo, GlyphPos)]
+    -> Bool
+    -> ProtoFragment
+protoFragmentH dir lvl vo gs hard = ProtoFragment dir lvl vo adv gs hard
     where
         adv = sum $ map (x_advance . snd) gs
+
+-- | Apply the given function to the `verticalOffsets` in the given fragment.
+mapVerticalOffsets
+    :: (VO.VerticalOffsets -> VO.VerticalOffsets)
+    -> ProtoFragment
+    -> ProtoFragment
+mapVerticalOffsets mapFunc pf =
+    pf { verticalOffsets = mapFunc $ verticalOffsets pf }
 
 instance BiDi.WithLevel ProtoFragment where
     level = level -- BiDi.level = ProtoFragment.level
diff --git a/src/Data/Text/ParagraphLayout/Internal/ProtoLine.hs b/src/Data/Text/ParagraphLayout/Internal/ProtoLine.hs
--- a/src/Data/Text/ParagraphLayout/Internal/ProtoLine.hs
+++ b/src/Data/Text/ParagraphLayout/Internal/ProtoLine.hs
@@ -4,6 +4,7 @@
     , visible
     , width
     , applyBoxes
+    , mapFragments
     )
 where
 
@@ -93,3 +94,17 @@
 -- | Boxes that end on the given line.
 boxesEnd :: (Foldable f, Functor f) => ProtoLine f d -> [ResolvedBox d]
 boxesEnd pl = allBoxes (protoFragments pl) `diff` nextOpenBoxes pl
+
+-- | Apply a function to every fragment on the line.
+--
+-- Note that `ResolvedSpan` cannot be changed in this manner and is
+-- only provided on the input of the mapping function.
+mapFragments
+    :: Functor f
+    => (ResolvedSpan d -> ProtoFragment -> ProtoFragment)
+    -> ProtoLine f d
+    -> ProtoLine f d
+mapFragments mapFunc pl =
+    pl { protoFragments = fmap mapFunc' $ protoFragments pl }
+    where
+        mapFunc' (WithSpan rs pf) = WithSpan rs $ mapFunc rs pf
diff --git a/src/Data/Text/ParagraphLayout/Internal/ResolvedBox.hs b/src/Data/Text/ParagraphLayout/Internal/ResolvedBox.hs
--- a/src/Data/Text/ParagraphLayout/Internal/ResolvedBox.hs
+++ b/src/Data/Text/ParagraphLayout/Internal/ResolvedBox.hs
@@ -13,12 +13,14 @@
 import Data.Text.Glyphize (Direction (DirLTR, DirRTL))
 
 import Data.Text.ParagraphLayout.Internal.BoxOptions
+import Data.Text.ParagraphLayout.Internal.TextOptions
 
 -- | Internal structure describing an inline box.
 -- May be shared by multiple fragments.
 data ResolvedBox d = ResolvedBox
     { boxUserData :: d
     , boxIndex :: Int
+    , boxParentTextOptions :: TextOptions
     , boxOptions :: BoxOptions
     , boxDirection :: Direction
     }
diff --git a/src/Data/Text/ParagraphLayout/Internal/Rich.hs b/src/Data/Text/ParagraphLayout/Internal/Rich.hs
--- a/src/Data/Text/ParagraphLayout/Internal/Rich.hs
+++ b/src/Data/Text/ParagraphLayout/Internal/Rich.hs
@@ -12,7 +12,10 @@
 import Data.Text.ParagraphLayout.Internal.Break
 import Data.Text.ParagraphLayout.Internal.Fragment
 import Data.Text.ParagraphLayout.Internal.Layout
+import Data.Text.ParagraphLayout.Internal.Line
+import Data.Text.ParagraphLayout.Internal.ParagraphExtents
 import Data.Text.ParagraphLayout.Internal.ParagraphOptions
+import Data.Text.ParagraphLayout.Internal.Rect
 import qualified Data.Text.ParagraphLayout.Internal.ResolvedSpan as RS
 import Data.Text.ParagraphLayout.Internal.Rich.Paragraph
 import Data.Text.ParagraphLayout.Internal.Rich.ParagraphLayout
@@ -23,15 +26,24 @@
 
 -- | Lay out a rich text paragraph.
 layoutRich :: Paragraph d -> ParagraphLayout d
-layoutRich p = paragraphLayout $ map unwrap frags
+layoutRich p = ParagraphLayout pRect stretchedLines unwrappedFrags
     where
         Paragraph _ _ root opts = p
         RootBox (Box _ rootTextOpts) = root
+        pRect = containRects $ map lineRect stretchedLines
+        stretchedLines = map stretchLine ls
+        stretchLine l = l { lineRect = stretchRect (lineRect l) }
+        stretchRect r = r
+            { x_origin = x_origin containingRect
+            , x_size = x_size containingRect
+            }
+        containingRect = containRects $ map fragmentSpacedRect unwrappedFrags
+        unwrappedFrags = map unwrap frags
         unwrap (WithSpan rs frag) =
             frag { fragmentUserData = RS.spanUserData rs }
-        frags = case nonEmpty wrappedRuns of
+        (frags, ls) = case nonEmpty wrappedRuns of
             Just xs -> layoutAndAlignLines dir align maxWidth xs
-            Nothing -> []
+            Nothing -> ([], [])
         wrappedRuns = spansToRunsWrapped spans
         -- TODO: To support @unicode-bidi: plaintext@ as in CSS, allow ignoring
         --       the text direction of the root box, and instead use the BiDi
diff --git a/src/Data/Text/ParagraphLayout/Internal/Rich/ParagraphLayout.hs b/src/Data/Text/ParagraphLayout/Internal/Rich/ParagraphLayout.hs
--- a/src/Data/Text/ParagraphLayout/Internal/Rich/ParagraphLayout.hs
+++ b/src/Data/Text/ParagraphLayout/Internal/Rich/ParagraphLayout.hs
@@ -1,20 +1,21 @@
 module Data.Text.ParagraphLayout.Internal.Rich.ParagraphLayout
     ( ParagraphLayout (..)
-    , appendFragments
+    , appendContents
     , emptyParagraphLayout
-    , filterFragments
-    , mapFragments
-    , paragraphLayout
+    , filterLine
     , paragraphOriginX
     , paragraphOriginY
     , paragraphSafeWidth
     , shapedRuns
+    , shiftContents
+    , topDistance
     )
 where
 
 import Data.Int (Int32)
 
 import Data.Text.ParagraphLayout.Internal.Fragment
+import Data.Text.ParagraphLayout.Internal.Line
 import Data.Text.ParagraphLayout.Internal.LineNumbers
 import Data.Text.ParagraphLayout.Internal.LinePagination
 import Data.Text.ParagraphLayout.Internal.ParagraphExtents
@@ -24,6 +25,9 @@
 data ParagraphLayout d = ParagraphLayout
     { paragraphRect :: Rect Int32
     -- ^ The containing block (CSS3).
+    , paragraphLines :: [Line]
+    -- ^ Information about line boxes (CSS).
+    -- May describe additional empty space around text fragments.
     , paragraphFragments :: [Fragment d]
     -- ^ The resulting layout of all input text, divided into fragments as
     -- required by the input structure, line breaking, text writing direction,
@@ -34,41 +38,48 @@
 instance LineNumbers (ParagraphLayout d) where
     lineNumbersWithDuplication pl = map fragmentLine $ paragraphFragments pl
 
-instance Line (ParagraphLayout d) where
+instance LineHeight (ParagraphLayout d) where
     lineHeight pl = height $ paragraphRect pl
 
--- | Wrap the given `Fragment`s and compute their containing rectangle.
-paragraphLayout :: [Fragment d] -> ParagraphLayout d
-paragraphLayout frags = ParagraphLayout pRect frags
-    where pRect = containRects $ map fragmentSpacedRect frags
-
--- | A `ParagraphLayout` with no fragments.
--- Useful as an identity element for `appendFragments`.
+-- | A `ParagraphLayout` with no fragments and no lines.
+-- Useful as an identity element for `appendContents`.
 emptyParagraphLayout :: ParagraphLayout a
-emptyParagraphLayout = ParagraphLayout emptyRect []
+emptyParagraphLayout = ParagraphLayout emptyRect [] []
 
--- | Remove fragments that do not match the given predicate.
---
--- The containing rectangle will be recalculated.
-filterFragments :: (Fragment d -> Bool) -> ParagraphLayout d ->
-    ParagraphLayout d
-filterFragments predicate (ParagraphLayout _ frags) =
-    paragraphLayout $ filter predicate frags
+-- | Distance from the paragraph origin to its topmost line.
+topDistance :: ParagraphLayout d -> Int32
+topDistance pl = case paragraphLines pl of
+    [] -> 0
+    ls -> maximum $ map (y_origin . lineRect) ls
 
--- | Run a mapping function over each fragment inside a `ParagraphLayout`.
---
--- The containing rectangle will be recalculated.
-mapFragments :: (Fragment d -> Fragment d) -> ParagraphLayout d ->
-    ParagraphLayout d
-mapFragments mapFunc (ParagraphLayout _ frags) =
-    paragraphLayout $ map mapFunc frags
+-- | Keep the line with the given number and its fragments,
+-- and remove everything else.
+filterLine :: Int -> ParagraphLayout d -> ParagraphLayout d
+filterLine num (ParagraphLayout _ ls frags) =
+    ParagraphLayout pRect' ls' frags'
+    where
+        pRect' = containRects $ map lineRect ls
+        ls' = filter ((== num) . lineNumber) ls
+        frags' = filter ((== num) . fragmentLine) frags
 
+-- | Add @dx@ and @dy@ to the origins of each line and fragment,
+-- effectively shifting the whole paragraph by the given amount.
+shiftContents :: Int32 -> Int32 -> ParagraphLayout d -> ParagraphLayout d
+shiftContents dx dy (ParagraphLayout _ ls frags) =
+    ParagraphLayout pRect' ls' frags'
+    where
+        pRect' = containRects $ map lineRect ls
+        ls' = map (shiftLine dx dy) ls
+        frags' = map (shiftFragment dx dy) frags
+
 -- | Combine fragments from two `ParagraphLayout`s.
---
--- The containing rectangle will be recalculated.
-appendFragments :: ParagraphLayout d -> ParagraphLayout d -> ParagraphLayout d
-appendFragments (ParagraphLayout _ a) (ParagraphLayout _ b) =
-    paragraphLayout $ a ++ b
+appendContents :: ParagraphLayout d -> ParagraphLayout d -> ParagraphLayout d
+appendContents (ParagraphLayout _ ls1 frags1) (ParagraphLayout _ ls2 frags2) =
+    ParagraphLayout pRect ls frags
+    where
+        pRect = containRects $ map lineRect ls
+        ls = ls1 ++ ls2
+        frags = frags1 ++ frags2
 
 -- | Return all shaped runs in the paragraph.
 shapedRuns :: ParagraphLayout d -> [ShapedRun]
diff --git a/src/Data/Text/ParagraphLayout/Internal/TextOptions.hs b/src/Data/Text/ParagraphLayout/Internal/TextOptions.hs
--- a/src/Data/Text/ParagraphLayout/Internal/TextOptions.hs
+++ b/src/Data/Text/ParagraphLayout/Internal/TextOptions.hs
@@ -4,6 +4,7 @@
     )
 where
 
+import Data.Int (Int32)
 import Data.Text.Glyphize (Direction, Font, emptyFont)
 
 import Data.Text.ParagraphLayout.Internal.LineHeight
@@ -20,6 +21,29 @@
     -- Make sure to set its scale (see `Data.Text.Glyphize.optionScale`) using
     -- the same units that you want in the output.
 
+    , textAscender :: Maybe Int32
+    -- ^ How much to add to the text's baseline coordinate to reach its
+    -- ascender line. This is usually a positive value.
+    --
+    -- If set to `Nothing`, the font's own `Data.Text.Glyphize.ascender`
+    -- metric will be used.
+    --
+    -- Setting an explicit value with @`Just` x@ is intended as an override
+    -- for situations where the text is intended to be replaced by an object
+    -- with differently calculated dimensions.
+
+    , textDescender :: Maybe Int32
+    -- ^ How much to add to the text's baseline coordinate to reach its
+    -- descender line. Note that this is usually a negative value because
+    -- the descender is usually below the baseline.
+    --
+    -- If set to `Nothing`, the font's own `Data.Text.Glyphize.descender`
+    -- metric will be used.
+    --
+    -- Setting an explicit value with @`Just` x@ is intended as an override
+    -- for situations where the text is intended to be replaced by an object
+    -- with differently calculated dimensions.
+
     , textLineHeight :: LineHeight
     -- ^ Preferred line height of the resulting fragments.
 
@@ -55,6 +79,8 @@
     -> TextOptions
 defaultTextOptions dir = TextOptions
     { textFont = emptyFont
+    , textAscender = Nothing
+    , textDescender = Nothing
     , textLineHeight = Normal
     , textLanguage = ""
     , textDirection = dir
diff --git a/src/Data/Text/ParagraphLayout/Internal/Tree.hs b/src/Data/Text/ParagraphLayout/Internal/Tree.hs
--- a/src/Data/Text/ParagraphLayout/Internal/Tree.hs
+++ b/src/Data/Text/ParagraphLayout/Internal/Tree.hs
@@ -102,7 +102,7 @@
     -- ^ Inline boxes found on the path from this text sequence to the root
     -- of the original tree.
 
--- | Data types that can represent an empty text sequence in a `Tree`.
+-- | Data types that can represent an empty text sequence in a tree.
 class EmptyText t where
     empty :: t
 
@@ -142,9 +142,10 @@
     (Int, [Leaf t d])
 flattenNode idx path textOpts (TextSequence d t) =
     (idx, [TextLeaf d t textOpts path])
-flattenNode idx path _ (InlineBox d (Box ns textOpts) boxOpts) =
-    flattenNodes (idx + 1) (ResolvedBox d idx boxOpts dir : path) textOpts ns
+flattenNode idx path parentTextOpts (InlineBox d (Box ns textOpts) boxOpts) =
+    flattenNodes (idx + 1) box textOpts ns
     where
+        box = ResolvedBox d idx parentTextOpts boxOpts dir : path
         dir = textDirection textOpts
 
 -- | Concatenate all pieces of text from a `Text` tree, plus an optional prefix
diff --git a/src/Data/Text/ParagraphLayout/Internal/VerticalOffsets.hs b/src/Data/Text/ParagraphLayout/Internal/VerticalOffsets.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Text/ParagraphLayout/Internal/VerticalOffsets.hs
@@ -0,0 +1,148 @@
+module Data.Text.ParagraphLayout.Internal.VerticalOffsets
+    ( VerticalOffsets (..)
+    , alignBaseline
+    , fromText
+    , strutted
+    , underBox
+    , underRoot
+    )
+where
+
+import Data.Int (Int32)
+import Data.List.NonEmpty (NonEmpty ((:|)), (<|))
+import Data.Maybe (fromMaybe)
+import Data.Text.Glyphize (ascender, descender, fontExtentsForDir)
+
+import Data.Text.ParagraphLayout.Internal.BoxOptions
+import Data.Text.ParagraphLayout.Internal.LineHeight
+import Data.Text.ParagraphLayout.Internal.ResolvedBox
+import Data.Text.ParagraphLayout.Internal.TextOptions
+
+-- | Metrics used for vertical alignment of text fragments.
+data VerticalOffsets = VerticalOffsets
+
+    { layoutTop :: Int32
+    -- ^ Y coordinate of the top edge of the fragment,
+    -- including half-leading.
+
+    , fontTop :: Int32
+    -- ^ Y coordinate of the font's ascender.
+
+    , baseline :: Int32
+    -- ^ Y coordinate of the font's baseline.
+
+    , fontBottom :: Int32
+    -- ^ Y coordinate of the font's descender.
+
+    , layoutBottom :: Int32
+    -- ^ Y coordinate of the bottom edge of the fragment,
+    -- including half-leading.
+
+    }
+    deriving (Eq, Show)
+
+-- | Add a constant to each of the coordinates, effectively moving them
+-- up by the given amount while preserving distances between them.
+shift :: Int32 -> VerticalOffsets -> VerticalOffsets
+shift d vo = vo
+    { layoutTop = layoutTop vo + d
+    , fontTop = fontTop vo + d
+    , baseline = baseline vo + d
+    , fontBottom = fontBottom vo + d
+    , layoutBottom = layoutBottom vo + d
+    }
+
+-- | Set `baseline` to the given value and update all other coordinates
+-- so that distances are preserved.
+alignBaseline :: Int32 -> VerticalOffsets -> VerticalOffsets
+alignBaseline x vo = shift (x - baseline vo) vo
+
+-- | Metrics calculated for a single text box, as if it existed alone
+-- with its baseline at @0@.
+fromText :: TextOptions -> VerticalOffsets
+fromText opts = VerticalOffsets
+    { layoutTop = ascent + topHalfLeading
+    , fontTop = ascent
+    , baseline = 0
+    , fontBottom = - descent
+    , layoutBottom = - descent - bottomHalfLeading
+    }
+    where
+        -- non-negative leading values iff `lineHeight` > `normalLineHeight`
+        leading = lineHeight - normalLineHeight
+        topHalfLeading = -((-leading) `div` 2)
+        bottomHalfLeading = leading `div` 2
+        -- `normalLineHeight` > 0 for horizontal fonts
+        normalLineHeight = ascent + descent
+        -- `ascent` >= 0 for horizontal fonts
+        ascent = ascender extents `fromMaybe` textAscender opts
+        -- `descent` >= 0 for horizontal fonts
+        descent = - (descender extents `fromMaybe` textDescender opts)
+        extents = fontExtentsForDir (textFont opts) (Just dir)
+        -- Actual shaped text direction may differ from the direction set in
+        -- `TextOptions` (for example RTL characters in a LTR box), but
+        -- HarfBuzz only distinguished horizontal and vertical extents,
+        -- so this should make no difference.
+        dir = textDirection opts
+        lineHeight = case textLineHeight opts of
+            Normal -> normalLineHeight
+            Absolute h -> h
+
+-- | Metrics for a nested text fragment, with a defined relation either to
+-- the root box or to a box with line-relative alignment.
+type NestedVerticalOffsets d = (Maybe (ResolvedBox d), VerticalOffsets)
+
+-- | Test whether the given `NestedVerticalOffsets` are defined relative to
+-- the root box.
+underRoot :: NestedVerticalOffsets d -> Bool
+underRoot (Nothing, _) = True
+underRoot (Just _, _) = False
+
+-- | Test whether the given `NestedVerticalOffsets` are defined relative to
+-- the given box.
+--
+-- (Note that boxes are compared internally using `boxIndex`, and should
+-- therefore only be compared with boxes created from the same input.)
+underBox :: ResolvedBox d -> NestedVerticalOffsets d -> Bool
+underBox _ (Nothing, _) = False
+underBox b (Just x, _) = b == x
+
+-- | Metrics calculated for a text box nested within zero or more boxes.
+--
+-- Vertical offsets will be recursively adjusted using the ancestor boxes'
+-- properties, stopping once a box with line-relative alignment is reached,
+-- if there is one.
+--
+-- If recursion ends at the root, this function returns @(`Nothing`, vo)@,
+-- where @vo@ is calculated such that the root baseline is at @0@.
+--
+-- If recursion ends at a box with line-relative alignment, this function
+-- returns @(`Just` b, vo)@, where @b@ is the box where recursion stopped
+-- (root of the /aligned subtree/ in CSS terminology), and @vo@ is calculated
+-- such that the baseline of @b@ is at @0@.
+--
+-- Note: The font extents are calculated using the same direction for the whole
+--       ancestry path regardless of the actual direction of these boxes, but
+--       this should not matter for text that is only horizontal.
+fromNestedText :: TextOptions -> [ResolvedBox d] -> NestedVerticalOffsets d
+fromNestedText opts boxes = case boxes of
+    [] -> -- Inline content directly in the root box.
+        (Nothing, vo)
+    (b : bs) -> case boxVerticalAlignment $ boxOptions b of
+        AlignLineTop -> (Just b, vo)
+        AlignLineBottom -> (Just b, vo)
+        AlignBaseline offset ->
+            let parentOpts = boxParentTextOptions b
+                (anchor, parentVO) = fromNestedText parentOpts bs
+            in (anchor, alignBaseline (baseline parentVO + offset) vo)
+    where
+        vo = fromText opts
+
+-- | Metrics calculated for a text box nested within zero or more boxes,
+-- plus metrics for each of its ancestor boxes, which can be used as struts
+-- on lines where these boxes do not directly contain any text.
+strutted :: TextOptions -> [ResolvedBox d] -> NonEmpty (NestedVerticalOffsets d)
+strutted opts [] =
+    fromNestedText opts [] :| []
+strutted opts boxes@(b : bs) =
+    fromNestedText opts boxes <| strutted (boxParentTextOptions b) bs
diff --git a/test/Data/Text/ParagraphLayout/Internal/ApplyBoxesSpec.hs b/test/Data/Text/ParagraphLayout/Internal/ApplyBoxesSpec.hs
--- a/test/Data/Text/ParagraphLayout/Internal/ApplyBoxesSpec.hs
+++ b/test/Data/Text/ParagraphLayout/Internal/ApplyBoxesSpec.hs
@@ -14,7 +14,8 @@
 import Data.Text.ParagraphLayout.Internal.WithSpan
 
 trivialBox :: d -> Int -> Direction -> ResolvedBox d
-trivialBox d i dir = ResolvedBox d i defaultBoxOptions dir
+trivialBox d i dir =
+    ResolvedBox d i (defaultTextOptions dir) defaultBoxOptions dir
 
 trivialSpan :: d -> Int -> Direction -> [ResolvedBox d] -> ResolvedSpan d
 trivialSpan d i dir bs = ResolvedSpan
diff --git a/test/Data/Text/ParagraphLayout/Internal/RunSpec.hs b/test/Data/Text/ParagraphLayout/Internal/RunSpec.hs
--- a/test/Data/Text/ParagraphLayout/Internal/RunSpec.hs
+++ b/test/Data/Text/ParagraphLayout/Internal/RunSpec.hs
@@ -15,7 +15,8 @@
 import Data.Text.ParagraphLayout.TextData
 
 defaultBox :: Direction -> ResolvedBox ()
-defaultBox dir = ResolvedBox () 0 defaultBoxOptions dir
+defaultBox dir =
+    ResolvedBox () 0 (defaultTextOptions dir) defaultBoxOptions dir
 
 sampleSpan :: (Direction, String, Text, a) -> TextLevels -> ResolvedSpan ()
 sampleSpan (dir, lang, text, _) levels = ResolvedSpan
diff --git a/test/Data/Text/ParagraphLayout/PrettyShow.hs b/test/Data/Text/ParagraphLayout/PrettyShow.hs
--- a/test/Data/Text/ParagraphLayout/PrettyShow.hs
+++ b/test/Data/Text/ParagraphLayout/PrettyShow.hs
@@ -147,12 +147,17 @@
         ]
 
 instance Show d => PrettyShow (Rich.ParagraphLayout d) where
-    prettyShow (Rich.ParagraphLayout pr frags) = concat
+    prettyShow (Rich.ParagraphLayout pr ls frags) = concat
         [ "ParagraphLayout"
         , newline
         , indent1
         , "{ paragraphRect = "
         , show pr
+        , newline
+        , indent1
+        , ", paragraphLines ="
+        , newline
+        , concat $ commaFirstList indent2 $ map show ls
         , newline
         , indent1
         , ", paragraphFragments ="
diff --git a/test/Data/Text/ParagraphLayout/Rich/ParagraphData.hs b/test/Data/Text/ParagraphLayout/Rich/ParagraphData.hs
--- a/test/Data/Text/ParagraphLayout/Rich/ParagraphData.hs
+++ b/test/Data/Text/ParagraphLayout/Rich/ParagraphData.hs
@@ -9,12 +9,16 @@
     , mixedLineHeightParagraph
     , mixedScriptParagraph
     , mixedSizesParagraph
+    , mixedVerticalAlignmentParagraph
     , nestedBoxesParagraph
     , neutralDirectionParagraph
     , newline1Paragraph
     , newline1TextParagraph
     , newline2Paragraph
     , newline2TextParagraph
+    , offsetMiddleInnerTextParagraph
+    , offsetMiddleOuterTextParagraph
+    , offsetTextlessBoxParagraph
     , softBreakParagraph
     , spaceBoxParagraph
     )
@@ -171,36 +175,40 @@
         t = (defaultTextOptions dir) { textFont = font, textLanguage = lang }
         (_, lang, textContents, _) = mixedDirectionSimple dir
 
-mixedLineHeightParagraph :: (Int32, Int32, Int32) -> Font -> ParagraphOptions ->
-    Paragraph String
-mixedLineHeightParagraph (lhSmall, lhMedium, lhLarge) font = constructParagraph
+mixedLineHeightParagraph
+    :: (Int32, Int32, Int32)
+    -> VerticalAlignment
+    -> Font
+    -> ParagraphOptions
+    -> Paragraph String
+mixedLineHeightParagraph lhs va font = constructParagraph
     (pack "prefix")
     (rootBox tMedium
         -- Line 1: all 3 heights, with medium height prevailing.
         [ text "mediumText" "medium "
-        , box "smallBox" b_ tSmall [text "smallText" "small "]
+        , box "smallBox" b tSmall [text "smallText" "small "]
         , text "mediumText" "medium "
-        , box "largeBox" b_ tLarge [text "largeText" "large "]
+        , box "largeBox" b tLarge [text "largeText" "large "]
         , text "mediumText" "medium "
         , text "lineBreak" "\n"
         -- Line 2: all 3 line heights, with medium only in the middle.
-        , box "smallBox" b_ tSmall [text "smallText" "small "]
+        , box "smallBox" b tSmall [text "smallText" "small "]
         , text "mediumText" "medium "
-        , box "largeBox" b_ tLarge [text "largeText" "large "]
+        , box "largeBox" b tLarge [text "largeText" "large "]
         , text "lineBreak" "\n"
         -- Line 3: asymmetric, medium changing into small.
         , text "mediumText" "medium "
-        , box "smallBox" b_ tSmall [text "smallText" "small "]
+        , box "smallBox" b tSmall [text "smallText" "small "]
         , text "lineBreak" "\n"
         -- Line 4: asymmetric, large changing into medium.
-        , box "largeBox" b_ tLarge [text "largeText" "large "]
+        , box "largeBox" b tLarge [text "largeText" "large "]
         , text "mediumText" "medium "
         , text "lineBreak" "\n"
         -- Line 5: small only.
-        , box "smallBox" b_ tSmall [text "smallText" "small "]
+        , box "smallBox" b tSmall [text "smallText" "small "]
         , text "lineBreak" "\n"
         -- Line 6: large only.
-        , box "largeBox" b_ tLarge [text "largeText" "large "]
+        , box "largeBox" b tLarge [text "largeText" "large "]
         ]
     )
     (pack "suffix")
@@ -208,7 +216,9 @@
         tLarge = t { textLineHeight = Absolute lhLarge }
         tMedium = t { textLineHeight = Absolute lhMedium }
         tSmall = t { textLineHeight = Absolute lhSmall }
+        (lhSmall, lhMedium, lhLarge) = lhs
         t = tLTR { textFont = font, textLanguage = "en" }
+        b = b_ { boxVerticalAlignment = va }
 
 mixedScriptParagraph :: Font -> ParagraphOptions -> Paragraph String
 mixedScriptParagraph font = constructParagraph
@@ -255,6 +265,80 @@
         tBig = tLTR { textFont = bigFont, textLanguage = "en" }
         tSmall = tLTR { textFont = smallFont, textLanguage = "en" }
 
+mixedVerticalAlignmentParagraph :: Font -> ParagraphOptions -> Paragraph String
+mixedVerticalAlignmentParagraph font = constructParagraph
+    (pack "prefix")
+    (rootBox t
+        -- Testing raised baselines.
+        [ text "base" "up "
+        , box "+9" (bRaise 9) t
+            [ text "base+9" "high "
+            , box "+6" (bRaise 6) t
+                [ text "base+9+6" "and "
+                , box "+2" (bRaise 2) t
+                    [ text "base+9+6+2" "higher "
+                    ]
+                ]
+            ]
+        -- Testing lowered baselines.
+        , text "base" "down "
+        , box "-9" (bLower 9) t
+            [ text "base-9" "low "
+            , box "-6" (bLower 6) t
+                [ text "base-9-6" "and "
+                , box "-2" (bLower 2) t
+                    [ text "base-9-6-2" "lower "
+                    ]
+                ]
+            ]
+        -- Line-aligned boxes should ignore their baseline-aligned parent.
+        --
+        -- Setting line height to zero should make approximately half
+        -- of the glyph (at the midpoint between ascender and descender)
+        -- overflow the line.
+        --
+        -- The parent should not affect layout unless it happens to be tall
+        -- enough to stretch the line.
+        , box "redundant" bBaseline (t { textLineHeight = Absolute 70 })
+            [ box "(h0)top" bTop (t { textLineHeight = Absolute 0 })
+                [ text "(h0)top" "X "
+                ]
+            , box "(h0)bottom" bBottom (t { textLineHeight = Absolute 0 })
+                [ text "(h0)bottom" "X "
+                ]
+            ]
+        -- Stretch the line more upwards than downwards, so that
+        -- top-aligned boxes will be placed higher than any other boxes.
+        , text "base" "stretching "
+        , box "(h72)+9" (bRaise 9) (t { textLineHeight = Absolute 72 })
+            [ text "(h72)base+9" "tall "
+            ]
+        -- Test line-top alignment with a subtree.
+        , box "top" bTop t
+            [ box "+12" (bRaise 12) t
+                [ text "top+12" "climax "
+                ]
+            , text "top" "preceding "
+            ]
+        -- Test line-bottom alignment, which should exclude other line-relative
+        -- aligned boxes from its subtree.
+        , box "bottom" bBottom t
+            [ box "top" bTop t
+                [ text "bottom+top" "the "
+                ]
+            , text "bottom" "crash "
+            ]
+        ]
+    )
+    (pack "suffix")
+    where
+        bTop = b_ { boxVerticalAlignment = AlignLineTop }
+        bRaise x = b_ { boxVerticalAlignment = AlignBaseline x }
+        bBaseline = b_ { boxVerticalAlignment = AlignBaseline 0 }
+        bLower x = b_ { boxVerticalAlignment = AlignBaseline (-x) }
+        bBottom = b_ { boxVerticalAlignment = AlignLineBottom }
+        t = tLTR { textFont = font, textLanguage = "en" }
+
 nestedBoxesParagraph :: Font -> ParagraphOptions -> Paragraph String
 nestedBoxesParagraph font = constructParagraph
     (pack "prefix")
@@ -314,6 +398,58 @@
     (pack "suffix")
     where
         t = tRTL { textFont = font, textLanguage = "zxx" }
+
+offsetMiddleInnerTextParagraph :: Int32 -> Font -> ParagraphOptions ->
+    Paragraph String
+offsetMiddleInnerTextParagraph offset font = constructParagraph
+    (pack "zero ")
+    (rootBox t
+        [ box "box" b t
+            [ text "inner" "three"
+            ]
+        ]
+    )
+    (pack " six")
+    where
+        b = b_ { boxVerticalAlignment = AlignBaseline offset }
+        t = tLTR { textFont = font, textLanguage = "en" }
+
+offsetMiddleOuterTextParagraph :: Int32 -> Font -> ParagraphOptions ->
+    Paragraph String
+offsetMiddleOuterTextParagraph offset font = constructParagraph
+    (pack "zero ")
+    (rootBox t
+        [ text "outer start" "one two "
+        , box "box" b t
+            -- API requires empty text to preserve the inner box.
+            [ text "inner" ""
+            ]
+        , text "outer end" " four five"
+        ]
+    )
+    (pack " six")
+    where
+        b = b_ { boxVerticalAlignment = AlignBaseline offset }
+        t = tLTR { textFont = font, textLanguage = "en" }
+
+offsetTextlessBoxParagraph :: Int32 -> Font -> ParagraphOptions ->
+    Paragraph String
+offsetTextlessBoxParagraph offset font = constructParagraph
+    (pack "prefix")
+    (rootBox t
+        [ text "outer" "out "
+        , box "textless box" b1 t
+            [ box "text box" b2 t
+                [ text "inner" "in"
+                ]
+            ]
+        ]
+    )
+    (pack "suffix")
+    where
+        b1 = b_ { boxVerticalAlignment = AlignBaseline offset }
+        b2 = b_ { boxVerticalAlignment = AlignLineBottom }
+        t = tLTR { textFont = font, textLanguage = "en" }
 
 softBreakParagraph :: Int32 -> Font -> ParagraphOptions -> Paragraph String
 softBreakParagraph spacing font = constructParagraph
diff --git a/test/Data/Text/ParagraphLayout/RichSpec.hs b/test/Data/Text/ParagraphLayout/RichSpec.hs
--- a/test/Data/Text/ParagraphLayout/RichSpec.hs
+++ b/test/Data/Text/ParagraphLayout/RichSpec.hs
@@ -109,7 +109,8 @@
                 let input w = loremIpsumParagraph font $
                         opts { paragraphMaxWidth = w }
                 let result20em = layoutRich $ input commonWrapWidth
-                let resultSafe = layoutRich $ input expectedSafeWidth
+                -- Adding + 1 to work around rounding errors.
+                let resultSafe = layoutRich $ input (expectedSafeWidth + 1)
                 let resultUnsafe = layoutRich $ input (expectedSafeWidth - 1)
                 let resultUnsafe2 = layoutRich $ input (expectedSafeWidth - 2)
 
@@ -129,16 +130,98 @@
                 it "does not wrap the same at 2 units smaller width" $
                     resultUnsafe2 `shouldNotBeWrappedLike` result20em
 
-            it "handles mixed line height" $ do
+            describe "mixed line height" $ do
                 let opts = defaultParagraphOptions
                         { paragraphAlignment = AlignStart
                         , paragraphMaxWidth = largeWidth
                         }
                 let lineHeights = (800, 1300, 1700)
-                let input = mixedLineHeightParagraph lineHeights font opts
-                let result = layoutRich input
-                result `shouldBeGolden` "mixedLineHeight"
 
+                it "aligns to top of line" $ do
+                    let input = mixedLineHeightParagraph
+                            lineHeights
+                            AlignLineTop
+                            font
+                            opts
+                    let result = layoutRich input
+                    result `shouldBeGolden` "mixedLineHeightTop"
+
+                it "aligns to bottom of line" $ do
+                    let input = mixedLineHeightParagraph
+                            lineHeights
+                            AlignLineBottom
+                            font
+                            opts
+                    let result = layoutRich input
+                    result `shouldBeGolden` "mixedLineHeightBottom"
+
+                it "aligns to baseline" $ do
+                    let input = mixedLineHeightParagraph
+                            lineHeights
+                            (AlignBaseline 0)
+                            font
+                            opts
+                    let result = layoutRich input
+                    result `shouldBeGolden` "mixedLineHeightBaseline"
+
+                it "aligns to baseline plus 3 units" $ do
+                    let input = mixedLineHeightParagraph
+                            lineHeights
+                            (AlignBaseline 3)
+                            font
+                            opts
+                    let result = layoutRich input
+                    result `shouldBeGolden` "mixedLineHeightBaseline3"
+
+            describe "offset middle baseline" $ do
+                let opts = defaultParagraphOptions
+                        { paragraphAlignment = AlignStart
+                        , paragraphMaxWidth = largeWidth
+                        }
+                let wrap = opts
+                        { paragraphMaxWidth = 3000
+                        }
+
+                it "root strut extends line downwards" $ do
+                    let input = offsetMiddleInnerTextParagraph 500 font opts
+                    let result = layoutRich input
+                    result `shouldBeGolden` "offsetMiddleUpInnerText"
+
+                it "root strut extends line upwards" $ do
+                    let input = offsetMiddleInnerTextParagraph (-500) font opts
+                    let result = layoutRich input
+                    result `shouldBeGolden` "offsetMiddleDownInnerText"
+
+                it "inline box strut extends line upwards" $ do
+                    let input = offsetMiddleOuterTextParagraph 500 font opts
+                    let result = layoutRich input
+                    result `shouldBeGolden` "offsetMiddleUpOuterText"
+
+                it "inline box strut extends line downwards" $ do
+                    let input = offsetMiddleOuterTextParagraph (-500) font opts
+                    let result = layoutRich input
+                    result `shouldBeGolden` "offsetMiddleDownOuterText"
+
+                it "inline box strut extends one wrapped line upwards" $ do
+                    let input = offsetMiddleOuterTextParagraph 500 font wrap
+                    let result = layoutRich input
+                    result `shouldBeGolden` "offsetMiddleUpOuterTextWrap"
+
+                it "inline box strut extends one wrapped line downwards" $ do
+                    let input = offsetMiddleOuterTextParagraph (-500) font wrap
+                    let result = layoutRich input
+                    result `shouldBeGolden` "offsetMiddleDownOuterTextWrap"
+
+                it "textless inline box strut extends line upwards" $ do
+                    let input = offsetTextlessBoxParagraph 500 font opts
+                    let result = layoutRich input
+                    result `shouldBeGolden` "offsetTextlessBoxUp"
+
+                it "textless inline box strut extends line downwards" $ do
+                    let input = offsetTextlessBoxParagraph (-500) font opts
+                    let result = layoutRich input
+                    result `shouldBeGolden` "offsetTextlessBoxDown"
+
             it "handles mixed sizes" $ do
                 let opts = defaultParagraphOptions
                         { paragraphAlignment = AlignStart
@@ -455,4 +538,20 @@
                 defaultParagraphOptions
                     { paragraphAlignment = AlignStart
                     , paragraphMaxWidth = 144
+                    }
+
+        describe "with Latin font" $ do
+            let fontPath = latinFont
+            font <- runIO $ loadFont latinFont 0 demoOptions
+
+            let shapedRunsSpec = shapedRunsSpecWithFont fontPath font
+
+            shapedRunsSpec
+                "handles complex vertical alignment"
+                "mixedVerticalAlignment" $
+                layoutRich $
+                mixedVerticalAlignmentParagraph font $
+                defaultParagraphOptions
+                    { paragraphAlignment = AlignStart
+                    , paragraphMaxWidth = largeWidth
                     }
