diff options
author | bptato <nincsnevem662@gmail.com> | 2022-01-19 18:12:02 +0100 |
---|---|---|
committer | bptato <nincsnevem662@gmail.com> | 2022-01-19 18:21:33 +0100 |
commit | bcaaf4e6b68ce1245558bc41559116a7a3296904 (patch) | |
tree | c6d97036f0bd553802917e17a2baf86e67a27d43 /src | |
parent | 0c0aa01a19d5dfb86562650c200cdc8c4b216fa0 (diff) | |
download | chawan-bcaaf4e6b68ce1245558bc41559116a7a3296904.tar.gz |
Re-implement inline blocks
Diffstat (limited to 'src')
-rw-r--r-- | src/css/cascade.nim | 6 | ||||
-rw-r--r-- | src/layout/box.nim | 5 | ||||
-rw-r--r-- | src/layout/engine.nim | 80 | ||||
-rw-r--r-- | src/render/renderdocument.nim | 5 |
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) |