about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--src/layout/box.nim22
-rw-r--r--src/layout/engine.nim180
-rw-r--r--src/layout/renderdocument.nim10
3 files changed, 103 insertions, 109 deletions
diff --git a/src/layout/box.nim b/src/layout/box.nim
index 5756a4a6..d607ea68 100644
--- a/src/layout/box.nim
+++ b/src/layout/box.nim
@@ -39,7 +39,6 @@ type
     # minimum content width
     xminwidth*: LayoutUnit
     size*: Size
-    children*: seq[InlineBoxBuilder] #TODO remove
 
   SplitType* = enum
     stSplitStart, stSplitEnd
@@ -48,14 +47,21 @@ type
     offset*: Offset
     size*: Size
 
-  InlineFragment* = ref object
+  InlineFragmentState* = object
     startOffset*: Offset # offset of the first word, for position: absolute
     areas*: seq[Area] # background that should be painted by fragment
-    children*: seq[InlineFragment]
     atoms*: seq[InlineAtom]
+
+  InlineFragment* = ref object
+    children*: seq[InlineFragment]
     computed*: CSSComputedValues
     node*: StyledNode
     splitType*: set[SplitType]
+    state*: InlineFragmentState
+    text*: seq[string]
+    newline*: bool #TODO enumify
+    bmp*: Bitmap
+    box*: BlockBox
 
   RelativeRect* = object
     top*: LayoutUnit
@@ -63,16 +69,6 @@ type
     left*: LayoutUnit
     right*: LayoutUnit
 
-  InlineBoxBuilder* = ref object
-    computed*: CSSComputedValues
-    node*: StyledNode
-    children*: seq[InlineBoxBuilder]
-    text*: seq[string]
-    newline*: bool
-    splitType*: set[SplitType]
-    bmp*: Bitmap
-    box*: BlockBox
-
   BlockBoxLayoutState* = object
     offset*: Offset
     size*: Size # padding size
diff --git a/src/layout/engine.nim b/src/layout/engine.nim
index ddbb4802..e10c8890 100644
--- a/src/layout/engine.nim
+++ b/src/layout/engine.nim
@@ -335,7 +335,7 @@ proc newWord(ictx: var InlineContext; state: var InlineState) =
   ictx.wrappos = -1
   ictx.hasshy = false
 
-proc horizontalAlignLines(ictx: var InlineContext; state: InlineState) =
+proc horizontalAlignLines(ictx: var InlineContext; align: CSSTextAlign) =
   let width = case ictx.space.w.t
   of scMinContent, scMaxContent:
     ictx.size.w
@@ -344,7 +344,7 @@ proc horizontalAlignLines(ictx: var InlineContext; state: InlineState) =
   of scStretch:
     max(ictx.size.w, ictx.space.w.u)
   # we don't support directions for now so left = start and right = end
-  case state.computed{"text-align"}
+  case align
   of TextAlignStart, TextAlignLeft, TextAlignChaLeft, TextAlignJustify:
     discard
   of TextAlignEnd, TextAlignRight, TextAlignChaRight:
@@ -477,7 +477,7 @@ proc putAtom(state: var LineBoxState; atom: InlineAtom;
     iastate: InlineAtomState; fragment: InlineFragment) =
   state.atomstates.add(iastate)
   state.atoms.add(atom)
-  fragment.atoms.add(atom)
+  fragment.state.atoms.add(atom)
 
 proc addSpacing(ictx: var InlineContext; width, height: LayoutUnit;
     state: InlineState; hang = false) =
@@ -549,7 +549,7 @@ proc finishLine(ictx: var InlineContext; state: var InlineState; wrap: bool;
       ictx.currentLine.size.w
     if state.firstLine:
       #TODO padding top
-      state.fragment.startOffset = offset(
+      state.fragment.state.startOffset = offset(
         x = state.startOffsetTop.x,
         y = y + ictx.currentLine.size.h
       )
@@ -575,36 +575,37 @@ proc addBackgroundAreas(ictx: var InlineContext; rootFragment: InlineFragment) =
       continue
     var prevEnd: LayoutUnit = 0
     for atom in line.atoms:
-      if currentStack.len == 0 or atomIdx >= top.atoms.len:
+      if currentStack.len == 0 or atomIdx >= top.state.atoms.len:
         atomIdx = 0
         while true:
           let thisNode = traverseStack.pop()
           if thisNode == nil: # sentinel found
             let oldTop = currentStack.pop()
             # finish oldTop area
-            if oldTop.areas[^1].offset.y == line.offsety:
+            if oldTop.state.areas[^1].offset.y == line.offsety:
               # if offset.y is this offsety, then it means that we added it on
               # this line, so we just have to set its width
               if prevEnd > 0:
-                oldTop.areas[^1].size.w = prevEnd - oldTop.areas[^1].offset.x
+                oldTop.state.areas[^1].size.w = prevEnd -
+                  oldTop.state.areas[^1].offset.x
               else:
                 # fragment got dropped without prevEnd moving anywhere; delete
                 # area
-                oldTop.areas.setLen(oldTop.areas.high)
+                oldTop.state.areas.setLen(oldTop.state.areas.high)
             elif prevEnd > 0:
               # offset.y is presumably from a previous line
               # (if prevEnd is 0, then the area doesn't extend to this line,
               # so we do not have to do anything.)
               let x = line.atoms[0].offset.x
               let w = prevEnd - x
-              if oldTop.areas[^1].offset.x == x and
-                  oldTop.areas[^1].size.w == w:
+              if oldTop.state.areas[^1].offset.x == x and
+                  oldTop.state.areas[^1].size.w == w:
                 # same vertical dimensions; just extend.
-                oldTop.areas[^1].size.h = line.offsety + line.height -
-                  oldTop.areas[^1].offset.y
+                oldTop.state.areas[^1].size.h = line.offsety + line.height -
+                  oldTop.state.areas[^1].offset.y
               else:
                 # vertical dimensions differ; add new area.
-                oldTop.areas.add(Area(
+                oldTop.state.areas.add(Area(
                   offset: offset(x = x, y = line.offsety),
                   size: size(w = w, h = line.height)
                 ))
@@ -612,33 +613,33 @@ proc addBackgroundAreas(ictx: var InlineContext; rootFragment: InlineFragment) =
           traverseStack.add(nil) # sentinel
           for i in countdown(thisNode.children.high, 0):
             traverseStack.add(thisNode.children[i])
-          thisNode.areas.add(Area(
+          thisNode.state.areas.add(Area(
             offset: offset(x = atom.offset.x, y = line.offsety),
             size: size(w = atom.size.w, h = line.height)
           ))
           currentStack.add(thisNode)
-          if thisNode.atoms.len > 0:
+          if thisNode.state.atoms.len > 0:
             break
       prevEnd = atom.offset.x + atom.size.w
-      assert top.atoms[atomIdx] == atom
+      assert top.state.atoms[atomIdx] == atom
       inc atomIdx
     # extend current areas
     for node in currentStack:
-      if node.areas[^1].offset.y == line.offsety:
+      if node.state.areas[^1].offset.y == line.offsety:
         # added in this iteration. no need to extend vertically, but make sure
         # that it reaches prevEnd.
-        node.areas[^1].size.w = prevEnd - node.areas[^1].offset.x
+        node.state.areas[^1].size.w = prevEnd - node.state.areas[^1].offset.x
         continue
-      let x1 = node.areas[^1].offset.x
-      let x2 = node.areas[^1].offset.x + node.areas[^1].size.w
+      let x1 = node.state.areas[^1].offset.x
+      let x2 = node.state.areas[^1].offset.x + node.state.areas[^1].size.w
       if x1 == line.atoms[0].offset.x and x2 == prevEnd and not lineSkipped:
         # horizontal dimensions are the same as for the last area. just move its
         # vertical end to the current line's end.
-        node.areas[^1].size.h = line.offsety + line.height -
-          node.areas[^1].offset.y
+        node.state.areas[^1].size.h = line.offsety + line.height -
+          node.state.areas[^1].offset.y
       else:
         # horizontal dimensions differ; add a new area
-        node.areas.add(Area(
+        node.state.areas.add(Area(
           offset: offset(x = line.atoms[0].offset.x, y = line.offsety),
           size: size(w = prevEnd - line.atoms[0].offset.x, h = line.height)
         ))
@@ -1163,8 +1164,7 @@ proc layoutRootInline(bctx: var BlockContext; root: RootInlineFragment;
 proc layoutBlock(bctx: var BlockContext; box: BlockBox; sizes: ResolvedSizes)
 proc layoutTableWrapper(bctx: BlockContext; box: BlockBox; sizes: ResolvedSizes)
 proc layoutFlex(bctx: var BlockContext; box: BlockBox; sizes: ResolvedSizes)
-proc layoutInline(ictx: var InlineContext; box: InlineBoxBuilder):
-  InlineFragment
+proc layoutInline(ictx: var InlineContext; fragment: InlineFragment)
 
 # Note: padding must still be applied after this.
 proc applySize(box: BlockBox; sizes: ResolvedSizes;
@@ -1441,34 +1441,34 @@ proc addInlineBlock(ictx: var InlineContext; state: var InlineState;
   ictx.whitespacenum = 0
 
 proc layoutChildren(ictx: var InlineContext; state: var InlineState;
-    children: seq[InlineBoxBuilder]) =
+    children: seq[InlineFragment]) =
   for child in children:
     case child.computed{"display"}
     of DisplayInline:
-      state.fragment.children.add(ictx.layoutInline(child))
+      ictx.layoutInline(child)
     of DisplayInlineBlock, DisplayInlineTableWrapper, DisplayInlineFlex:
-      # Note: we do not need a separate inline fragment here, because the tree
-      # generator already does an iflush() before adding inline blocks.
+      child.state = InlineFragmentState()
+      var state = InlineState(
+        computed: child.computed,
+        node: child.node,
+        fragment: child
+      )
       let w = fitContent(ictx.space.w)
       let h = ictx.space.h
       ictx.addInlineBlock(state, child.box, w, h)
     else:
       assert false
 
-proc layoutInline(ictx: var InlineContext; box: InlineBoxBuilder):
-    InlineFragment =
+proc layoutInline(ictx: var InlineContext; fragment: InlineFragment) =
   let lctx = ictx.lctx
-  let fragment = InlineFragment(
-    computed: box.computed,
-    node: box.node,
-    splitType: box.splitType
-  )
-  if stSplitStart in box.splitType:
-    let marginLeft = box.computed{"margin-left"}.px(lctx, ictx.space.w)
+  fragment.state = InlineFragmentState()
+  if stSplitStart in fragment.splitType:
+    let marginLeft = fragment.computed{"margin-left"}.px(lctx, ictx.space.w)
     ictx.currentLine.size.w += marginLeft
   var state = InlineState(
-    computed: box.computed,
-    node: box.node,
+    #TODO do I really have to copy these two?
+    computed: fragment.computed,
+    node: fragment.node,
     fragment: fragment,
     firstLine: true,
     startOffsetTop: offset(
@@ -1476,69 +1476,62 @@ proc layoutInline(ictx: var InlineContext; box: InlineBoxBuilder):
       y = ictx.currentLine.offsety
     )
   )
-  if box.newline:
+  if fragment.newline:
     ictx.flushLine(state)
-  if stSplitStart in box.splitType:
-    let paddingLeft = box.computed{"padding-left"}.px(lctx, ictx.space.w)
+  if stSplitStart in fragment.splitType:
+    let paddingLeft = fragment.computed{"padding-left"}.px(lctx, ictx.space.w)
     ictx.currentLine.size.w += paddingLeft
-  assert box.children.len == 0 or box.text.len == 0
+  assert fragment.children.len == 0 or fragment.text.len == 0
   ictx.applyLineHeight(ictx.currentLine, state.computed)
   if ictx.firstTextFragment == nil:
     ictx.firstTextFragment = fragment
   ictx.lastTextFragment = fragment
-  if box.bmp != nil:
-    let h = int(box.bmp.height).toLayoutUnit().ceilTo(ictx.cellheight)
+  if fragment.bmp != nil:
+    let h = int(fragment.bmp.height).toLayoutUnit().ceilTo(ictx.cellheight)
     let iastate = InlineAtomState(
       vertalign: state.computed{"vertical-align"},
       baseline: h
     )
     let atom = InlineAtom(
       t: iatImage,
-      bmp: box.bmp,
-      size: size(w = int(box.bmp.width), h = h), #TODO overflow
+      bmp: fragment.bmp,
+      size: size(w = int(fragment.bmp.width), h = h), #TODO overflow
     )
     discard ictx.addAtom(state, iastate, atom)
   else:
-    ictx.layoutText(state, box.text)
-    ictx.layoutChildren(state, box.children)
-  if stSplitEnd in box.splitType:
-    let paddingRight = box.computed{"padding-right"}.px(lctx, ictx.space.w)
+    ictx.layoutText(state, fragment.text)
+    ictx.layoutChildren(state, fragment.children)
+  assert fragment.children.len == 0 or fragment.state.atoms.len == 0
+  if stSplitEnd in fragment.splitType:
+    let paddingRight = fragment.computed{"padding-right"}.px(lctx, ictx.space.w)
     ictx.currentLine.size.w += paddingRight
-    let marginRight = box.computed{"margin-right"}.px(lctx, ictx.space.w)
+    let marginRight = fragment.computed{"margin-right"}.px(lctx, ictx.space.w)
     ictx.currentLine.size.w += marginRight
   if state.firstLine:
-    fragment.startOffset = offset(
+    fragment.state.startOffset = offset(
       x = state.startOffsetTop.x,
       y = ictx.currentLine.offsety
     )
   else:
-    fragment.startOffset = offset(x = 0, y = ictx.currentLine.offsety)
-  return fragment
+    fragment.state.startOffset = offset(x = 0, y = ictx.currentLine.offsety)
 
 proc layoutRootInline(bctx: var BlockContext; root: RootInlineFragment;
     space: AvailableSpace; computed: CSSComputedValues;
     offset, bfcOffset: Offset) =
   root.offset = offset
-  root.fragment = InlineFragment(computed: bctx.lctx.myRootProperties)
   root.size = size(w = 0, h = 0)
   root.firstBaseline = 0
   root.baseline = 0
   root.xminwidth = 0
   root.size = size(w = 0, h = 0)
   var ictx = bctx.initInlineContext(space, bfcOffset, root)
-  for child in root.children:
-    assert child.computed{"display"} == DisplayInline
-    let childFragment = ictx.layoutInline(child)
-    root.fragment.children.add(childFragment)
+  ictx.layoutInline(root.fragment)
   if ictx.firstTextFragment != nil:
-    root.fragment.startOffset = ictx.firstTextFragment.startOffset
-  let lastFragment = if ictx.lastTextFragment != nil:
-    ictx.lastTextFragment
-  else:
-    InlineFragment(computed: computed)
-  var state = InlineState(computed: computed, fragment: lastFragment)
-  ictx.finishLine(state, wrap = false)
-  ictx.horizontalAlignLines(state)
+    root.fragment.state.startOffset = ictx.firstTextFragment.state.startOffset
+  if ictx.lastTextFragment != nil:
+    var state = InlineState(computed: computed, fragment: ictx.lastTextFragment)
+    ictx.finishLine(state, wrap = false)
+  ictx.horizontalAlignLines(computed{"text-align"})
   ictx.addBackgroundAreas(root.fragment)
   root.xminwidth = ictx.minwidth
 
@@ -2537,12 +2530,12 @@ proc layoutBlock(bctx: var BlockContext; box: BlockBox; sizes: ResolvedSizes) =
 # Tree generation (1st pass)
 
 proc newMarkerBox(computed: CSSComputedValues; listItemCounter: int):
-    InlineBoxBuilder =
+    InlineFragment =
   let computed = computed.inheritProperties()
   computed{"display"} = DisplayInline
   # Use pre, so the space at the end of the default markers isn't ignored.
   computed{"white-space"} = WhitespacePre
-  return InlineBoxBuilder(
+  return InlineFragment(
     computed: computed,
     text: @[computed{"list-style-type"}.listMarker(listItemCounter)]
   )
@@ -2551,13 +2544,14 @@ type BlockGroup = object
   parent: BlockBox
   # if inline is not nil, then inline.children.len > 0
   inline: RootInlineFragment
+  lctx: LayoutContext
 
 type InnerBlockContext = object
   styledNode: StyledNode
   blockgroup: BlockGroup
   lctx: LayoutContext
-  ibox: InlineBoxBuilder
-  iroot: InlineBoxBuilder
+  ibox: InlineFragment
+  iroot: InlineFragment
   anonRow: BlockBox
   anonTableWrapper: BlockBox
   quoteLevel: int
@@ -2566,11 +2560,13 @@ type InnerBlockContext = object
   parent: ptr InnerBlockContext
   inlineStack: seq[StyledNode]
 
-proc add(blockgroup: var BlockGroup; box: InlineBoxBuilder) =
+proc add(blockgroup: var BlockGroup; box: InlineFragment) =
   assert box.computed{"display"} == DisplayInline
   if blockgroup.inline == nil:
-    blockgroup.inline = RootInlineFragment()
-  blockgroup.inline.children.add(box)
+    blockgroup.inline = RootInlineFragment(
+      fragment: InlineFragment(computed: blockgroup.lctx.myRootProperties)
+    )
+  blockgroup.inline.fragment.children.add(box)
 
 proc flush(blockgroup: var BlockGroup) =
   if blockgroup.inline != nil:
@@ -2588,7 +2584,7 @@ proc flush(blockgroup: var BlockGroup) =
 func canBuildAnonymousInline(blockgroup: BlockGroup;
     computed: CSSComputedValues; str: string): bool =
   return blockgroup.inline != nil and
-      blockgroup.inline.children[^1].computed{"display"} == DisplayInline or
+      blockgroup.inline.fragment.children.len > 0 or
     computed.whitespacepre or not str.onlyWhitespace()
 
 proc buildTable(parent: var InnerBlockContext; styledNode: StyledNode): BlockBox
@@ -2601,14 +2597,14 @@ proc buildTableCell(parent: var InnerBlockContext; styledNode: StyledNode):
 proc buildTableCaption(parent: var InnerBlockContext; styledNode: StyledNode):
   BlockBox
 proc buildBlock(styledNode: StyledNode; lctx: LayoutContext;
-  marker: InlineBoxBuilder = nil; parent: ptr InnerBlockContext = nil):
+  marker: InlineFragment = nil; parent: ptr InnerBlockContext = nil):
   BlockBox
 proc buildFlex(styledNode: StyledNode; lctx: LayoutContext;
   parent: ptr InnerBlockContext = nil): BlockBox
 proc buildInlineBoxes(ctx: var InnerBlockContext; styledNode: StyledNode)
 
 proc buildBlock(pctx: var InnerBlockContext; styledNode: StyledNode;
-    marker: InlineBoxBuilder = nil): BlockBox =
+    marker: InlineFragment = nil): BlockBox =
   return buildBlock(styledNode, pctx.lctx, marker, addr pctx)
 
 proc buildFlex(pctx: var InnerBlockContext; styledNode: StyledNode): BlockBox =
@@ -2670,16 +2666,16 @@ proc flush(ctx: var InnerBlockContext) =
   ctx.flushTable()
   ctx.flushInherit()
 
-proc reconstructInlineParents(ctx: var InnerBlockContext): InlineBoxBuilder =
+proc reconstructInlineParents(ctx: var InnerBlockContext): InlineFragment =
   let rootNode = ctx.inlineStack[0]
-  var parent = InlineBoxBuilder(
+  var parent = InlineFragment(
     computed: rootNode.computed,
     node: rootNode
   )
   ctx.iroot = parent
   for i in 1 ..< ctx.inlineStack.len:
     let node = ctx.inlineStack[i]
-    let nbox = InlineBoxBuilder(computed: node.computed, node: node)
+    let nbox = InlineFragment(computed: node.computed, node: node)
     assert nbox.computed{"display"} != DisplayTableCell
     parent.children.add(nbox)
     parent = nbox
@@ -2712,7 +2708,7 @@ proc buildFromElem(ctx: var InnerBlockContext; styledNode: StyledNode) =
       markerComputed{"display"} = DisplayBlock
       let marker = BlockBox(
         computed: marker.computed,
-        inline: RootInlineFragment(children: @[marker])
+        inline: RootInlineFragment(fragment: marker)
       )
       let child = BlockBox(
         computed: styledNode.computed,
@@ -2727,7 +2723,7 @@ proc buildFromElem(ctx: var InnerBlockContext; styledNode: StyledNode) =
     # create a new inline box that we can safely put our inline block into
     ctx.iflush()
     let computed = styledNode.computed.inheritProperties()
-    ctx.ibox = InlineBoxBuilder(computed: computed, node: styledNode)
+    ctx.ibox = InlineFragment(computed: computed, node: styledNode)
     if ctx.inlineStack.len > 0:
       let iparent = ctx.reconstructInlineParents()
       iparent.children.add(ctx.ibox)
@@ -2739,7 +2735,7 @@ proc buildFromElem(ctx: var InnerBlockContext; styledNode: StyledNode) =
     of DisplayInlineTable: ctx.buildTable(styledNode)
     of DisplayInlineFlex: ctx.buildFlex(styledNode)
     else: nil
-    let wrapper = InlineBoxBuilder(computed: childBox.computed, box: childBox)
+    let wrapper = InlineFragment(computed: childBox.computed, box: childBox)
     ctx.ibox.children.add(wrapper)
     ctx.iflush()
   of DisplayTable:
@@ -2799,14 +2795,14 @@ proc buildAnonymousInlineText(ctx: var InnerBlockContext; text: string;
     styledNode: StyledNode; bmp: Bitmap = nil) =
   if ctx.iroot == nil:
     let computed = styledNode.computed.inheritProperties()
-    ctx.ibox = InlineBoxBuilder(computed: computed, node: styledNode, bmp: bmp)
+    ctx.ibox = InlineFragment(computed: computed, node: styledNode)
     if ctx.inlineStack.len > 0:
       let iparent = ctx.reconstructInlineParents()
-      assert ctx.ibox.computed{"display"} != DisplayTableCell
       iparent.children.add(ctx.ibox)
       ctx.iroot = iparent
     else:
       ctx.iroot = ctx.ibox
+  ctx.ibox.bmp = bmp
   ctx.ibox.text.add(text)
 
 proc buildReplacement(ctx: var InnerBlockContext; child, parent: StyledNode) =
@@ -2850,7 +2846,7 @@ proc buildReplacement(ctx: var InnerBlockContext; child, parent: StyledNode) =
     #TODO ??
     # this used to set ibox (before we had iroot), now I'm not sure if we
     # should reconstruct here first
-    ctx.iroot = InlineBoxBuilder(
+    ctx.iroot = InlineFragment(
       computed: parent.computed.inheritProperties(),
       newline: true
     )
@@ -2887,7 +2883,7 @@ proc newInnerBlockContext(styledNode: StyledNode; box: BlockBox;
   assert box.computed{"display"} != DisplayInline
   var ctx = InnerBlockContext(
     styledNode: styledNode,
-    blockgroup: BlockGroup(parent: box),
+    blockgroup: BlockGroup(parent: box, lctx: lctx),
     lctx: lctx,
     parent: parent
   )
@@ -2917,7 +2913,7 @@ proc buildInnerBlockBox(ctx: var InnerBlockContext) =
   ctx.iflush()
 
 proc buildBlock(styledNode: StyledNode; lctx: LayoutContext;
-    marker: InlineBoxBuilder = nil; parent: ptr InnerBlockContext = nil):
+    marker: InlineFragment = nil; parent: ptr InnerBlockContext = nil):
     BlockBox =
   let box = BlockBox(computed: styledNode.computed, node: styledNode)
   var ctx = newInnerBlockContext(styledNode, box, lctx, parent)
@@ -2936,7 +2932,9 @@ proc buildBlock(styledNode: StyledNode; lctx: LayoutContext;
     box.inline = if ctx.blockgroup.inline != nil:
       ctx.blockgroup.inline
     else:
-      RootInlineFragment()
+      RootInlineFragment(fragment: InlineFragment(
+        computed: lctx.myRootProperties
+      ))
     ctx.blockgroup.inline = nil
   ctx.blockgroup.flush()
   return box
diff --git a/src/layout/renderdocument.nim b/src/layout/renderdocument.nim
index d218dce6..45bcb64f 100644
--- a/src/layout/renderdocument.nim
+++ b/src/layout/renderdocument.nim
@@ -341,7 +341,7 @@ proc renderBlockBox(grid: var FlexibleGrid; state: var RenderState;
 
 proc paintInlineFragment(grid: var FlexibleGrid; state: var RenderState;
     fragment: InlineFragment; offset: Offset; bgcolor: CellColor) =
-  for area in fragment.areas:
+  for area in fragment.state.areas:
     let x1 = toInt(offset.x + area.offset.x)
     let y1 = toInt(offset.y + area.offset.y)
     let x2 = toInt(offset.x + area.offset.x + area.size.w)
@@ -350,14 +350,14 @@ proc paintInlineFragment(grid: var FlexibleGrid; state: var RenderState;
 
 proc renderInlineFragment(grid: var FlexibleGrid; state: var RenderState;
     fragment: InlineFragment; offset: Offset) =
-  assert fragment.atoms.len == 0 or fragment.children.len == 0
+  assert fragment.state.atoms.len == 0 or fragment.children.len == 0
   let bgcolor = fragment.computed{"background-color"}
   if bgcolor.t == ctANSI or bgcolor.t == ctRGB and bgcolor.argbcolor.a > 0:
     #TODO color blending
     grid.paintInlineFragment(state, fragment, offset, bgcolor)
-  if fragment.atoms.len > 0:
+  if fragment.state.atoms.len > 0:
     let format = fragment.computed.toFormat()
-    for atom in fragment.atoms:
+    for atom in fragment.state.atoms:
       case atom.t
       of iatInlineBlock:
         grid.renderBlockBox(state, atom.innerbox, offset + atom.offset)
@@ -377,7 +377,7 @@ proc renderInlineFragment(grid: var FlexibleGrid; state: var RenderState;
   if fragment.computed{"position"} != PositionStatic:
     if fragment.splitType != {stSplitStart, stSplitEnd}:
       if stSplitStart in fragment.splitType:
-        state.absolutePos.add(offset + fragment.startOffset)
+        state.absolutePos.add(offset + fragment.state.startOffset)
       if stSplitEnd in fragment.splitType:
         discard state.absolutePos.pop()