diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/css/select.nim | 11 | ||||
-rw-r--r-- | src/layout/box.nim | 2 | ||||
-rw-r--r-- | src/layout/engine.nim | 72 |
3 files changed, 49 insertions, 36 deletions
diff --git a/src/css/select.nim b/src/css/select.nim index 3a2e0e27..1bd45dcd 100644 --- a/src/css/select.nim +++ b/src/css/select.nim @@ -32,15 +32,12 @@ func attrSelectorMatches(elem: Element, sel: Selector): bool = of '*': return elem.attr(sel.attr).contains(sel.value) else: return false -func pseudoElemSelectorMatches(elem: Element, s: string): SelectResult = - case s +func pseudoElemSelectorMatches(elem: Element, sel: Selector): SelectResult = + case sel.elem of "before": return selectres(true, PSEUDO_BEFORE) of "after": return selectres(true, PSEUDO_AFTER) else: return selectres(false) -func pseudoElemSelectorMatches(elem: Element, sel: Selector): SelectResult = - return elem.pseudoElemSelectorMatches(sel.elem) - func pseudoSelectorMatches(elem: Element, sel: Selector): SelectResult = case sel.pseudo of "first-child": return selectres(elem.parentNode.firstElementChild == elem) @@ -48,7 +45,9 @@ func pseudoSelectorMatches(elem: Element, sel: Selector): SelectResult = of "only-child": return selectres(elem.parentNode.firstElementChild == elem and elem.parentNode.lastElementChild == elem) of "hover": return selectres(elem.hover) of "root": return selectres(elem == elem.ownerDocument.root) - else: return elem.pseudoElemSelectorMatches(sel.pseudo) + of "before": return selectres(true, PSEUDO_BEFORE) + of "after": return selectres(true, PSEUDO_AFTER) + else: return selectres(false) func selectorsMatch*(elem: Element, selectors: SelectorList): SelectResult diff --git a/src/layout/box.nim b/src/layout/box.nim index 48265fde..07dce0ed 100644 --- a/src/layout/box.nim +++ b/src/layout/box.nim @@ -18,6 +18,7 @@ type specified*: CSSSpecifiedValues node*: Node element*: Element + nodes*: seq[Node] InlineAtom* = ref object of RootObj relx*: int @@ -49,6 +50,7 @@ type whitespace*: bool maxwidth*: int viewport*: Viewport + nodes*: seq[Node] BlockContext* = ref object of InlineAtom inline*: InlineContext diff --git a/src/layout/engine.nim b/src/layout/engine.nim index f8ccc956..10cc1374 100644 --- a/src/layout/engine.nim +++ b/src/layout/engine.nim @@ -280,7 +280,7 @@ proc alignInline(bctx: BlockContext, box: InlineBox) = box.ictx.flushLine() for text in box.text: assert box.children.len == 0 - box.ictx.renderText(text, bctx.compwidth, box.specified, bctx.viewport.nodes) + box.ictx.renderText(text, bctx.compwidth, box.specified, box.nodes) for child in box.children: case child.t @@ -321,20 +321,17 @@ proc alignInlines(bctx: BlockContext, inlines: seq[CSSBox]) = bctx.margin_top = bctx.specified{"margin-top"}.px(bctx.viewport, bctx.compwidth) bctx.margin_bottom = bctx.specified{"margin-bottom"}.px(bctx.viewport, bctx.compwidth) -proc alignBlocks(bctx: BlockContext, blocks: seq[CSSBox]) = +template flush_group() = + if blockgroup.len > 0: + let gctx = newBlockContext(bctx) + gctx.alignInlines(blockgroup) + blockgroup.setLen(0) + bctx.nested.add(gctx) + +proc alignBlocks(bctx: BlockContext, blocks: seq[CSSBox], blockgroup: var seq[CSSBox], node: Node) = # Box contains block boxes. # If present, group inline boxes together in anonymous block boxes. Place # block boxes inbetween these. - var blockgroup: seq[CSSBox] - var has_noinline = false - - template flush_group() = - if blockgroup.len > 0: - let gctx = newBlockContext(bctx) - gctx.alignInlines(blockgroup) - blockgroup.setLen(0) - bctx.nested.add(gctx) - for child in blocks: case child.t of DISPLAY_BLOCK, DISPLAY_LIST_ITEM: @@ -344,15 +341,18 @@ proc alignBlocks(bctx: BlockContext, blocks: seq[CSSBox]) = alignBlock(child) of DISPLAY_INLINE: if child.inlinelayout: + child.nodes = bctx.viewport.nodes blockgroup.add(child) else: - flush_group() - bctx.alignBlocks(child.children) + if child.node != nil: + bctx.viewport.nodes.add(child.node) + bctx.alignBlocks(child.children, blockgroup, child.node) + if child.node != nil: + discard bctx.viewport.nodes.pop() #eprint "put" of DISPLAY_INLINE_BLOCK: blockgroup.add(child) else: discard #TODO - flush_group() proc alignBlock(box: BlockBox) = if box.bctx.done: @@ -363,7 +363,10 @@ proc alignBlock(box: BlockBox) = # Box only contains inline boxes. box.bctx.alignInlines(box.children) else: - box.bctx.alignBlocks(box.children) + var blockgroup: seq[CSSBox] + box.bctx.alignBlocks(box.children, blockgroup, box.node) + let bctx = box.bctx + flush_group() box.bctx.arrangeBlocks() if box.node != nil: discard box.bctx.viewport.nodes.pop() @@ -403,9 +406,15 @@ proc getPseudoBox(bctx: BlockContext, specified: CSSSpecifiedValues): CSSBox = if box == nil: return nil - if specified{"display"} in {DISPLAY_BLOCK, DISPLAY_LIST_ITEM}: + case box.specified{"display"} + of DISPLAY_BLOCK, DISPLAY_LIST_ITEM: let box = BlockBox(box) box.bctx = bctx.newBlockContext(box) + of DISPLAY_INLINE_BLOCK: + let box = InlineBlockBox(box) + box.bctx = bctx.newInlineBlockContext(box) + else: + discard box.inlinelayout = true if specified{"content"}.len > 0: @@ -480,9 +489,17 @@ proc generateBox(elem: Element, viewport: Viewport, bctx: BlockContext = nil): C if elem.tagType == TAG_LI: ordinalvalue = HTMLLIElement(elem).ordinalvalue let marker = box.getTextBox() + marker.node = elem marker.text.add(elem.css{"list-style-type"}.listMarker(ordinalvalue)) add_box(marker) + let before = elem.pseudo[PSEUDO_BEFORE] + if before != nil: + let bbox = bctx.getPseudoBox(before) + if bbox != nil: + bbox.node = elem + add_box(bbox) + for child in elem.childNodes: case child.nodeType of ELEMENT_NODE: @@ -492,22 +509,9 @@ proc generateBox(elem: Element, viewport: Viewport, bctx: BlockContext = nil): C ibox = box.getTextBox() ibox.newline = true - let before = elem.pseudo[PSEUDO_BEFORE] - if before != nil: - let bbox = bctx.getPseudoBox(before) - bbox.node = elem - if bbox != nil: - add_box(bbox) - let cbox = elem.generateBox(viewport, bctx) if cbox != nil: add_box(cbox) - - let after = elem.pseudo[PSEUDO_AFTER] - if after != nil: - let abox = bctx.getPseudoBox(after) - if abox != nil: - add_box(abox) of TEXT_NODE: let text = Text(child) # Don't generate empty anonymous inline blocks between block boxes @@ -517,10 +521,18 @@ proc generateBox(elem: Element, viewport: Viewport, bctx: BlockContext = nil): C not text.data.onlyWhitespace(): if ibox == nil: ibox = box.getTextBox() + ibox.node = elem ibox.text.add(text.data) else: discard add_ibox() + let after = elem.pseudo[PSEUDO_AFTER] + if after != nil: + let abox = bctx.getPseudoBox(after) + if abox != nil: + abox.node = elem + add_box(abox) + viewport.map[elem.uid] = box return box |