diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/html/dom.nim | 37 | ||||
-rw-r--r-- | src/io/buffer.nim | 88 | ||||
-rw-r--r-- | src/io/cell.nim | 10 | ||||
-rw-r--r-- | src/layout/box.nim | 7 | ||||
-rw-r--r-- | src/layout/engine.nim | 24 | ||||
-rw-r--r-- | src/render/renderdocument.nim | 2 |
6 files changed, 86 insertions, 82 deletions
diff --git a/src/html/dom.nim b/src/html/dom.nim index 5537491c..c3506a72 100644 --- a/src/html/dom.nim +++ b/src/html/dom.nim @@ -129,6 +129,30 @@ iterator textNodes*(node: Node): Text {.inline.} = if node.nodeType == TEXT_NODE: yield Text(node) +# Returns the node's ancestors +iterator ancestors*(node: Node): Element {.inline.} = + var element = node.parentElement + while element != nil: + yield element + element = element.parentElement + +# Returns the node itself and its ancestors +iterator branch*(node: Node): Node {.inline.} = + var node = node + while node != nil: + yield node + node = node.parentElement + +# a == b or b in a's ancestors +func contains*(a, b: Node): bool = + for node in a.branch: + if node == b: return true + return false + +func branch*(node: Node): seq[Node] = + for node in node.branch: + result.add(node) + func firstChild(node: Node): Node = if node.childNodes.len == 0: return nil @@ -223,13 +247,10 @@ func toInputType*(str: string): InputType = of "week": INPUT_WEEK else: INPUT_UNKNOWN -func ancestor(node: Node, tagTypes: set[TagType]): Element = - var elem = node.parentElement - while elem != nil: - if elem.tagType in tagTypes: - return elem - - elem = elem.parentElement +func findAncestor*(node: Node, tagTypes: set[TagType]): Element = + for element in node.ancestors: + if element.tagType in tagTypes: + return element return nil func attr*(element: Element, s: string): string = @@ -247,7 +268,7 @@ proc applyOrdinal*(elem: HTMLLIElement) = if val.issome: elem.ordinalvalue = val.get else: - let owner = elem.ancestor({TAG_OL, TAG_UL, TAG_MENU}) + let owner = elem.findAncestor({TAG_OL, TAG_UL, TAG_MENU}) if owner == nil: elem.ordinalvalue = 1 else: diff --git a/src/io/buffer.nim b/src/io/buffer.nim index a082cfe3..f46b5be0 100644 --- a/src/io/buffer.nim +++ b/src/io/buffer.nim @@ -45,7 +45,7 @@ type streamclosed*: bool source*: string rootbox*: CSSBox - prevnodes*: seq[Node] + prevnode*: Node sourcepair*: Buffer prev*: Buffer next* {.cursor.}: Buffer @@ -197,16 +197,15 @@ func currentDisplayCell(buffer: Buffer): FixedCell = let row = (buffer.cursory - buffer.fromy) * buffer.width return buffer.display[row + buffer.currentCellOrigin()] -func getLink(nodes: seq[Node]): Element = - for node in nodes: - if node.nodeType == ELEMENT_NODE: - let elem = Element(node) - if elem.tagType == TAG_A: - return elem - return nil +func getLink(node: Node): Element = + if node == nil: + return nil + if node.nodeType == ELEMENT_NODE and Element(node).tagType == TAG_A: + return Element(node) + return node.findAncestor({TAG_A}) func getCursorLink(buffer: Buffer): Element = - return buffer.currentDisplayCell().nodes.getLink() + return buffer.currentDisplayCell().node.getLink() func currentLine(buffer: Buffer): string = return buffer.lines[buffer.cursory].str @@ -311,7 +310,7 @@ proc refreshDisplay(buffer: Buffer) = buffer.display[dls + k].runes.add(r) if cf.pos != -1: buffer.display[dls + k].formatting = cf.formatting - buffer.display[dls + k].nodes = cf.nodes + buffer.display[dls + k].node = cf.node let tk = k + r.width() while k < tk and k < buffer.width - 1: inc k @@ -476,12 +475,12 @@ proc cursorNextLink*(buffer: Buffer) = var i = line.findFormatN(buffer.currentCursorBytes()) - 1 var link: Element = nil if i >= 0: - link = line.formats[i].nodes.getLink() + link = line.formats[i].node.getLink() inc i while i < line.formats.len: let format = line.formats[i] - let fl = format.nodes.getLink() + let fl = format.node.getLink() if fl != nil and fl != link: buffer.setCursorXB(format.pos) return @@ -492,7 +491,7 @@ proc cursorNextLink*(buffer: Buffer) = i = 0 while i < line.formats.len: let format = line.formats[i] - let fl = format.nodes.getLink() + let fl = format.node.getLink() if fl != nil and fl != link: buffer.setCursorXBY(format.pos, y) return @@ -503,12 +502,12 @@ proc cursorPrevLink*(buffer: Buffer) = var i = line.findFormatN(buffer.currentCursorBytes()) - 1 var link: Element = nil if i >= 0: - link = line.formats[i].nodes.getLink() + link = line.formats[i].node.getLink() dec i while i >= 0: let format = line.formats[i] - let fl = format.nodes.getLink() + let fl = format.node.getLink() if fl != nil and fl != link: buffer.setCursorXB(format.pos) return @@ -519,7 +518,7 @@ proc cursorPrevLink*(buffer: Buffer) = i = line.formats.len - 1 while i >= 0: let format = line.formats[i] - let fl = format.nodes.getLink() + let fl = format.node.getLink() if fl != nil and fl != link: #go to beginning of link var ly = y #last y @@ -529,7 +528,7 @@ proc cursorPrevLink*(buffer: Buffer) = i = line.formats.len - 1 while i >= 0: let format = line.formats[i] - let nl = format.nodes.getLink() + let nl = format.node.getLink() if nl == fl: ly = iy lx = format.pos @@ -652,7 +651,7 @@ proc gotoAnchor*(buffer: Buffer) = var i = 0 while i < line.formats.len: let format = line.formats[i] - if anchor in format.nodes: + if anchor in format.node: buffer.setCursorY(y) buffer.centerLine() buffer.setCursorXB(format.pos) @@ -680,38 +679,35 @@ proc updateCursor(buffer: Buffer) = buffer.cursory = 0 proc updateHover(buffer: Buffer) = - let nodes = buffer.currentDisplayCell().nodes - if nodes != buffer.prevnodes: - for node in nodes: - var elem: Element - if node of Element: - elem = Element(node) - else: - elem = node.parentElement - assert elem != nil - - if not elem.hover and not (node in buffer.prevnodes): - elem.hover = true - buffer.reshape = true - elem.refreshStyle() - let link = nodes.getLink() + let thisnode = buffer.currentDisplayCell().node + let prevnode = buffer.prevnode + + if thisnode != prevnode: + for node in thisnode.branch: + if node.nodeType == ELEMENT_NODE: + let elem = Element(node) + if not elem.hover and node notin prevnode: + elem.hover = true + buffer.reshape = true + elem.refreshStyle() + + let link = thisnode.getLink() if link != nil: if link.tagType == TAG_A: - buffer.hovertext = parseUrl(HTMLAnchorElement(link).href, buffer.location.some).serialize() + let anchor = HTMLAnchorElement(link) + buffer.hovertext = parseUrl(anchor.href, buffer.location.some).serialize() else: buffer.hovertext = "" - for node in buffer.prevnodes: - var elem: Element - if node of Element: - elem = Element(node) - else: - elem = node.parentElement - assert elem != nil - if elem.hover and not (node in nodes): - elem.hover = false - buffer.reshape = true - elem.refreshStyle() - buffer.prevnodes = nodes + + for node in prevnode.branch: + if node.nodeType == ELEMENT_NODE: + let elem = Element(node) + if elem.hover and node notin thisnode: + elem.hover = false + buffer.reshape = true + elem.refreshStyle() + + buffer.prevnode = thisnode proc loadResources(buffer: Buffer, document: Document) = for elem in document.head.children: diff --git a/src/io/cell.nim b/src/io/cell.nim index fbe35268..b783d180 100644 --- a/src/io/cell.nim +++ b/src/io/cell.nim @@ -24,7 +24,7 @@ type Cell* = object of RootObj formatting*: Formatting - nodes*: seq[Node] + node*: Node FormattingCell* = object of Cell pos*: int @@ -64,7 +64,7 @@ template `overline=`*(f: var Formatting, b: bool) = flag_template f, b, FLAG_OVE func `==`*(a: FixedCell, b: FixedCell): bool = return a.formatting == b.formatting and a.runes == b.runes and - a.nodes == b.nodes + a.node == b.node func newFixedGrid*(w: int, h: int = 1): FixedGrid = return newSeq[FixedCell](w * h) @@ -128,7 +128,7 @@ proc setLen*(line: var FlexibleLine, len: int) = proc add*(a: var FlexibleLine, b: FlexibleLine) = let l = a.str.len - a.formats.add(b.formats.map((x) => FormattingCell(formatting: x.formatting, nodes: x.nodes, pos: l + x.pos))) + a.formats.add(b.formats.map((x) => FormattingCell(formatting: x.formatting, node: x.node, pos: l + x.pos))) a.str &= b.str proc addLine*(grid: var FlexibleGrid) = @@ -140,8 +140,8 @@ proc addFormat*(line: var FlexibleLine, pos: int, format: Formatting) = proc addFormat*(grid: var FlexibleGrid, y, pos: int, format: Formatting) = grid[y].formats.add(FormattingCell(formatting: format, pos: grid[y].str.len)) -proc addFormat*(grid: var FlexibleGrid, y, pos: int, format: Formatting, nodes: seq[Node]) = - grid[y].formats.add(FormattingCell(formatting: format, nodes: nodes, pos: pos)) +proc addFormat*(grid: var FlexibleGrid, y, pos: int, format: Formatting, node: Node) = + grid[y].formats.add(FormattingCell(formatting: format, node: node, pos: pos)) proc addCell*(grid: var FlexibleGrid, y: int, r: Rune) = grid[y].str &= $r diff --git a/src/layout/box.nim b/src/layout/box.nim index 07dce0ed..d0cf99c4 100644 --- a/src/layout/box.nim +++ b/src/layout/box.nim @@ -7,7 +7,7 @@ import io/term type Viewport* = ref object term*: TermAttributes - nodes*: seq[Node] + node*: Node root*: BlockBox map*: seq[CSSBox] @@ -18,7 +18,6 @@ type specified*: CSSSpecifiedValues node*: Node element*: Element - nodes*: seq[Node] InlineAtom* = ref object of RootObj relx*: int @@ -31,7 +30,7 @@ type fontweight*: int textdecoration*: CSSTextDecoration color*: CSSColor - nodes*: seq[Node] + node*: Node InlineRow* = ref object atoms*: seq[InlineAtom] @@ -50,7 +49,7 @@ type whitespace*: bool maxwidth*: int viewport*: Viewport - nodes*: seq[Node] + node*: Node BlockContext* = ref object of InlineAtom inline*: InlineContext diff --git a/src/layout/engine.nim b/src/layout/engine.nim index 10cc1374..441f6233 100644 --- a/src/layout/engine.nim +++ b/src/layout/engine.nim @@ -26,7 +26,7 @@ func px(l: CSSLength, state: Viewport, p = 0): int {.inline.} = type InlineState = object ictx: InlineContext skip: bool - nodes: seq[Node] + node: Node word: InlineWord maxwidth: int specified: CSSSpecifiedValues @@ -58,7 +58,7 @@ proc newWord(state: var InlineState) = word.fontstyle = specified{"font-style"} word.fontweight = specified{"font-weight"} word.textdecoration = specified{"text-decoration"} - word.nodes = state.nodes + word.node = state.node state.word = word proc finishRow(ictx: InlineContext) = @@ -128,12 +128,12 @@ proc processWhitespace(state: var InlineState, c: char) = else: state.ictx.whitespace = true -proc renderText*(ictx: InlineContext, str: string, maxwidth: int, specified: CSSSpecifiedValues, nodes: seq[Node]) = +proc renderText*(ictx: InlineContext, str: string, maxwidth: int, specified: CSSSpecifiedValues, node: Node) = var state: InlineState state.specified = specified state.ictx = ictx state.maxwidth = maxwidth - state.nodes = nodes + state.node = node state.newWord() #if str.strip().len > 0: @@ -271,16 +271,13 @@ proc alignInlineBlock(bctx: BlockContext, box: InlineBlockBox, parentcss: CSSSpe box.ictx.whitespace = false proc alignInline(bctx: BlockContext, box: InlineBox) = - if box.node != nil: - bctx.viewport.nodes.add(box.node) - let box = InlineBox(box) assert box.ictx != nil if box.newline: box.ictx.flushLine() for text in box.text: assert box.children.len == 0 - box.ictx.renderText(text, bctx.compwidth, box.specified, box.nodes) + box.ictx.renderText(text, bctx.compwidth, box.specified, box.node) for child in box.children: case child.t @@ -294,8 +291,6 @@ proc alignInline(bctx: BlockContext, box: InlineBox) = bctx.alignInlineBlock(child, box.specified) else: assert false, "child.t is " & $child.t - if box.node != nil: - discard bctx.viewport.nodes.pop() proc alignInlines(bctx: BlockContext, inlines: seq[CSSBox]) = let ictx = bctx.newInlineContext() @@ -341,14 +336,11 @@ proc alignBlocks(bctx: BlockContext, blocks: seq[CSSBox], blockgroup: var seq[CS alignBlock(child) of DISPLAY_INLINE: if child.inlinelayout: - child.nodes = bctx.viewport.nodes blockgroup.add(child) else: if child.node != nil: - bctx.viewport.nodes.add(child.node) + bctx.viewport.node = 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) @@ -357,8 +349,6 @@ proc alignBlocks(bctx: BlockContext, blocks: seq[CSSBox], blockgroup: var seq[CS proc alignBlock(box: BlockBox) = if box.bctx.done: return - if box.node != nil: - box.bctx.viewport.nodes.add(box.node) if box.inlinelayout: # Box only contains inline boxes. box.bctx.alignInlines(box.children) @@ -368,8 +358,6 @@ proc alignBlock(box: BlockBox) = let bctx = box.bctx flush_group() box.bctx.arrangeBlocks() - if box.node != nil: - discard box.bctx.viewport.nodes.pop() box.bctx.done = true proc getBox(specified: CSSSpecifiedValues): CSSBox = diff --git a/src/render/renderdocument.nim b/src/render/renderdocument.nim index 2ff46488..6765853b 100644 --- a/src/render/renderdocument.nim +++ b/src/render/renderdocument.nim @@ -48,7 +48,7 @@ proc setRowWord(lines: var FlexibleGrid, word: InlineWord, x, y: int, term: Term let oformats = lines[y].formats.subformats(i) lines[y].setLen(i) - lines.addFormat(y, i, word.formatFromWord(), word.nodes) + lines.addFormat(y, i, word.formatFromWord(), word.node) var nx = cx if nx < x: |