about summary refs log tree commit diff stats
path: root/src/layout/engine.nim
diff options
context:
space:
mode:
Diffstat (limited to 'src/layout/engine.nim')
-rw-r--r--src/layout/engine.nim102
1 files changed, 80 insertions, 22 deletions
diff --git a/src/layout/engine.nim b/src/layout/engine.nim
index 45aef6de..b5876b5c 100644
--- a/src/layout/engine.nim
+++ b/src/layout/engine.nim
@@ -53,12 +53,13 @@ func computeShift(ictx: InlineContext, specified: CSSSpecifiedValues): int =
 
 proc newWord(state: var InlineState) =
   let word = InlineWord()
+  word.format = ComputedFormat()
   let specified = state.specified
-  word.color = specified{"color"}
-  word.fontstyle = specified{"font-style"}
-  word.fontweight = specified{"font-weight"}
-  word.textdecoration = specified{"text-decoration"}
-  word.node = state.node
+  word.format.color = specified{"color"}
+  word.format.fontstyle = specified{"font-style"}
+  word.format.fontweight = specified{"font-weight"}
+  word.format.textdecoration = specified{"text-decoration"}
+  word.format.node = state.node
   state.word = word
 
 proc finishRow(ictx: InlineContext) =
@@ -69,6 +70,12 @@ proc finishRow(ictx: InlineContext) =
     ictx.width = max(ictx.width, oldrow.width)
     ictx.thisrow = InlineRow(rely: oldrow.rely + oldrow.height)
 
+proc addSpacing(row: InlineRow, width, height: int, format: ComputedFormat) {.inline.} =
+  let spacing = InlineSpacing(width: width, height: height, format: format)
+  spacing.relx = row.width
+  row.width += spacing.width
+  row.atoms.add(spacing)
+
 proc addAtom(ictx: InlineContext, atom: InlineAtom, maxwidth: int, specified: CSSSpecifiedValues) =
   var shift = ictx.computeShift(specified)
   ictx.whitespace = false
@@ -82,10 +89,11 @@ proc addAtom(ictx: InlineContext, atom: InlineAtom, maxwidth: int, specified: CS
 
   if atom.width > 0 and atom.height > 0:
     if shift > 0:
-      let spacing = InlineSpacing(width: shift, height: atom.height)
-      spacing.relx = ictx.thisrow.width
-      ictx.thisrow.width += spacing.width
-      ictx.thisrow.atoms.add(spacing)
+      let format = if atom of InlineWord:
+        InlineWord(atom).format
+      else:
+        nil
+      ictx.thisrow.addSpacing(shift, atom.height, format)
 
     atom.relx += ictx.thisrow.width
     ictx.thisrow.width += atom.width
@@ -163,16 +171,22 @@ proc computedDimensions(bctx: BlockContext, width: int, height: Option[int]) =
   if pwidth.auto:
     bctx.compwidth = width
   else:
-    #bctx.compwidth = pwidth.cells_w(bctx.viewport, width)
     bctx.compwidth = pwidth.px(bctx.viewport, width)
 
-  #let mlef = bctx.specified{"margin-left"}.cells_w(bctx.viewport, width)
-  #let mrig = bctx.specified{"margin-right"}.cells_w(bctx.viewport, width)
-  let mlef = bctx.specified{"margin-left"}.px(bctx.viewport, width)
-  let mrig = bctx.specified{"margin-right"}.px(bctx.viewport, width)
-  bctx.relx = mlef
-  bctx.compwidth -= mlef
-  bctx.compwidth -= mrig
+  bctx.margin_left = bctx.specified{"margin-left"}.px(bctx.viewport, width)
+  bctx.margin_right = bctx.specified{"margin-right"}.px(bctx.viewport, width)
+
+  bctx.padding_top = bctx.specified{"padding-top"}.px(bctx.viewport, width)
+  bctx.padding_bottom = bctx.specified{"padding-bottom"}.px(bctx.viewport, width)
+  bctx.padding_left = bctx.specified{"padding-left"}.px(bctx.viewport, width)
+  bctx.padding_right = bctx.specified{"padding-right"}.px(bctx.viewport, width)
+
+  if bctx.compwidth >= width:
+    bctx.compwidth -= bctx.margin_left
+    bctx.compwidth -= bctx.margin_right
+
+    bctx.compwidth -= bctx.padding_left
+    bctx.compwidth -= bctx.padding_right
 
   let pheight = bctx.specified{"height"}
   if not pheight.auto:
@@ -219,10 +233,17 @@ proc newInlineContext(bctx: BlockContext): InlineContext =
 # children, whence the separate procedure.
 proc arrangeBlocks(bctx: BlockContext) =
   var y = 0
+  var x = 0
   var margin_todo = 0
 
+  y += bctx.padding_top
+  bctx.height += bctx.padding_top
+
+  x += bctx.padding_left
+
   template apply_child(child: BlockContext) =
     child.rely = y
+    child.relx = x + child.margin_left
     y += child.height
     bctx.height += child.height
     bctx.width = max(bctx.width, child.width)
@@ -233,7 +254,6 @@ proc arrangeBlocks(bctx: BlockContext) =
     let child = bctx.nested[i]
 
     bctx.margin_top = child.margin_top
-    #let mtop = bctx.specified{"margin-top"}.cells_h(bctx.viewport, bctx.compwidth)
     let mtop = bctx.specified{"margin-top"}.px(bctx.viewport, bctx.compwidth)
     if mtop > bctx.margin_top or mtop < 0:
       bctx.margin_top = mtop - bctx.margin_top
@@ -253,23 +273,46 @@ proc arrangeBlocks(bctx: BlockContext) =
     inc i
 
   bctx.margin_bottom = margin_todo
-  #let mbot = bctx.specified{"margin-bottom"}.cells_h(bctx.viewport, bctx.compwidth)
   let mbot = bctx.specified{"margin-bottom"}.px(bctx.viewport, bctx.compwidth)
   if mbot > bctx.margin_bottom or mbot < 0:
     bctx.margin_bottom = mbot - bctx.margin_bottom
 
+  bctx.height += bctx.padding_bottom
+
   if bctx.compheight.issome:
     bctx.height = bctx.compheight.get
 
+  bctx.width += bctx.padding_left
+  bctx.width += bctx.padding_right
+
+proc arrangeInlines(bctx: BlockContext) =
+  bctx.width += bctx.padding_left
+  bctx.inline.relx += bctx.padding_left
+
+  bctx.height += bctx.padding_top
+  bctx.inline.rely += bctx.padding_top
+
+  bctx.height += bctx.padding_bottom
+
+  bctx.width += bctx.padding_right
+
+  bctx.width = min(bctx.width, bctx.compwidth)
+
 proc alignBlock(box: BlockBox)
 
 proc alignInlineBlock(bctx: BlockContext, box: InlineBlockBox, parentcss: CSSSpecifiedValues) =
   if box.bctx.done:
     return
   alignBlock(box)
+
   box.bctx.rely += box.bctx.margin_top
   box.bctx.height += box.bctx.margin_top
   box.bctx.height += box.bctx.margin_bottom
+
+  box.bctx.relx += box.bctx.margin_left
+  box.bctx.width += box.bctx.margin_left
+  box.bctx.width += box.bctx.margin_right
+
   box.ictx.addAtom(box.bctx, bctx.compwidth, parentcss)
   box.ictx.whitespace = false
 
@@ -277,6 +320,15 @@ proc alignInline(bctx: BlockContext, box: InlineBox) =
   assert box.ictx != nil
   if box.newline:
     box.ictx.flushLine()
+
+  let margin_left = box.specified{"margin-left"}.px(bctx.viewport, bctx.compwidth)
+  box.ictx.thisrow.width += margin_left
+
+  let paddingformat = ComputedFormat(node: box.node)
+  let padding_left = box.specified{"padding-left"}.px(bctx.viewport, bctx.compwidth)
+  if padding_left > 0:
+    box.ictx.thisrow.addSpacing(padding_left, max(box.ictx.thisrow.height, 1), paddingformat)
+
   for text in box.text:
     assert box.children.len == 0
     box.ictx.renderText(text, bctx.compwidth, box.specified, box.node)
@@ -294,6 +346,13 @@ proc alignInline(bctx: BlockContext, box: InlineBox) =
     else:
       assert false, "child.t is " & $child.t
 
+  let padding_right = box.specified{"padding-right"}.px(bctx.viewport, bctx.compwidth)
+  if padding_right > 0:
+    box.ictx.thisrow.addSpacing(padding_right, max(box.ictx.thisrow.height, 1), paddingformat)
+
+  let margin_right = box.specified{"margin-right"}.px(bctx.viewport, bctx.compwidth)
+  box.ictx.thisrow.width += margin_right
+
 proc alignInlines(bctx: BlockContext, inlines: seq[CSSBox]) =
   let ictx = bctx.newInlineContext()
   for child in inlines:
@@ -312,9 +371,7 @@ proc alignInlines(bctx: BlockContext, inlines: seq[CSSBox]) =
   bctx.height += ictx.height
   if bctx.compheight.issome:
     bctx.height = bctx.compheight.get
-  bctx.width = max(ictx.width, ictx.width)
-  #bctx.margin_top = bctx.specified{"margin-top"}.cells_h(bctx.viewport, bctx.compwidth)
-  #bctx.margin_bottom = bctx.specified{"margin-bottom"}.cells_h(bctx.viewport, bctx.compwidth)
+  bctx.width = max(bctx.width, ictx.width)
   bctx.margin_top = bctx.specified{"margin-top"}.px(bctx.viewport, bctx.compwidth)
   bctx.margin_bottom = bctx.specified{"margin-bottom"}.px(bctx.viewport, bctx.compwidth)
 
@@ -351,6 +408,7 @@ proc alignBlock(box: BlockBox) =
   if box.inlinelayout:
     # Box only contains inline boxes.
     box.bctx.alignInlines(box.children)
+    box.bctx.arrangeInlines()
   else:
     var blockgroup: seq[CSSBox]
     box.bctx.alignBlocks(box.children, blockgroup, box.node)