about summary refs log tree commit diff stats
path: root/src/layout
diff options
context:
space:
mode:
authorbptato <nincsnevem662@gmail.com>2022-12-12 15:23:39 +0100
committerbptato <nincsnevem662@gmail.com>2022-12-12 15:23:39 +0100
commit47b0c8df73dc15599a19017cc7691cebb6d0b918 (patch)
tree702cb8f58599755c6cb346131555bfc6fb11af53 /src/layout
parent23da83a2faac129271cfd7b9761588301280a9fe (diff)
downloadchawan-47b0c8df73dc15599a19017cc7691cebb6d0b918.tar.gz
Add support for q, fix list-item counter behavior
Diffstat (limited to 'src/layout')
-rw-r--r--src/layout/engine.nim149
1 files changed, 100 insertions, 49 deletions
diff --git a/src/layout/engine.nim b/src/layout/engine.nim
index c22e96e7..b603d5c1 100644
--- a/src/layout/engine.nim
+++ b/src/layout/engine.nim
@@ -1139,7 +1139,6 @@ proc getTableCaptionBox(computed: CSSComputedValues): TableCaptionBoxBuilder =
 type BlockGroup = object
   parent: BoxBuilder
   boxes: seq[BoxBuilder]
-  listItemCounter: int
 
 type InnerBlockContext = object
   styledNode: StyledNode
@@ -1148,6 +1147,10 @@ type InnerBlockContext = object
   ibox: InlineBoxBuilder
   anonRow: TableRowBoxBuilder
   anonTable: TableBoxBuilder
+  quoteLevel: int
+  listItemCounter: int
+  listItemReset: bool
+  parent: ptr InnerBlockContext
 
 proc add(blockgroup: var BlockGroup, box: BoxBuilder) {.inline.} =
   assert box.computed{"display"} in {DISPLAY_INLINE, DISPLAY_INLINE_TABLE, DISPLAY_INLINE_BLOCK}, $box.computed{"display"}
@@ -1177,16 +1180,17 @@ proc iflush(blockgroup: var BlockGroup, ibox: var InlineBoxBuilder) =
 proc newBlockGroup(parent: BoxBuilder): BlockGroup =
   assert parent.computed{"display"} != DISPLAY_INLINE
   result.parent = parent
-  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
-proc generateTableCaptionBox(styledNode: StyledNode, viewport: Viewport): TableCaptionBoxBuilder
-proc generateBlockBox(styledNode: StyledNode, viewport: Viewport, marker = none(MarkerBoxBuilder)): BlockBoxBuilder
+
+proc generateTableBox(styledNode: StyledNode, viewport: Viewport, parent: var InnerBlockContext): TableBoxBuilder
+proc generateTableRowGroupBox(styledNode: StyledNode, viewport: Viewport, parent: var InnerBlockContext): TableRowGroupBoxBuilder
+proc generateTableRowBox(styledNode: StyledNode, viewport: Viewport, parent: var InnerBlockContext): TableRowBoxBuilder
+proc generateTableCellBox(styledNode: StyledNode, viewport: Viewport, parent: var InnerBlockContext): TableCellBoxBuilder
+proc generateTableCaptionBox(styledNode: StyledNode, viewport: Viewport, parent: var InnerBlockContext): TableCaptionBoxBuilder
+proc generateBlockBox(styledNode: StyledNode, viewport: Viewport, marker = none(MarkerBoxBuilder), parent: ptr InnerBlockContext = nil): BlockBoxBuilder
 proc generateInlineBoxes(ctx: var InnerBlockContext, styledNode: StyledNode)
 
+proc generateBlockBox(pctx: var InnerBlockContext, styledNode: StyledNode, marker = none(MarkerBoxBuilder)): BlockBoxBuilder =
+  return generateBlockBox(styledNode, pctx.viewport, marker, addr pctx)
 
 proc flushTableRow(ctx: var InnerBlockContext) =
   if ctx.anonRow != nil:
@@ -1212,10 +1216,17 @@ proc bflush(ctx: var InnerBlockContext) =
   ctx.iflush()
   ctx.blockgroup.flush()
 
+proc flushInherit(ctx: var InnerBlockContext) =
+  if ctx.parent != nil:
+    if not ctx.listItemReset:
+      ctx.parent.listItemCounter = ctx.listItemCounter
+    ctx.parent.quoteLevel = ctx.quoteLevel
+
 proc flush(ctx: var InnerBlockContext) =
   ctx.blockgroup.flush()
   ctx.flushTableRow()
   ctx.flushTable()
+  ctx.flushInherit()
 
 proc generateFromElem(ctx: var InnerBlockContext, styledNode: StyledNode) =
   let box = ctx.blockgroup.parent
@@ -1230,34 +1241,34 @@ proc generateFromElem(ctx: var InnerBlockContext, styledNode: StyledNode) =
   of DISPLAY_BLOCK:
     ctx.iflush()
     ctx.flush()
-    let childbox = styledNode.generateBlockBox(ctx.viewport)
+    let childbox = ctx.generateBlockBox(styledNode)
     box.children.add(childbox)
   of DISPLAY_LIST_ITEM:
     ctx.flush()
-    let childbox = getListItemBox(styledNode.computed, ctx.blockgroup.listItemCounter)
+    inc ctx.listItemCounter
+    let childbox = getListItemBox(styledNode.computed, ctx.listItemCounter)
     if childbox.computed{"list-style-position"} == LIST_STYLE_POSITION_INSIDE:
-      childbox.content = styledNode.generateBlockBox(ctx.viewport, some(childbox.marker))
+      childbox.content = ctx.generateBlockBox(styledNode, some(childbox.marker))
       childbox.marker = nil
     else:
-      childbox.content = styledNode.generateBlockBox(ctx.viewport)
+      childbox.content = ctx.generateBlockBox(styledNode)
     box.children.add(childbox)
-    inc ctx.blockgroup.listItemCounter
   of DISPLAY_INLINE:
     ctx.iflush()
     ctx.generateInlineBoxes(styledNode)
   of DISPLAY_INLINE_BLOCK:
     ctx.iflush()
     let childbox = getInlineBlockBox(styledNode.computed)
-    childbox.content = styledNode.generateBlockBox(ctx.viewport)
+    childbox.content = ctx.generateBlockBox(styledNode)
     ctx.blockgroup.add(childbox)
   of DISPLAY_TABLE:
     ctx.flush()
-    let childbox = styledNode.generateTableBox(ctx.viewport)
+    let childbox = styledNode.generateTableBox(ctx.viewport, ctx)
     box.children.add(childbox)
   of DISPLAY_TABLE_ROW:
     ctx.bflush()
     ctx.flushTableRow()
-    let childbox = styledNode.generateTableRowBox(ctx.viewport)
+    let childbox = styledNode.generateTableRowBox(ctx.viewport, ctx)
     if box.computed{"display"} in ProperTableRowParent:
       box.children.add(childbox)
     else:
@@ -1270,7 +1281,7 @@ proc generateFromElem(ctx: var InnerBlockContext, styledNode: StyledNode) =
   of DISPLAY_TABLE_ROW_GROUP, DISPLAY_TABLE_HEADER_GROUP, DISPLAY_TABLE_FOOTER_GROUP:
     ctx.bflush()
     ctx.flushTableRow()
-    let childbox = styledNode.generateTableRowGroupBox(ctx.viewport)
+    let childbox = styledNode.generateTableRowGroupBox(ctx.viewport, ctx)
     if box.computed{"display"} in {DISPLAY_TABLE, DISPLAY_INLINE_TABLE}:
       box.children.add(childbox)
     else:
@@ -1281,7 +1292,7 @@ proc generateFromElem(ctx: var InnerBlockContext, styledNode: StyledNode) =
         ctx.anonTable = getTableBox(wrappervals)
   of DISPLAY_TABLE_CELL:
     ctx.bflush()
-    let childbox = styledNode.generateTableCellBox(ctx.viewport)
+    let childbox = styledNode.generateTableCellBox(ctx.viewport, ctx)
     if box.computed{"display"} == DISPLAY_TABLE_ROW:
       box.children.add(childbox)
     else:
@@ -1292,12 +1303,12 @@ proc generateFromElem(ctx: var InnerBlockContext, styledNode: StyledNode) =
       ctx.anonRow.children.add(childbox)
   of DISPLAY_INLINE_TABLE:
     ctx.iflush()
-    let childbox = styledNode.generateTableBox(ctx.viewport)
+    let childbox = styledNode.generateTableBox(ctx.viewport, ctx)
     ctx.blockgroup.add(childbox)
   of DISPLAY_TABLE_CAPTION:
     ctx.bflush()
     ctx.flushTableRow()
-    let childbox = styledNode.generateTableCaptionBox(ctx.viewport)
+    let childbox = styledNode.generateTableCaptionBox(ctx.viewport, ctx)
     if box.computed{"display"} in {DISPLAY_TABLE, DISPLAY_INLINE_TABLE}:
       box.children.add(childbox)
     else:
@@ -1312,24 +1323,67 @@ proc generateFromElem(ctx: var InnerBlockContext, styledNode: StyledNode) =
     discard #TODO
   of DISPLAY_NONE: discard
 
+proc generateInlineText(ctx: var InnerBlockContext, text: string, styledNode: StyledNode) =
+  if ctx.ibox == nil:
+    ctx.ibox = getTextBox(styledNode.computed)
+    ctx.ibox.node = styledNode
+  ctx.ibox.text.add(text)
+
+proc generateReplacement(ctx: var InnerBlockContext, child, parent: StyledNode) =
+  case child.content.t
+  of CONTENT_OPEN_QUOTE:
+    let quotes = parent.computed{"quotes"}
+    var text: string
+    if quotes.qs.len > 0:
+      text = quotes.qs[min(ctx.quoteLevel, quotes.qs.high)].s
+    elif quotes.auto:
+      text = quoteStart(ctx.quoteLevel)
+    else: return
+    ctx.generateInlineText(text, parent)
+    inc ctx.quoteLevel
+  of CONTENT_CLOSE_QUOTE:
+    if ctx.quoteLevel > 0: dec ctx.quoteLevel
+    let quotes = parent.computed{"quotes"}
+    var text: string
+    if quotes.qs.len > 0:
+      text = quotes.qs[min(ctx.quoteLevel, quotes.qs.high)].e
+    elif quotes.auto:
+      text = quoteEnd(ctx.quoteLevel)
+    else: return
+    ctx.generateInlineText(text, parent)
+  of CONTENT_NO_OPEN_QUOTE:
+    inc ctx.quoteLevel
+  of CONTENT_NO_CLOSE_QUOTE:
+    if ctx.quoteLevel > 0: dec ctx.quoteLevel
+  of CONTENT_STRING:
+    #TODO canGenerateAnonymousInline?
+    ctx.generateInlineText(child.content.s, parent)
+
 proc generateInlineBoxes(ctx: var InnerBlockContext, styledNode: StyledNode) =
   for child in styledNode.children:
     case child.t
     of STYLED_ELEMENT:
       ctx.generateFromElem(child)
     of STYLED_TEXT:
-      if ctx.ibox == nil:
-        ctx.ibox = getTextBox(styledNode.computed)
-        ctx.ibox.node = styledNode
-      ctx.ibox.text.add(child.text)
+      ctx.generateInlineText(child.text, styledNode)
+    of STYLED_REPLACEMENT:
+      ctx.generateReplacement(child, styledNode)
   ctx.iflush()
 
-proc newInnerBlockContext(styledNode: StyledNode, blockgroup: BlockGroup, viewport: Viewport): InnerBlockContext =
-  return InnerBlockContext(
+proc newInnerBlockContext(styledNode: StyledNode, box: BoxBuilder, viewport: Viewport, parent: ptr InnerBlockContext): InnerBlockContext =
+  result = InnerBlockContext(
     styledNode: styledNode,
-    blockgroup: blockgroup,
-    viewport: viewport
+    blockgroup: newBlockGroup(box),
+    viewport: viewport,
+    parent: parent
   )
+  if parent != nil:
+    result.listItemCounter = parent[].listItemCounter
+    result.quoteLevel = parent[].quoteLevel
+  for reset in styledNode.computed{"counter-reset"}:
+    if reset.name == "list-item":
+      result.listItemCounter = reset.num
+      result.listItemReset = true
 
 proc generateInnerBlockBox(ctx: var InnerBlockContext) =
   let box = ctx.blockgroup.parent
@@ -1341,15 +1395,14 @@ proc generateInnerBlockBox(ctx: var InnerBlockContext) =
       ctx.generateFromElem(child)
     of STYLED_TEXT:
       if canGenerateAnonymousInline(ctx.blockgroup, box.computed, child.text):
-        if ctx.ibox == nil:
-          ctx.ibox = getTextBox(ctx.styledNode.computed)
-          ctx.ibox.node = ctx.styledNode
-        ctx.ibox.text.add(child.text)
+        ctx.generateInlineText(child.text, ctx.styledNode)
+    of STYLED_REPLACEMENT:
+      ctx.generateReplacement(child, ctx.styledNode)
   ctx.iflush()
 
-proc generateBlockBox(styledNode: StyledNode, viewport: Viewport, marker = none(MarkerBoxBuilder)): BlockBoxBuilder =
+proc generateBlockBox(styledNode: StyledNode, viewport: Viewport, marker = none(MarkerBoxBuilder), parent: ptr InnerBlockContext = nil): BlockBoxBuilder =
   let box = getBlockBox(styledNode.computed)
-  var ctx = newInnerBlockContext(styledNode, newBlockGroup(box), viewport)
+  var ctx = newInnerBlockContext(styledNode, box, viewport, parent)
 
   if marker.issome:
     ctx.ibox = marker.get
@@ -1362,17 +1415,15 @@ proc generateBlockBox(styledNode: StyledNode, viewport: Viewport, marker = none(
     if box.children.len == 0:
       box.children = ctx.blockgroup.boxes
       box.inlinelayout = true
-    else:
-      ctx.blockgroup.flush()
-  ctx.flushTableRow()
-  ctx.flushTable()
+      ctx.blockgroup.boxes.setLen(0)
+  ctx.flush()
   return box
 
-proc generateTableCellBox(styledNode: StyledNode, viewport: Viewport): TableCellBoxBuilder =
+proc generateTableCellBox(styledNode: StyledNode, viewport: Viewport, parent: var InnerBlockContext): 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 ctx = newInnerBlockContext(styledNode, newBlockGroup(box), viewport)
+  var ctx = newInnerBlockContext(styledNode, box, viewport, addr parent)
   ctx.generateInnerBlockBox()
   ctx.flush()
   return box
@@ -1390,9 +1441,9 @@ proc generateTableRowChildWrappers(box: TableRowBoxBuilder) =
       newchildren.add(wrapper)
   box.children = newchildren
 
-proc generateTableRowBox(styledNode: StyledNode, viewport: Viewport): TableRowBoxBuilder =
+proc generateTableRowBox(styledNode: StyledNode, viewport: Viewport, parent: var InnerBlockContext): TableRowBoxBuilder =
   let box = getTableRowBox(styledNode.computed)
-  var ctx = newInnerBlockContext(styledNode, newBlockGroup(box), viewport)
+  var ctx = newInnerBlockContext(styledNode, box, viewport, addr parent)
   ctx.generateInnerBlockBox()
   ctx.flush()
   box.generateTableRowChildWrappers()
@@ -1412,17 +1463,17 @@ proc generateTableRowGroupChildWrappers(box: TableRowGroupBoxBuilder) =
       newchildren.add(wrapper)
   box.children = newchildren
 
-proc generateTableRowGroupBox(styledNode: StyledNode, viewport: Viewport): TableRowGroupBoxBuilder =
+proc generateTableRowGroupBox(styledNode: StyledNode, viewport: Viewport, parent: var InnerBlockContext): TableRowGroupBoxBuilder =
   let box = getTableRowGroupBox(styledNode.computed)
-  var ctx = newInnerBlockContext(styledNode, newBlockGroup(box), viewport)
+  var ctx = newInnerBlockContext(styledNode, box, viewport, addr parent)
   ctx.generateInnerBlockBox()
   ctx.flush()
   box.generateTableRowGroupChildWrappers()
   return box
 
-proc generateTableCaptionBox(styledNode: StyledNode, viewport: Viewport): TableCaptionBoxBuilder =
+proc generateTableCaptionBox(styledNode: StyledNode, viewport: Viewport, parent: var InnerBlockContext): TableCaptionBoxBuilder =
   let box = getTableCaptionBox(styledNode.computed)
-  var ctx = newInnerBlockContext(styledNode, newBlockGroup(box), viewport)
+  var ctx = newInnerBlockContext(styledNode, box, viewport, addr parent)
   ctx.generateInnerBlockBox()
   ctx.flush()
   return box
@@ -1441,9 +1492,9 @@ proc generateTableChildWrappers(box: TableBoxBuilder) =
       newchildren.add(wrapper)
   box.children = newchildren
 
-proc generateTableBox(styledNode: StyledNode, viewport: Viewport): TableBoxBuilder =
+proc generateTableBox(styledNode: StyledNode, viewport: Viewport, parent: var InnerBlockContext): TableBoxBuilder =
   let box = getTableBox(styledNode.computed)
-  var ctx = newInnerBlockContext(styledNode, newBlockGroup(box), viewport)
+  var ctx = newInnerBlockContext(styledNode, box, viewport, addr parent)
   ctx.generateInnerBlockBox()
   ctx.flush()
   box.generateTableChildWrappers()