diff options
author | bptato <nincsnevem662@gmail.com> | 2022-01-23 12:41:23 +0100 |
---|---|---|
committer | bptato <nincsnevem662@gmail.com> | 2022-01-23 12:41:23 +0100 |
commit | 7a2cda0e992da40684c193791b5865bb643df95e (patch) | |
tree | 21a08211c69afd14bc84fe8ba666402c071d1117 /src/layout | |
parent | 806e38f140b377b308ed41622d795c21a497bd44 (diff) | |
download | chawan-7a2cda0e992da40684c193791b5865bb643df95e.tar.gz |
Implement word-spacing
Diffstat (limited to 'src/layout')
-rw-r--r-- | src/layout/box.nim | 1 | ||||
-rw-r--r-- | src/layout/engine.nim | 54 |
2 files changed, 34 insertions, 21 deletions
diff --git a/src/layout/box.nim b/src/layout/box.nim index a49bde7f..e5e3f2fa 100644 --- a/src/layout/box.nim +++ b/src/layout/box.nim @@ -48,6 +48,7 @@ type whitespace*: bool maxwidth*: int + viewport*: Viewport BlockContext* = ref object of InlineAtom inline*: InlineContext diff --git a/src/layout/engine.nim b/src/layout/engine.nim index d11f1093..cfd2a1dd 100644 --- a/src/layout/engine.nim +++ b/src/layout/engine.nim @@ -46,22 +46,28 @@ proc finishRow(ictx: InlineContext) = ictx.width = max(ictx.width, oldrow.width) ictx.thisrow = InlineRow(rely: oldrow.rely + oldrow.height) -proc addAtom(ictx: InlineContext, atom: InlineAtom, maxwidth: int, specified: CSSSpecifiedValues) = - # Whitespace between words - var shift = 0 - let whitespacepre = specified{"white-space"} in {WHITESPACE_PRE, WHITESPACE_PRE_WRAP} +func whitespacepre(specified: CSSSpecifiedValues): bool {.inline.} = + specified{"white-space"} in {WHITESPACE_PRE, WHITESPACE_PRE_WRAP} + +# Whitespace between words +func computeShift(ictx: InlineContext, specified: CSSSpecifiedValues): int = if ictx.whitespace: - if ictx.thisrow.atoms.len > 0 or whitespacepre: - shift = 1 + if ictx.thisrow.atoms.len > 0 or specified.whitespacepre: + let spacing = specified{"word-spacing"} + if spacing.auto: + return 1 + return spacing.cells_w(ictx.viewport, 0) ictx.whitespace = false + return 0 +proc addAtom(ictx: InlineContext, atom: InlineAtom, maxwidth: int, specified: CSSSpecifiedValues) = + var shift = ictx.computeShift(specified) # Line wrapping if specified{"white-space"} notin {WHITESPACE_NOWRAP, WHITESPACE_PRE}: - if specified{"word-break"} == WORD_BREAK_NORMAL and ictx.thisrow.width + atom.width + shift > maxwidth: + if ictx.thisrow.width + atom.width + shift > maxwidth: ictx.finishRow() - if not whitespacepre: - # No whitespace on newline - shift = 0 + # Recompute on newline + shift = ictx.computeShift(specified) ictx.thisrow.width += shift @@ -87,13 +93,14 @@ proc flushLine(ictx: InlineContext) = proc checkWrap(state: var InlineState, r: Rune) = if state.specified{"white-space"} in {WHITESPACE_NOWRAP, WHITESPACE_PRE}: return + let shift = state.ictx.computeShift(state.specified) case state.specified{"word-break"} of WORD_BREAK_BREAK_ALL: - if state.ictx.thisrow.width + state.word.width + r.width() > state.maxwidth: + if state.ictx.thisrow.width + state.word.width + shift + r.width() > state.maxwidth: state.addWord() state.ictx.finishRow() of WORD_BREAK_KEEP_ALL: - if state.ictx.thisrow.width + state.word.width + r.width() > state.maxwidth: + if state.ictx.thisrow.width + state.word.width + shift + r.width() > state.maxwidth: state.ictx.finishRow() else: discard @@ -120,18 +127,15 @@ proc renderText*(ictx: InlineContext, str: string, maxwidth: int, specified: CSS #eprint "start", str.strip() var i = 0 while i < str.len: - var rw = 0 - case str[i] - of ' ', '\n', '\t': + if str[i].isWhitespace(): state.processWhitespace(str[i]) inc i else: var r: Rune fastRuneAt(str, i, r) - rw = r.width() state.checkWrap(r) state.word.str &= r - state.word.width += rw + state.word.width += r.width() state.addWord() @@ -186,6 +190,7 @@ proc newBlockContext(viewport: Viewport): BlockContext = proc newInlineContext(bctx: BlockContext): InlineContext = new(result) result.thisrow = InlineRow() + result.viewport = bctx.viewport bctx.inline = result # Blocks' positions do not have to be arranged if alignBlocks is called with @@ -235,7 +240,8 @@ proc arrangeBlocks(bctx: BlockContext) = proc alignBlock(box: BlockBox) proc alignInlineBlock(bctx: BlockContext, box: InlineBlockBox, parentcss: CSSSpecifiedValues) = - box.bctx = bctx.newInlineBlockContext(box) + if box.bctx.done: + return alignBlock(box) box.bctx.rely += box.bctx.margin_top box.bctx.height += box.bctx.margin_top @@ -328,7 +334,6 @@ proc alignBlocks(bctx: BlockContext, blocks: seq[CSSBox]) = proc alignBlock(box: BlockBox) = if box.bctx.done: return - box.bctx.done = true if box.node != nil: box.bctx.viewport.nodes.add(box.node) if box.inlinelayout: @@ -339,6 +344,7 @@ proc alignBlock(box: BlockBox) = box.bctx.arrangeBlocks() if box.node != nil: discard box.bctx.viewport.nodes.pop() + box.bctx.done = true proc getBox(specified: CSSSpecifiedValues): CSSBox = case specified{"display"} @@ -390,7 +396,7 @@ proc generateBox(elem: Element, viewport: Viewport, bctx: BlockContext = nil): C if viewport.map[elem.uid] != nil: let box = viewport.map[elem.uid] var bctx = bctx - if box.specified{"display"} in {DISPLAY_BLOCK, DISPLAY_LIST_ITEM}: + if box.specified{"display"} in {DISPLAY_BLOCK, DISPLAY_LIST_ITEM, DISPLAY_INLINE_BLOCK}: let box = BlockBox(box) if bctx == nil: box.bctx = viewport.newBlockContext() @@ -418,13 +424,19 @@ proc generateBox(elem: Element, viewport: Viewport, bctx: BlockContext = nil): C box.element = elem var bctx = bctx - if box.specified{"display"} in {DISPLAY_BLOCK, DISPLAY_LIST_ITEM}: + case box.specified{"display"} + of DISPLAY_BLOCK, DISPLAY_LIST_ITEM: let box = BlockBox(box) if bctx == nil: box.bctx = viewport.newBlockContext() else: box.bctx = bctx.newBlockContext(box) bctx = box.bctx + of DISPLAY_INLINE_BLOCK: + let box = InlineBlockBox(box) + box.bctx = bctx.newInlineBlockContext(box) + bctx = box.bctx + else: discard var ibox: InlineBox template add_ibox() = |