about summary refs log tree commit diff stats
path: root/src/layout
diff options
context:
space:
mode:
authorbptato <nincsnevem662@gmail.com>2022-12-28 21:01:45 +0100
committerbptato <nincsnevem662@gmail.com>2022-12-28 21:01:45 +0100
commit2765d53eea53f23bf7686a6f39b81c04e741ae3a (patch)
tree4c485960e7e2dadb98f72af0d41fd6845f5921d1 /src/layout
parentf9979334fa2b65a7747b3875feef45a4068a1d1d (diff)
downloadchawan-2765d53eea53f23bf7686a6f39b81c04e741ae3a.tar.gz
layout/engine: add hanging spaces, markers
Implement hanging ascii spaces. Non-ascii is still not supported...
Markers are now built in shrunken inline contexts, and are set to
white-space pre, so the trailing space is preserved.
Diffstat (limited to 'src/layout')
-rw-r--r--src/layout/engine.nim35
1 files changed, 25 insertions, 10 deletions
diff --git a/src/layout/engine.nim b/src/layout/engine.nim
index fe2c41af..41b195bf 100644
--- a/src/layout/engine.nim
+++ b/src/layout/engine.nim
@@ -198,23 +198,31 @@ proc verticalAlignLine(ictx: InlineContext) =
   line.height += margin_top
   line.height += margin_bottom
 
-proc addSpacing(line: LineBox, width, height: int, format: ComputedFormat) {.inline.} =
+proc addSpacing(line: LineBox, width, height: int, format: ComputedFormat, hang = false) =
   let spacing = InlineSpacing(width: width, height: height, baseline: height, format: format)
   spacing.offset.x = line.width
-  line.width += spacing.width
+  if not hang:
+    # In some cases, whitespace may "hang" at the end of the line. This means
+    # it is written, but is not actually counted in the box's width.
+    line.width += spacing.width
   line.atoms.add(spacing)
 
-proc flushWhitespace(ictx: InlineContext, computed: CSSComputedValues) =
+proc flushWhitespace(ictx: InlineContext, computed: CSSComputedValues, hang = false) =
   let shift = ictx.computeShift(computed)
   ictx.whitespacenum = 0
   if shift > 0:
-    ictx.currentLine.addSpacing(shift, ictx.cellheight, ictx.format)
+    ictx.currentLine.addSpacing(shift, ictx.cellheight, ictx.format, hang)
 
 proc finishLine(ictx: InlineContext, computed: CSSComputedValues, force = false) =
   if ictx.currentLine.atoms.len != 0 or force:
-    ictx.whitespacenum = 0
     ictx.charwidth = 0
-    ictx.flushWhitespace(computed)
+    let whitespace = computed{"white-space"}
+    if whitespace == WHITESPACE_PRE:
+      ictx.flushWhitespace(computed)
+    elif whitespace == WHITESPACE_PRE_WRAP:
+      ictx.flushWhitespace(computed, hang = true)
+    else:
+      ictx.whitespacenum = 0
     ictx.verticalAlignLine()
 
     let line = ictx.currentLine
@@ -704,7 +712,7 @@ proc buildInlines(parent: BlockBox, inlines: seq[BoxBuilder]): InlineContext =
         ictx.buildInline(child)
       of DISPLAY_INLINE_BLOCK, DISPLAY_INLINE_TABLE:
         let child = BlockBoxBuilder(child)
-        let iblock = child.buildInlineBlock(ictx, parent.contentWidth, parent.contentHeight)
+        let iblock = child.buildInlineBlock(ictx, ictx.contentWidth, ictx.contentHeight)
         ictx.addAtom(iblock, parent.computed)
         ictx.whitespacenum = 0
       else:
@@ -712,12 +720,17 @@ proc buildInlines(parent: BlockBox, inlines: seq[BoxBuilder]): InlineContext =
     ictx.finish(parent.computed)
   return ictx
 
+proc buildMarker(builder: MarkerBoxBuilder, parent: BlockBox): InlineContext =
+  let ictx = parent.newInlineContext()
+  ictx.shrink = true
+  ictx.buildInline(builder)
+  ictx.finish(builder.computed)
+  return ictx
+
 proc buildListItem(builder: ListItemBoxBuilder, parent: BlockBox): ListItemBox =
   result = parent.newListItem(builder)
-
   if builder.marker != nil:
-    result.marker = result.buildInlines(@[BoxBuilder(builder.marker)])
-
+    result.marker = buildMarker(builder.marker, result)
   result.buildLayout(builder.content)
 
 proc positionFixed(box: BlockBox, last: BlockBox = box.viewport.root[0]) =
@@ -1197,6 +1210,8 @@ proc getMarkerBox(computed: CSSComputedValues, listItemCounter: int): MarkerBoxB
   result.inlinelayout = true
   result.computed = computed.copyProperties()
   result.computed{"display"} = DISPLAY_INLINE
+  # Use pre, so the space at the end of the default markers isn't ignored.
+  result.computed{"white-space"} = WHITESPACE_PRE
   result.text.add(computed{"list-style-type"}.listMarker(listItemCounter))
 
 proc getListItemBox(computed: CSSComputedValues, listItemCounter: int): ListItemBoxBuilder =