diff options
author | bptato <nincsnevem662@gmail.com> | 2023-10-13 23:22:25 +0200 |
---|---|---|
committer | bptato <nincsnevem662@gmail.com> | 2023-10-13 23:22:25 +0200 |
commit | f0b013e7904c8f9dac50c6340617508fa3d52177 (patch) | |
tree | 96b8d199ad86cb56087c736eaa6e09080e83a047 | |
parent | 04cbc981edb8edc586d06ce804c24951dd1badd6 (diff) | |
download | chawan-f0b013e7904c8f9dac50c6340617508fa3d52177.tar.gz |
layout: refactor InlineContext
Most InlineContext members may be discarded after layout, and thus belong in InlineState.
-rw-r--r-- | src/layout/box.nim | 9 | ||||
-rw-r--r-- | src/layout/engine.nim | 340 |
2 files changed, 187 insertions, 162 deletions
diff --git a/src/layout/box.nim b/src/layout/box.nim index 4f5eb84d..22bed3a5 100644 --- a/src/layout/box.nim +++ b/src/layout/box.nim @@ -109,18 +109,11 @@ type InlineContext* = ref object offset*: Offset height*: LayoutUnit - lines*: seq[LineBox] - currentLine*: LineBox width*: LayoutUnit - availableWidth*: SizeConstraint - availableHeight*: SizeConstraint + lines*: seq[LineBox] - charwidth*: int - whitespacenum*: int # this is actually xminwidth. minwidth*: LayoutUnit - viewport*: Viewport - format*: ComputedFormat BlockBox* = ref object of RootObj inline*: InlineContext diff --git a/src/layout/engine.nim b/src/layout/engine.nim index 46ffff0c..6ca54e46 100644 --- a/src/layout/engine.nim +++ b/src/layout/engine.nim @@ -58,6 +58,13 @@ type InlineState = object wrappos: int # position of last wrapping opportunity, or -1 hasshy: bool computed: CSSComputedValues + currentLine: LineBox + charwidth: int + whitespacenum: int + format: ComputedFormat + viewport: Viewport + availableWidth: SizeConstraint + availableHeight: SizeConstraint func whitespacepre(computed: CSSComputedValues): bool = computed{"white-space"} in {WHITESPACE_PRE, WHITESPACE_PRE_LINE, WHITESPACE_PRE_WRAP} @@ -68,21 +75,21 @@ func nowrap(computed: CSSComputedValues): bool = func cellwidth(viewport: Viewport): LayoutUnit = viewport.window.ppc -func cellwidth(ictx: InlineContext): LayoutUnit = - ictx.viewport.cellwidth +func cellwidth(state: InlineState): LayoutUnit = + state.viewport.cellwidth func cellheight(viewport: Viewport): LayoutUnit = viewport.window.ppl -func cellheight(ictx: InlineContext): LayoutUnit = - ictx.viewport.cellheight +func cellheight(state: InlineState): LayoutUnit = + state.viewport.cellheight # Check if the last atom on the current line is a spacing atom, not counting # padding atoms. -func hasLastSpacing(ictx: InlineContext): bool = - for i in countdown(ictx.currentLine.atoms.high, 0): - if ictx.currentLine.atoms[i] of InlineSpacing: - if ictx.currentLine.atoms[i] of InlinePadding: +func hasLastSpacing(state: InlineState): bool = + for i in countdown(state.currentLine.atoms.high, 0): + if state.currentLine.atoms[i] of InlineSpacing: + if state.currentLine.atoms[i] of InlinePadding: continue # skip padding return true else: @@ -90,15 +97,15 @@ func hasLastSpacing(ictx: InlineContext): bool = return false # Whitespace between words -func computeShift(ictx: InlineContext, computed: CSSComputedValues): +func computeShift(state: InlineState, computed: CSSComputedValues): LayoutUnit = - if ictx.whitespacenum > 0: - if ictx.currentLine.atoms.len > 0 and not ictx.hasLastSpacing() or + if state.whitespacenum > 0: + if state.currentLine.atoms.len > 0 and not state.hasLastSpacing() or computed.whitespacepre: let spacing = computed{"word-spacing"} if spacing.auto: - return ictx.cellwidth * ictx.whitespacenum - return spacing.px(ictx.viewport) * ictx.whitespacenum + return state.cellwidth * state.whitespacenum + return spacing.px(state.viewport) * state.whitespacenum return 0 proc applyLineHeight(viewport: Viewport, line: LineBox, computed: CSSComputedValues) = @@ -124,20 +131,20 @@ proc newWord(state: var InlineState) = let word = InlineWord() word.format = getComputedFormat(state.computed, state.node) word.vertalign = state.computed{"vertical-align"} - state.ictx.format = word.format + state.format = word.format state.word = word state.wrappos = -1 state.hasshy = false -proc horizontalAlignLine(ictx: InlineContext, line: LineBox, +proc horizontalAlignLine(state: InlineState, line: LineBox, computed: CSSComputedValues, last = false) = - let width = case ictx.availableWidth.t + let width = case state.availableWidth.t of MIN_CONTENT, MAX_CONTENT: - ictx.width + state.ictx.width of FIT_CONTENT: - min(ictx.width, ictx.availableWidth.u) + min(state.ictx.width, state.availableWidth.u) of STRETCH: - max(ictx.width, ictx.availableWidth.u) + max(state.ictx.width, state.availableWidth.u) # we don't support directions for now so left = start and right = end case computed{"text-align"} of TEXT_ALIGN_START, TEXT_ALIGN_LEFT, TEXT_ALIGN_CHA_LEFT: @@ -147,12 +154,12 @@ proc horizontalAlignLine(ictx: InlineContext, line: LineBox, let x = max(width, line.width) - line.width for atom in line.atoms: atom.offset.x += x - ictx.width = max(atom.offset.x + atom.width, ictx.width) + state.ictx.width = max(atom.offset.x + atom.width, state.ictx.width) of TEXT_ALIGN_CENTER, TEXT_ALIGN_CHA_CENTER: let x = max((max(width - line.offset.x, line.width)) div 2 - line.width div 2, 0) for atom in line.atoms: atom.offset.x += x - ictx.width = max(atom.offset.x + atom.width, ictx.width) + state.ictx.width = max(atom.offset.x + atom.width, state.ictx.width) of TEXT_ALIGN_JUSTIFY: if not computed.whitespacepre and not last: var sumwidth: LayoutUnit = 0 @@ -173,11 +180,11 @@ proc horizontalAlignLine(ictx: InlineContext, line: LineBox, let atom = InlineSpacing(atom) atom.width = spacingwidth line.width += atom.width - ictx.width = max(width, ictx.width) #TODO this seems meaningless? + state.ictx.width = max(width, state.ictx.width) #TODO this seems meaningless? # Align atoms (inline boxes, text, etc.) vertically inside the line. -proc verticalAlignLine(ictx: InlineContext) = - let line = ictx.currentLine +proc verticalAlignLine(state: InlineState) = + let line = state.currentLine # Start with line-height as the baseline and line height. line.height = line.lineheight @@ -187,7 +194,7 @@ proc verticalAlignLine(ictx: InlineContext) = for atom in line.atoms: case atom.vertalign.keyword of VERTICAL_ALIGN_BASELINE: - let len = atom.vertalign.length.px(ictx.viewport, line.lineheight) + let len = atom.vertalign.length.px(state.viewport, line.lineheight) line.baseline = max(line.baseline, atom.baseline + len) of VERTICAL_ALIGN_TOP, VERTICAL_ALIGN_BOTTOM: line.baseline = max(line.baseline, atom.height) @@ -207,7 +214,7 @@ proc verticalAlignLine(ictx: InlineContext) = of VERTICAL_ALIGN_BASELINE: # Line height must be at least as high as # (line baseline) - (atom baseline) + (atom height) + (extra height). - let len = atom.vertalign.length.px(ictx.viewport, line.lineheight) + let len = atom.vertalign.length.px(state.viewport, line.lineheight) line.height = max(line.baseline - atom.baseline + atom.height + len, line.height) of VERTICAL_ALIGN_MIDDLE: # Line height must be at least @@ -225,7 +232,7 @@ proc verticalAlignLine(ictx: InlineContext) = case atom.vertalign.keyword of VERTICAL_ALIGN_BASELINE: # Atom is placed at (line baseline) - (atom baseline) - len - let len = atom.vertalign.length.px(ictx.viewport, line.lineheight) + let len = atom.vertalign.length.px(state.viewport, line.lineheight) atom.offset.y = line.baseline - atom.baseline - len of VERTICAL_ALIGN_MIDDLE: # Atom is placed at (line baseline) - ((atom height) / 2) @@ -266,7 +273,12 @@ proc addPadding(line: LineBox, width, height: LayoutUnit, proc addSpacing(line: LineBox, width, height: LayoutUnit, format: ComputedFormat, hang = false) = - let spacing = InlineSpacing(width: width, height: height, baseline: height, format: format) + let spacing = InlineSpacing( + width: width, + height: height, + baseline: height, + format: format + ) spacing.offset.x = line.width if not hang: # In some cases, whitespace may "hang" at the end of the line. This means @@ -274,85 +286,92 @@ proc addSpacing(line: LineBox, width, height: LayoutUnit, line.width += spacing.width line.atoms.add(spacing) -proc flushWhitespace(ictx: InlineContext, computed: CSSComputedValues, hang = false) = - let shift = ictx.computeShift(computed) - ictx.charwidth += ictx.whitespacenum - ictx.whitespacenum = 0 +proc flushWhitespace(state: var InlineState, computed: CSSComputedValues, + hang = false) = + let shift = state.computeShift(computed) + state.charwidth += state.whitespacenum + state.whitespacenum = 0 if shift > 0: - ictx.currentLine.addSpacing(shift, ictx.cellheight, ictx.format, hang) + state.currentLine.addSpacing(shift, state.cellheight, state.format, hang) -proc finishLine(ictx: InlineContext, computed: CSSComputedValues, force = false) = - if ictx.currentLine.atoms.len != 0 or force: +proc finishLine(state: var InlineState, computed: CSSComputedValues, + force = false) = + if state.currentLine.atoms.len != 0 or force: let whitespace = computed{"white-space"} if whitespace == WHITESPACE_PRE: - ictx.flushWhitespace(computed) + state.flushWhitespace(computed) elif whitespace == WHITESPACE_PRE_WRAP: - ictx.flushWhitespace(computed, hang = true) + state.flushWhitespace(computed, hang = true) else: - ictx.whitespacenum = 0 - ictx.verticalAlignLine() - - let line = ictx.currentLine - ictx.lines.add(line) - ictx.height += line.height - ictx.width = max(ictx.width, line.width) - ictx.currentLine = LineBox(offset: Offset(y: line.offset.y + line.height)) - ictx.charwidth = 0 - -proc finish(ictx: InlineContext, computed: CSSComputedValues) = - ictx.finishLine(computed) - for line in ictx.lines: - ictx.horizontalAlignLine(line, computed, line == ictx.lines[^1]) + state.whitespacenum = 0 + state.verticalAlignLine() + + let line = state.currentLine + state.ictx.lines.add(line) + state.ictx.height += line.height + state.ictx.width = max(state.ictx.width, line.width) + state.currentLine = LineBox(offset: Offset(y: line.offset.y + line.height)) + state.charwidth = 0 + +proc finish(state: var InlineState, computed: CSSComputedValues) = + state.finishLine(computed) + if state.ictx.lines.len > 0: + for i in 0 ..< state.ictx.lines.len - 1: + let line = state.ictx.lines[i] + state.horizontalAlignLine(line, computed, last = false) + let line = state.ictx.lines[^1] + state.horizontalAlignLine(line, computed, last = true) func minwidth(atom: InlineAtom): LayoutUnit = if atom of InlineBlockBox: return cast[InlineBlockBox](atom).innerbox.xminwidth return atom.width -func shouldWrap(ictx: InlineContext, w: LayoutUnit, +func shouldWrap(state: InlineState, w: LayoutUnit, pcomputed: CSSComputedValues): bool = if pcomputed != nil and pcomputed.nowrap: return false - if ictx.availableWidth.t == MAX_CONTENT: + if state.availableWidth.t == MAX_CONTENT: return false # no wrap with max-content - if ictx.availableWidth.t == MIN_CONTENT: + if state.availableWidth.t == MIN_CONTENT: return true # always wrap with min-content - return ictx.currentLine.width + w > ictx.availableWidth.u + return state.currentLine.width + w > state.availableWidth.u # pcomputed: computed values of parent, for white-space: pre, line-height. # This isn't necessarily the computed of ictx (e.g. they may differ for nested # inline boxes.) -proc addAtom(ictx: InlineContext, atom: InlineAtom, pcomputed: CSSComputedValues) = - var shift = ictx.computeShift(pcomputed) - ictx.whitespacenum = 0 +proc addAtom(state: var InlineState, atom: InlineAtom, + pcomputed: CSSComputedValues) = + var shift = state.computeShift(pcomputed) + state.whitespacenum = 0 # Line wrapping - if ictx.shouldWrap(atom.width + shift, pcomputed): - ictx.finishLine(pcomputed, false) + if state.shouldWrap(atom.width + shift, pcomputed): + state.finishLine(pcomputed, false) # Recompute on newline - shift = ictx.computeShift(pcomputed) + shift = state.computeShift(pcomputed) if atom.width > 0 and atom.height > 0: if shift > 0: - ictx.currentLine.addSpacing(shift, ictx.cellheight, ictx.format) + state.currentLine.addSpacing(shift, state.cellheight, state.format) - atom.offset.x += ictx.currentLine.width - ictx.minwidth = max(ictx.minwidth, atom.minwidth) - applyLineHeight(ictx.viewport, ictx.currentLine, pcomputed) - ictx.currentLine.width += atom.width + atom.offset.x += state.currentLine.width + state.ictx.minwidth = max(state.ictx.minwidth, atom.minwidth) + applyLineHeight(state.viewport, state.currentLine, pcomputed) + state.currentLine.width += atom.width if atom of InlineWord: - ictx.format = InlineWord(atom).format + state.format = InlineWord(atom).format else: - ictx.charwidth = 0 - ictx.format = nil - ictx.currentLine.atoms.add(atom) + state.charwidth = 0 + state.format = nil + state.currentLine.atoms.add(atom) proc addWord(state: var InlineState) = if state.word.str != "": var word = state.word word.str.mnormalize() #TODO this may break on EOL. - word.height = state.ictx.cellheight + word.height = state.cellheight word.baseline = word.height - state.ictx.addAtom(word, state.computed) + state.addAtom(word, state.computed) state.newWord() proc addWordEOL(state: var InlineState) = @@ -365,78 +384,90 @@ proc addWordEOL(state: var InlineState) = state.hasshy = false state.addWord() state.word.str = leftstr - state.word.width = leftstr.width() * state.ictx.cellwidth + state.word.width = leftstr.width() * state.cellwidth else: state.addWord() # Start a new line, even if the previous one is empty -proc flushLine(ictx: InlineContext, computed: CSSComputedValues) = - applyLineHeight(ictx.viewport, ictx.currentLine, computed) - ictx.finishLine(computed, true) +proc flushLine(state: var InlineState, computed: CSSComputedValues) = + applyLineHeight(state.viewport, state.currentLine, computed) + state.finishLine(computed, true) proc checkWrap(state: var InlineState, r: Rune) = if state.computed.nowrap: return - let shift = state.ictx.computeShift(state.computed) + let shift = state.computeShift(state.computed) let rw = r.width() case state.computed{"word-break"} of WORD_BREAK_NORMAL: if rw == 2 or state.wrappos != -1: # break on cjk and wrap opportunities - let plusWidth = state.word.width + shift + rw * state.ictx.cellwidth - if state.ictx.shouldWrap(plusWidth, nil): - let l = state.ictx.currentLine + let plusWidth = state.word.width + shift + rw * state.cellwidth + if state.shouldWrap(plusWidth, nil): + let l = state.currentLine state.addWordEOL() - if l == state.ictx.currentLine: # no line wrapping occured in addAtom - state.ictx.finishLine(state.computed) - state.ictx.whitespacenum = 0 + if l == state.currentLine: # no line wrapping occured in addAtom + state.finishLine(state.computed) + state.whitespacenum = 0 of WORD_BREAK_BREAK_ALL: - let plusWidth = state.word.width + shift + rw * state.ictx.cellwidth - if state.ictx.shouldWrap(plusWidth, nil): - let l = state.ictx.currentLine + let plusWidth = state.word.width + shift + rw * state.cellwidth + if state.shouldWrap(plusWidth, nil): + let l = state.currentLine state.addWordEOL() - if l == state.ictx.currentLine: # no line wrapping occured in addAtom - state.ictx.finishLine(state.computed) - state.ictx.whitespacenum = 0 + if l == state.currentLine: # no line wrapping occured in addAtom + state.finishLine(state.computed) + state.whitespacenum = 0 of WORD_BREAK_KEEP_ALL: - let plusWidth = state.word.width + shift + rw * state.ictx.cellwidth - if state.ictx.shouldWrap(plusWidth, nil): - state.ictx.finishLine(state.computed) - state.ictx.whitespacenum = 0 + let plusWidth = state.word.width + shift + rw * state.cellwidth + if state.shouldWrap(plusWidth, nil): + state.finishLine(state.computed) + state.whitespacenum = 0 proc processWhitespace(state: var InlineState, c: char) = state.addWord() case state.computed{"white-space"} of WHITESPACE_NORMAL, WHITESPACE_NOWRAP: - state.ictx.whitespacenum = max(state.ictx.whitespacenum, 1) + state.whitespacenum = max(state.whitespacenum, 1) of WHITESPACE_PRE_LINE: if c == '\n': - state.ictx.flushLine(state.computed) + state.flushLine(state.computed) else: - state.ictx.whitespacenum = max(state.ictx.whitespacenum, 1) + state.whitespacenum = max(state.whitespacenum, 1) of WHITESPACE_PRE, WHITESPACE_PRE_WRAP: #TODO whitespace type should be preserved here. (it isn't, because # it would break tabs in the current buffer model.) if c == '\n': - state.ictx.flushLine(state.computed) + state.flushLine(state.computed) elif c == '\t': - let prev = state.ictx.charwidth - state.ictx.charwidth = ((state.ictx.charwidth + - state.ictx.whitespacenum) div 8 + 1) * 8 - state.ictx.whitespacenum - state.ictx.whitespacenum += state.ictx.charwidth - prev + let prev = state.charwidth + state.charwidth = ((state.charwidth + + state.whitespacenum) div 8 + 1) * 8 - state.whitespacenum + state.whitespacenum += state.charwidth - prev else: - inc state.ictx.whitespacenum + inc state.whitespacenum + +func newInlineState(ictx: InlineContext, viewport: Viewport, + availableWidth, availableHeight: SizeConstraint): InlineState = + return InlineState( + currentLine: LineBox(), + ictx: ictx, + viewport: viewport, + availableWidth: availableWidth, + availableHeight: availableHeight + ) -proc layoutText(ictx: InlineContext, str: string, computed: CSSComputedValues, node: StyledNode) = - var state: InlineState +proc layoutText(state: var InlineState, str: string, + computed: CSSComputedValues, node: StyledNode) = + #TODO the lifetime of these is somewhat confusing, maybe move into some + # other object? state.computed = computed - state.ictx = ictx state.node = node - state.ictx.flushWhitespace(state.computed) + + state.flushWhitespace(state.computed) state.newWord() var i = 0 while i < str.len: - if str[i].isWhitespace(): + if str[i] in AsciiWhitespace: state.processWhitespace(str[i]) inc i else: @@ -449,8 +480,8 @@ proc layoutText(ictx: InlineContext, str: string, computed: CSSComputedValues, n else: state.word.str &= r let w = r.width() - state.word.width += w * state.ictx.cellwidth - state.ictx.charwidth += w + state.word.width += w * state.cellwidth + state.charwidth += w if r == Rune('-'): # ascii dash state.wrappos = state.word.str.len state.hasshy = false @@ -793,13 +824,8 @@ proc newInlineBlock(viewport: Viewport, builder: BoxBuilder, ) return box -proc newInlineContext(parent: BlockBox): InlineContext = - return InlineContext( - currentLine: LineBox(), - viewport: parent.viewport, - availableWidth: parent.availableWidth, - availableHeight: parent.availableHeight - ) +proc newInlineContext(): InlineContext = + return InlineContext() proc buildBlock(builder: BlockBoxBuilder, parent: BlockBox): BlockBox proc buildInlines(parent: BlockBox, inlines: seq[BoxBuilder]): InlineContext @@ -875,9 +901,9 @@ func toperc100(sc: SizeConstraint): Option[LayoutUnit] = return none(LayoutUnit) # parentWidth, parentHeight: width/height of the containing block. -proc buildInlineBlock(builder: BlockBoxBuilder, parent: InlineContext, +proc buildInlineBlock(builder: BlockBoxBuilder, viewport: Viewport, parentWidth, parentHeight: SizeConstraint): InlineBlockBox = - result = newInlineBlock(parent.viewport, builder, fitContent(parentWidth), + result = newInlineBlock(viewport, builder, fitContent(parentWidth), maxContent(), parentHeight.toperc100()) case builder.computed{"display"} @@ -902,80 +928,86 @@ proc buildInlineBlock(builder: BlockBoxBuilder, parent: InlineContext, result.width += result.innerbox.margin_left result.width += result.innerbox.margin_right -proc buildInline(ictx: InlineContext, box: InlineBoxBuilder) = +proc buildInline(state: var InlineState, box: InlineBoxBuilder) = + let viewport = state.viewport if box.newline: - ictx.flushLine(box.computed) + state.flushLine(box.computed) let paddingformat = getComputedFormat(box.computed, box.node) if box.splitstart: - let margin_left = box.computed{"margin-left"}.px(ictx.viewport, - ictx.availableWidth) - ictx.currentLine.width += margin_left + let margin_left = box.computed{"margin-left"}.px(viewport, + state.availableWidth) + state.currentLine.width += margin_left - let padding_left = box.computed{"padding-left"}.px(ictx.viewport, - ictx.availableWidth) + let padding_left = box.computed{"padding-left"}.px(viewport, + state.availableWidth) if padding_left > 0: # We must add spacing to the line to make sure that it is formatted # appropriately. # We need this so long as we have no proper inline boxes. - ictx.currentLine.addPadding(padding_left, ictx.cellheight, paddingformat) + state.currentLine.addPadding(padding_left, state.cellheight, + paddingformat) - assert not (box.children.len > 0 and box.text.len > 0) + assert box.children.len == 0 or box.text.len == 0 for text in box.text: - ictx.layoutText(text, box.computed, box.node) + state.layoutText(text, box.computed, box.node) for child in box.children: case child.computed{"display"} of DISPLAY_INLINE: let child = InlineBoxBuilder(child) - ictx.buildInline(child) + state.buildInline(child) of DISPLAY_INLINE_BLOCK, DISPLAY_INLINE_TABLE: let child = BlockBoxBuilder(child) - let w = fitContent(ictx.availableWidth) - let h = ictx.availableHeight - let iblock = child.buildInlineBlock(ictx, w, h) - ictx.addAtom(iblock, box.computed) - ictx.whitespacenum = 0 + let w = fitContent(state.availableWidth) + let h = state.availableHeight + let iblock = child.buildInlineBlock(viewport, w, h) + state.addAtom(iblock, box.computed) + state.whitespacenum = 0 else: assert false, "child.t is " & $child.computed{"display"} if box.splitend: - let padding_right = box.computed{"padding-right"}.px(ictx.viewport, - ictx.availableWidth) - ictx.currentLine.width += padding_right + let padding_right = box.computed{"padding-right"}.px(viewport, + state.availableWidth) + state.currentLine.width += padding_right if padding_right > 0: - ictx.currentLine.addPadding(padding_right, - max(ictx.currentLine.height, 1), paddingformat) - let margin_right = box.computed{"margin-right"}.px(ictx.viewport, - ictx.availableWidth) - ictx.currentLine.width += margin_right + state.currentLine.addPadding(padding_right, + max(state.currentLine.height, 1), paddingformat) + let margin_right = box.computed{"margin-right"}.px(viewport, + state.availableWidth) + state.currentLine.width += margin_right proc buildInlines(parent: BlockBox, inlines: seq[BoxBuilder]): InlineContext = - let ictx = parent.newInlineContext() + let ictx = newInlineContext() + var state = newInlineState(ictx, parent.viewport, parent.availableWidth, + parent.availableHeight) + let viewport = state.viewport if inlines.len > 0: for child in inlines: case child.computed{"display"} of DISPLAY_INLINE: let child = InlineBoxBuilder(child) - ictx.buildInline(child) + state.buildInline(child) of DISPLAY_INLINE_BLOCK, DISPLAY_INLINE_TABLE: #TODO wtf let child = BlockBoxBuilder(child) - let w = fitContent(ictx.availableWidth) - let h = ictx.availableHeight - let iblock = child.buildInlineBlock(ictx, w, h) - ictx.addAtom(iblock, parent.computed) - ictx.whitespacenum = 0 + let w = fitContent(state.availableWidth) + let h = state.availableHeight + let iblock = child.buildInlineBlock(viewport, w, h) + state.addAtom(iblock, parent.computed) + state.whitespacenum = 0 else: assert false, "child.t is " & $child.computed{"display"} - ictx.finish(parent.computed) + state.finish(parent.computed) return ictx proc buildMarker(builder: MarkerBoxBuilder, parent: BlockBox): InlineContext = - let ictx = parent.newInlineContext() - ictx.availableWidth = fitContent(ictx.availableWidth) - ictx.buildInline(builder) - ictx.finish(builder.computed) + let ictx = newInlineContext() + var state = newInlineState(ictx, parent.viewport, + fitContent(parent.availableWidth), parent.availableHeight) + state.buildInline(builder) + state.finish(builder.computed) return ictx proc buildListItem(builder: ListItemBoxBuilder, parent: BlockBox): ListItemBox = |