about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
authorbptato <nincsnevem662@gmail.com>2022-11-15 17:47:58 +0100
committerbptato <nincsnevem662@gmail.com>2022-11-15 17:47:58 +0100
commit86d05a993463b49d2bd9cc6cb6a7af9b416f802a (patch)
tree446c75a668695abc341bc32f2d5e21b7edbd8e4f /src
parentb00b6a1e1cc6d74bb0b76218ddb4dcf37bef7ac7 (diff)
downloadchawan-86d05a993463b49d2bd9cc6cb6a7af9b416f802a.tar.gz
Very much WIP table implementation
Diffstat (limited to 'src')
-rw-r--r--src/css/values.nim18
-rw-r--r--src/layout/box.nim2
-rw-r--r--src/layout/engine.nim112
-rw-r--r--src/render/renderdocument.nim11
4 files changed, 124 insertions, 19 deletions
diff --git a/src/css/values.nim b/src/css/values.nim
index c3050eae..fcd8e068 100644
--- a/src/css/values.nim
+++ b/src/css/values.nim
@@ -450,15 +450,15 @@ func cssDisplay(d: CSSDeclaration): CSSDisplay =
       of "inline": return DISPLAY_INLINE
       of "list-item": return DISPLAY_LIST_ITEM
       of "inline-block": return DISPLAY_INLINE_BLOCK
-      # of "table": return DISPLAY_TABLE
-      # of "table-row": return DISPLAY_TABLE_ROW
-      # of "table-cell": return DISPLAY_TABLE_CELL
-      # of "table-column": return DISPLAY_TABLE_COLUMN
-      # of "table-column-group": return DISPLAY_TABLE_COLUMN_GROUP
-      # of "inline-table": return DISPLAY_INLINE_TABLE
-      # of "table-row-group": return DISPLAY_TABLE_ROW_GROUP
-      # of "table-header-group": return DISPLAY_TABLE_HEADER_GROUP
-      # of "table-footer-group": return DISPLAY_TABLE_FOOTER_GROUP
+      of "table": return DISPLAY_TABLE
+      of "table-row": return DISPLAY_TABLE_ROW
+      of "table-cell": return DISPLAY_TABLE_CELL
+      of "table-column": return DISPLAY_TABLE_COLUMN
+      of "table-column-group": return DISPLAY_TABLE_COLUMN_GROUP
+      of "inline-table": return DISPLAY_INLINE_TABLE
+      of "table-row-group": return DISPLAY_TABLE_ROW_GROUP
+      of "table-header-group": return DISPLAY_TABLE_HEADER_GROUP
+      of "table-footer-group": return DISPLAY_TABLE_FOOTER_GROUP
       of "none": return DISPLAY_NONE
       else: return DISPLAY_INLINE
   raise newException(CSSValueError, "Invalid display")
diff --git a/src/layout/box.nim b/src/layout/box.nim
index 2db2a78a..61e64ee0 100644
--- a/src/layout/box.nim
+++ b/src/layout/box.nim
@@ -53,6 +53,7 @@ type
   TableRowBoxBuilder* = ref object of BoxBuilder
 
   TableCellBoxBuilder* = ref object of BoxBuilder
+    colspan*: int
 
   TableBoxBuilder* = ref object of BlockBoxBuilder
     rowgroups*: seq[TableRowGroupBoxBuilder]
@@ -136,6 +137,7 @@ type
   TableRowBox* = ref object of BlockBox
 
   TableBox* = ref object of BlockBox
+    columns*: seq[int] # offset of each column
 
   InlineBlockBox* = ref object of InlineAtom
     bctx*: BlockBox
diff --git a/src/layout/engine.nim b/src/layout/engine.nim
index a51c4c55..b5365184 100644
--- a/src/layout/engine.nim
+++ b/src/layout/engine.nim
@@ -639,25 +639,47 @@ proc buildTableCell(box: TableCellBoxBuilder, parent: TableRowBox): TableCellBox
     result.buildInlineLayout(box.children)
   else:
     result.buildBlockLayout(box.children, box.node)
+  result.offset.x += parent.width
 
 proc buildTableRow(box: TableRowBoxBuilder, parent: TableBox): TableRowBox =
   result = parent.newTableRowBox(box)
+  var n = 0
   for child in box.children:
     case child.computed{"display"}
     of DISPLAY_TABLE_CELL:
-      result.nested.add(buildTableCell(TableCellBoxBuilder(child), result))
+      let cellbuilder = TableCellBoxBuilder(child)
+      let cell = buildTableCell(cellbuilder, result)
+      result.nested.add(cell)
+      result.height = max(result.height, cell.height)
+      if parent.columns.len <= n:
+        parent.columns.setLen(n + 1)
+      parent.columns[n] = max(cell.width, parent.columns[n])
+      var i = n
+      n += cellbuilder.colspan
+      if parent.columns.len <= n:
+        parent.columns.setLen(n + 1)
+      while i < n:
+        result.width += parent.columns[i]
+        inc i
     else:
-      discard
-      #TODO assert false
+      assert false
+  result.offset.y += parent.height
 
 proc buildTable(box: TableBoxBuilder, parent: BlockBox): TableBox =
   result = parent.newTableBox(box)
   for child in box.children:
     case child.computed{"display"}
     of DISPLAY_TABLE_ROW:
-      result.nested.add(buildTableRow(TableRowBoxBuilder(child), result))
+      let row = buildTableRow(TableRowBoxBuilder(child), result)
+      result.nested.add(row)
+      result.height += row.height
+      result.width = max(row.width, result.width)
     of DISPLAY_TABLE_ROW_GROUP:
-      discard
+      for child in TableRowGroupBoxBuilder(child).children:
+        let row = buildTableRow(TableRowBoxBuilder(child), result)
+        result.nested.add(row)
+        result.height += row.height
+        result.width = max(row.width, result.width)
     else:
       discard
       #TODO assert false
@@ -748,6 +770,7 @@ proc getTableRowBox(computed: CSSComputedValues): TableRowBoxBuilder =
 proc getTableCellBox(computed: CSSComputedValues): TableCellBoxBuilder =
   new(result)
   result.computed = computed
+  result.colspan = 1
 
 type BlockGroup = object
   parent: BoxBuilder
@@ -782,6 +805,7 @@ proc newBlockGroup(parent: BoxBuilder): BlockGroup =
   result.listItemCounter = 1
 
 proc generateTableBox(styledNode: StyledNode, viewport: Viewport): TableBoxBuilder
+proc generateTableRowGroupBox(styledNode: StyledNode, viewport: Viewport): TableRowGroupBoxBuilder
 proc generateTableRowBox(styledNode: StyledNode, viewport: Viewport): TableRowBoxBuilder
 proc generateTableCellBox(styledNode: StyledNode, viewport: Viewport): TableCellBoxBuilder
 
@@ -830,6 +854,10 @@ proc generateFromElem(styledNode: StyledNode, blockgroup: var BlockGroup, viewpo
     blockgroup.flush()
     let childbox = styledNode.generateTableRowBox(viewport)
     box.children.add(childbox)
+  of DISPLAY_TABLE_ROW_GROUP:
+    blockgroup.flush()
+    let childbox = styledNode.generateTableRowGroupBox(viewport)
+    box.children.add(childbox)
   of DISPLAY_TABLE_CELL:
     blockgroup.flush()
     let childbox = styledNode.generateTableCellBox(viewport)
@@ -909,10 +937,13 @@ func isMisparented(box: BoxBuilder, parent: BoxBuilder): bool =
 
 proc generateTableCellBox(styledNode: StyledNode, viewport: Viewport): TableCellBoxBuilder =
   let box = getTableCellBox(styledNode.computed)
+  if styledNode.node != nil and styledNode.node.nodeType == ELEMENT_NODE:
+    box.colspan = Element(styledNode.node).attri("colspan").get(1)
   var blockgroup = newBlockGroup(box)
   var ibox: InlineBoxBuilder = nil
   for child in styledNode.children:
     if child.t == STYLED_ELEMENT:
+      flush_ibox
       generateFromElem(child, blockgroup, viewport, ibox)
     else:
       if canGenerateAnonymousInline(blockgroup, box.computed, child.text):
@@ -920,8 +951,29 @@ proc generateTableCellBox(styledNode: StyledNode, viewport: Viewport): TableCell
           ibox = getTextBox(styledNode.computed)
           ibox.node = styledNode
         ibox.text.add(child.text)
+  flush_ibox
+  if blockgroup.boxes.len > 0:
+    # Avoid unnecessary anonymous block boxes
+    if box.children.len == 0:
+      box.children = blockgroup.boxes
+      box.inlinelayout = true
+    else:
+      blockgroup.flush()
   return box
 
+proc generateTableRowChildWrappers(box: TableRowBoxBuilder) =
+  var newchildren = newSeqOfCap[BoxBuilder](box.children.len)
+  var wrappervals = box.computed.inheritProperties()
+  wrappervals.setDisplay(DISPLAY_TABLE_CELL)
+  for child in box.children:
+    if child.computed{"display"} == DISPLAY_TABLE_CELL:
+      newchildren.add(child)
+    else:
+      let wrapper = getTableCellBox(wrappervals)
+      wrapper.children.add(child)
+      newchildren.add(wrapper)
+  box.children = newchildren
+
 proc generateTableRowBox(styledNode: StyledNode, viewport: Viewport): TableRowBoxBuilder =
   let box = getTableRowBox(styledNode.computed)
   var blockgroup = newBlockGroup(box)
@@ -937,12 +989,53 @@ proc generateTableRowBox(styledNode: StyledNode, viewport: Viewport): TableRowBo
         ibox.text.add(child.text)
   return box
 
+proc generateTableRowGroupChildWrappers(box: TableRowGroupBoxBuilder) =
+  var newchildren = newSeqOfCap[BoxBuilder](box.children.len)
+  var wrappervals = box.computed.inheritProperties()
+  wrappervals.setDisplay(DISPLAY_TABLE_CELL)
+  for child in box.children:
+    if child.computed{"display"} == DISPLAY_TABLE_ROW:
+      newchildren.add(child)
+    else:
+      let wrapper = getTableRowBox(wrappervals)
+      wrapper.children.add(child)
+      newchildren.add(wrapper)
+  box.children = newchildren
+
+proc generateTableRowGroupBox(styledNode: StyledNode, viewport: Viewport): TableRowGroupBoxBuilder =
+  let box = getTableRowGroupBox(styledNode.computed)
+  var blockgroup = newBlockGroup(box)
+  var ibox: InlineBoxBuilder = nil
+  for child in styledNode.children:
+    if child.t == STYLED_ELEMENT:
+      generateFromElem(child, blockgroup, viewport, ibox)
+    else:
+      if canGenerateAnonymousInline(blockgroup, box.computed, child.text):
+        if ibox == nil:
+          ibox = getTextBox(styledNode.computed)
+          ibox.node = styledNode
+        ibox.text.add(child.text)
+  return box
+
+proc generateTableChildWrappers(box: TableBoxBuilder) =
+  var newchildren = newSeqOfCap[BoxBuilder](box.children.len)
+  var wrappervals = box.computed.inheritProperties()
+  wrappervals.setDisplay(DISPLAY_TABLE_ROW)
+  for child in box.children:
+    if child.computed{"display"} in ProperTableChild:
+      newchildren.add(child)
+    else:
+      let wrapper = getTableRowBox(wrappervals)
+      wrapper.children.add(child)
+      wrapper.generateTableRowChildWrappers()
+      newchildren.add(wrapper)
+  box.children = newchildren
+
 proc generateTableBox(styledNode: StyledNode, viewport: Viewport): TableBoxBuilder =
   let box = getTableBox(styledNode.computed)
-  var blockgroup = newBlockGroup(box)
+  var blockgroup = newBlockGroup(box) #TODO this probably shouldn't exist
   var ibox: InlineBoxBuilder = nil
   var listItemCounter = 1
-
   for child in styledNode.children:
     if child.t == STYLED_ELEMENT:
       generateFromElem(child, blockgroup, viewport, ibox)
@@ -952,11 +1045,10 @@ proc generateTableBox(styledNode: StyledNode, viewport: Viewport): TableBoxBuild
           ibox = getTextBox(styledNode.computed)
           ibox.node = styledNode
         ibox.text.add(child.text)
-
   flush_ibox
   blockgroup.flush()
-
-  #TODO Generate missing child wrappers
+  box.generateTableChildWrappers()
+  #TODO generate missing parents
   return box
 
 proc renderLayout*(viewport: var Viewport, document: Document, root: StyledNode) =
diff --git a/src/render/renderdocument.nim b/src/render/renderdocument.nim
index 484f8fb5..4fddddc7 100644
--- a/src/render/renderdocument.nim
+++ b/src/render/renderdocument.nim
@@ -261,6 +261,15 @@ proc renderInlineContext(grid: var FlexibleGrid, ctx: InlineContext, x, y: int,
         let spacing = InlineSpacing(atom)
         grid.setSpacing(spacing, x, y, term)
 
+proc renderTable(grid: var FlexibleGrid, ctx: TableBox, x, y: int, term: TermAttributes) =
+  for row in ctx.nested:
+    assert row.computed{"display"} == DISPLAY_TABLE_ROW
+    for cell in row.nested:
+      let x = x + row.offset.x
+      let y = y + row.offset.y
+      assert cell.computed{"display"} == DISPLAY_TABLE_CELL
+      grid.renderBlockContext(cell, x, y, term)
+
 proc renderBlockContext(grid: var FlexibleGrid, ctx: BlockBox, x, y: int, term: TermAttributes) =
   var stack = newSeqOfCap[(BlockBox, int, int)](100)
   stack.add((ctx, x, y))
@@ -281,6 +290,8 @@ proc renderBlockContext(grid: var FlexibleGrid, ctx: BlockBox, x, y: int, term:
     if ctx.inline != nil:
       assert ctx.nested.len == 0
       grid.renderInlineContext(ctx.inline, x, y, term)
+    elif ctx.computed{"display"} == DISPLAY_TABLE: #TODO INLINE_TABLE
+      grid.renderTable(TableBox(ctx), x, y, term)
     else:
       for i in countdown(ctx.nested.high, 0):
         stack.add((ctx.nested[i], x, y))