about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
authorbptato <nincsnevem662@gmail.com>2022-01-19 18:12:02 +0100
committerbptato <nincsnevem662@gmail.com>2022-01-19 18:21:33 +0100
commitbcaaf4e6b68ce1245558bc41559116a7a3296904 (patch)
treec6d97036f0bd553802917e17a2baf86e67a27d43 /src
parent0c0aa01a19d5dfb86562650c200cdc8c4b216fa0 (diff)
downloadchawan-bcaaf4e6b68ce1245558bc41559116a7a3296904.tar.gz
Re-implement inline blocks
Diffstat (limited to 'src')
-rw-r--r--src/css/cascade.nim6
-rw-r--r--src/layout/box.nim5
-rw-r--r--src/layout/engine.nim80
-rw-r--r--src/render/renderdocument.nim5
4 files changed, 62 insertions, 34 deletions
diff --git a/src/css/cascade.nim b/src/css/cascade.nim
index 3f85bfd8..fcec96d6 100644
--- a/src/css/cascade.nim
+++ b/src/css/cascade.nim
@@ -100,17 +100,13 @@ func calcRules(elem: Element, rules: CSSStylesheet): RuleList =
 #TODO couldn't these two procedures be merged?
 proc applyNormal(ares: var ApplyResult, decls: seq[CSSDeclaration]) =
   for decl in decls:
-    if decl.important:
-      ares.important.add(decl)
-    else:
+    if not decl.important:
       ares.normal.add(decl)
 
 proc applyImportant(ares: var ApplyResult, decls: seq[CSSDeclaration]) =
   for decl in decls:
     if decl.important:
       ares.important.add(decl)
-    else:
-      ares.normal.add(decl)
 
 proc applyRules(element: Element, ua, user, author: RuleList, pseudo: PseudoElem) =
   var ares: ApplyResult
diff --git a/src/layout/box.nim b/src/layout/box.nim
index 74e97c97..44e423ba 100644
--- a/src/layout/box.nim
+++ b/src/layout/box.nim
@@ -25,6 +25,7 @@ type
   InlineAtom* = ref object of RootObj
     relx*: int
     width*: int
+    height*: int
 
   InlineWord* = ref object of InlineAtom
     str*: string
@@ -53,7 +54,6 @@ type
     maxwidth*: int
 
   BlockContext* = ref object of InlineAtom
-    height*: int
     margin_done*: int
     margin_todo*: int
     inline*: InlineContext
@@ -84,6 +84,7 @@ type
     newline*: bool
   BlockBox* = ref object of CSSBox
     bctx*: BlockContext
-  InlineBlockBox* = ref object of CSSBox
+  InlineBlockBox* = ref object of BlockBox
+    ictx*: InlineContext
   ListItemBox* = ref object of CSSBox
 
diff --git a/src/layout/engine.nim b/src/layout/engine.nim
index 417d5d2c..562c5b4e 100644
--- a/src/layout/engine.nim
+++ b/src/layout/engine.nim
@@ -515,15 +515,20 @@ proc newWord(state: var InlineState) =
   word.nodes = state.nodes
   state.word = word
 
+proc addAtom(row: InlineRow, atom: InlineAtom) =
+  atom.relx = row.width
+  row.width += atom.width
+  row.height = max(row.height, atom.height)
+  row.atoms.add(atom)
+
 proc addWord(state: var InlineState) =
   if state.word.str != "":
     let row = state.ictx.thisrow
     var word = state.word
-    word.relx = state.ictx.thisrow.width
-    row.width += word.width
-    if row.height == 0: #first word => higher than 0
-      row.height = 1
-    row.atoms.add(word)
+    # Note, this should technically be set as soon as word has one letter but
+    # in practice this doesn't matter.
+    word.height = 1
+    row.addAtom(word)
     state.newWord()
 
 proc finishRow(ictx: InlineContext) =
@@ -531,8 +536,8 @@ proc finishRow(ictx: InlineContext) =
     let oldrow = ictx.thisrow
     ictx.rows.add(oldrow)
     ictx.height += oldrow.height
-    ictx.thisrow = InlineRow()
-    ictx.thisrow.rely = oldrow.rely + oldrow.height
+    ictx.width = max(ictx.width, oldrow.width)
+    ictx.thisrow = InlineRow(rely: oldrow.rely + oldrow.height)
 
 proc inlineWrap(state: var InlineState) =
   state.addWord()
@@ -641,7 +646,7 @@ proc renderText*(ictx: InlineContext, str: string, maxwidth: int, specified: CSS
 proc finish(ictx: InlineContext) =
   ictx.finishRow()
 
-proc newBlockContext(parent: BlockContext, box: BlockBox): BlockContext =
+template newBlockContext_common(parent: BlockContext, box: CSSBox) =
   new(result)
   result.rely = parent.height
   result.viewport = parent.viewport
@@ -651,8 +656,14 @@ proc newBlockContext(parent: BlockContext, box: BlockBox): BlockContext =
   else:
     result.compwidth = pwidth.cells_w(parent.viewport, parent.compwidth)
   result.specified = parent.specified
+
+proc newBlockContext(parent: BlockContext, box: BlockBox): BlockContext =
+  newBlockContext_common(parent, box)
   parent.nested.add(result)
 
+proc newInlineBlockContext(parent: BlockContext, box: InlineBlockBox): BlockContext =
+  newBlockContext_common(parent, box)
+
 proc newBlockContext(viewport: Viewport): BlockContext =
   new(result)
   result.compwidth = viewport.term.width
@@ -689,27 +700,31 @@ proc alignInline(pctx: BlockContext, box: InlineBox) =
     child.ictx = box.ictx
     pctx.alignInline(child)
 
+proc alignBlock(box: BlockBox)
+
 proc alignInlines(bctx: BlockContext, inlines: seq[CSSBox]) =
   let ictx = bctx.newInlineContext()
   for child in inlines:
-    assert child.t == BOX_INLINE
-    let child = InlineBox(child)
-    child.ictx = ictx
-    bctx.alignInline(child)
+    case child.t
+    of BOX_INLINE:
+      let child = InlineBox(child)
+      child.ictx = ictx
+      bctx.alignInline(child)
+    of BOX_INLINE_BLOCK:
+      let child = InlineBlockBox(child)
+      child.bctx = bctx.newInlineBlockContext(child)
+      alignBlock(child)
+      child.ictx = ictx
+      child.bctx.relx = ictx.thisrow.width
+      if ictx.thisrow.width + child.bctx.width > ictx.maxwidth:
+        ictx.finishRow()
+      ictx.thisrow.addAtom(child.bctx)
+      ictx.thisrow.height = max(ictx.thisrow.height, child.bctx.height)
+    else:
+      assert false
   ictx.finish()
   bctx.height += ictx.height
-  #eprint bctx.height, "add", ictx.height
-
-proc alignBlocks(bctx: BlockContext, blocks: seq[CSSBox])
-
-proc alignBlock(pctx: BlockContext, box: BlockBox) =
-  box.bctx = newBlockContext(pctx, box)
-
-  if box.inlinelayout:
-    # Box only contains inline boxes.
-    box.bctx.alignInlines(box.children)
-  else:
-    box.bctx.alignBlocks(box.children)
+  bctx.width = max(bctx.width, ictx.width)
 
 proc alignBlocks(bctx: BlockContext, blocks: seq[CSSBox]) =
   # Box contains block boxes.
@@ -722,6 +737,7 @@ proc alignBlocks(bctx: BlockContext, blocks: seq[CSSBox]) =
       let gctx = newBlockContext(bctx)
       gctx.alignInlines(blockgroup)
       bctx.height += gctx.height
+      bctx.width = max(bctx.width, gctx.width)
       blockgroup.setLen(0)
 
   for child in blocks:
@@ -729,8 +745,10 @@ proc alignBlocks(bctx: BlockContext, blocks: seq[CSSBox]) =
     of BOX_BLOCK:
       let child = BlockBox(child)
       flush_group()
-      bctx.alignBlock(child)
+      child.bctx = newBlockContext(bctx, child)
+      alignBlock(child)
       bctx.height += child.bctx.height
+      bctx.width = max(bctx.width, child.bctx.width)
     of BOX_INLINE:
       if child.inlinelayout:
         blockgroup.add(child)
@@ -738,9 +756,18 @@ proc alignBlocks(bctx: BlockContext, blocks: seq[CSSBox]) =
         flush_group()
         bctx.alignBlocks(child.children)
         #eprint "put"
+    of BOX_INLINE_BLOCK:
+      blockgroup.add(child)
     else: discard #TODO
   flush_group()
 
+proc alignBlock(box: BlockBox) =
+  if box.inlinelayout:
+    # Box only contains inline boxes.
+    box.bctx.alignInlines(box.children)
+  else:
+    box.bctx.alignBlocks(box.children)
+
 proc getBox(specified: CSSSpecifiedValues): CSSBox =
   case specified{"display"}
   of DISPLAY_BLOCK:
@@ -838,5 +865,6 @@ proc renderLayout*(document: Document, term: TermAttributes): BlockBox =
   #eprint document.root
   let viewport = Viewport(term: term)
   let root = document.generateBoxes()
-  viewport.newBlockContext().alignBlock(root)
+  root.bctx = viewport.newBlockContext()
+  alignBlock(root)
   return root
diff --git a/src/render/renderdocument.nim b/src/render/renderdocument.nim
index 1b195be0..39183c52 100644
--- a/src/render/renderdocument.nim
+++ b/src/render/renderdocument.nim
@@ -128,8 +128,11 @@ proc renderBlockContext(grid: var FlexibleGrid, ctx: BlockContext, x, y: int)
 proc renderInlineContext(grid: var FlexibleGrid, ctx: InlineContext, x, y: int) =
   for row in ctx.rows:
     let x = x + row.relx
-    let y = y + row.rely
+    let y = y + row.rely + row.height
     for atom in row.atoms:
+      # This aligns atoms with the baseline.
+      # (other alignment types in progress)
+      let y = y - atom.height
       if atom of BlockContext:
         let ctx = BlockContext(atom)
         grid.renderBlockContext(ctx, x + ctx.relx, y)