diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/css/cascade.nim | 205 | ||||
-rw-r--r-- | src/css/stylednode.nim | 18 | ||||
-rw-r--r-- | src/css/values.nim | 6 | ||||
-rw-r--r-- | src/html/dom.nim | 42 | ||||
-rw-r--r-- | src/io/buffer.nim | 6 | ||||
-rw-r--r-- | src/layout/engine.nim | 157 | ||||
-rw-r--r-- | src/render/renderdocument.nim | 16 |
7 files changed, 261 insertions, 189 deletions
diff --git a/src/css/cascade.nim b/src/css/cascade.nim index 8a52cc58..d71a3dab 100644 --- a/src/css/cascade.nim +++ b/src/css/cascade.nim @@ -2,13 +2,15 @@ import algorithm import streams import sugar -import css/mediaquery import css/cssparser +import css/mediaquery import css/select import css/selectorparser import css/sheet +import css/stylednode import css/values import html/dom +import html/tags type ApplyResult = object @@ -32,6 +34,17 @@ proc applyProperty(elem: Element, d: CSSDeclaration, pseudo: PseudoElem) = elem.cssapplied = true +proc applyProperty(styledNode: StyledNode, parent: CSSComputedValues, d: CSSDeclaration) = + + styledNode.computed.applyValue(parent, d) + #else: + #if styled.pseudo[pseudo] == nil: + # elem.pseudo[pseudo] = elem.css.inheritProperties() + #elem.pseudo[pseudo].applyValue(elem.css, d) + + if styledNode.node != nil: + Element(styledNode.node).cssapplied = true + func applies(mq: MediaQuery): bool = case mq.t of CONDITION_MEDIA: @@ -144,6 +157,58 @@ proc applyDeclarations(element: Element, ua, user: DeclarationList, author: seq[ for rule in ares.important: element.applyProperty(rule, pseudo) +# Always returns a new styled node, with the passed declarations applied. +proc applyDeclarations(elem: Element, parent: CSSComputedValues, ua, user: DeclarationList, author: seq[DeclarationList]): StyledNode = + let pseudo = PSEUDO_NONE + var ares: ApplyResult + + ares.applyNormal(ua[pseudo]) + ares.applyNormal(user[pseudo]) + for rule in author: + ares.applyNormal(rule[pseudo]) + + for rule in author: + ares.applyImportant(rule[pseudo]) + + let style = Element(elem).attr("style") + if style.len > 0: + let inline_rules = newStringStream(style).parseListOfDeclarations2() + ares.applyNormal(inline_rules) + ares.applyImportant(inline_rules) + + ares.applyImportant(user[pseudo]) + ares.applyImportant(ua[pseudo]) + + result = StyledNode(t: STYLED_ELEMENT, node: elem, computed: parent.inheritProperties()) + for rule in ares.normal: + result.applyProperty(parent, rule) + + for rule in ares.important: + result.applyProperty(parent, rule) + +# Either returns a new styled node or nil. +proc applyDeclarations(pseudo: PseudoElem, parent: CSSComputedValues, ua, user: DeclarationList, author: seq[DeclarationList]): StyledNode = + var ares: ApplyResult + + ares.applyNormal(ua[pseudo]) + ares.applyNormal(user[pseudo]) + for rule in author: + ares.applyNormal(rule[pseudo]) + + for rule in author: + ares.applyImportant(rule[pseudo]) + + ares.applyImportant(user[pseudo]) + ares.applyImportant(ua[pseudo]) + + if ares.normal.len > 0 or ares.important.len > 0: + result = StyledNode(t: STYLED_ELEMENT, node: nil, computed: parent.inheritProperties(), pseudo: pseudo) + for rule in ares.normal: + result.applyProperty(parent, rule) + + for rule in ares.important: + result.applyProperty(parent, rule) + func applyMediaQuery(ss: CSSStylesheet): CSSStylesheet = result = ss for mq in ss.mq_list: @@ -159,7 +224,7 @@ proc resetRules(elem: Element) = for pseudo in PSEUDO_BEFORE..PSEUDO_AFTER: elem.pseudo[pseudo] = nil -proc applyRules(elem: Element, ua, user: CSSStylesheet, author: seq[CSSStylesheet]) {.inline.} = +proc applyRules(elem: Element, ua, user: CSSStylesheet, author: seq[CSSStylesheet]) = let uadecls = calcRules(elem, ua) let userdecls = calcRules(elem, user) var authordecls: seq[DeclarationList] @@ -169,49 +234,129 @@ proc applyRules(elem: Element, ua, user: CSSStylesheet, author: seq[CSSStyleshee for pseudo in PseudoElem: elem.applyDeclarations(uadecls, userdecls, authordecls, pseudo) -proc applyRules(document: Document, ua, user: CSSStylesheet) = +func calcRules(elem: Element, ua, user: CSSStylesheet, author: seq[CSSStylesheet]): tuple[uadecls, userdecls: DeclarationList, authordecls: seq[DeclarationList]] = + result.uadecls = calcRules(elem, ua) + result.userdecls = calcRules(elem, user) + for rule in author: + result.authordecls.add(calcRules(elem, rule)) + +proc applyStyle(parent: StyledNode, elem: Element, uadecls, userdecls: DeclarationList, authordecls: seq[DeclarationList]): StyledNode = + let parentComputed = if parent != nil: + parent.computed + else: + rootProperties() + + result = elem.applyDeclarations(parentComputed, uadecls, userdecls, authordecls) + assert result != nil + +proc applyRules(document: Document, ua, user: CSSStylesheet, previousStyled: StyledNode): StyledNode = + if document.html == nil: + return + var author: seq[CSSStylesheet] if document.head != nil: for sheet in document.head.sheets: author.add(sheet) - var stack: seq[Element] - - if document.html != nil: - stack.add(document.html) - var lenstack = newSeqOfCap[int](15) + var lenstack = newSeqOfCap[int](256) + var styledStack: seq[(StyledNode, Node, PseudoElem, StyledNode)] + if previousStyled != nil: + styledStack.add((nil, document.html, PSEUDO_NONE, previousStyled)) + else: + styledStack.add((nil, document.html, PSEUDO_NONE, nil)) - while stack.len > 0: - let elem = stack.pop() + #TODO TODO TODO this can't work as we currently store cached children in the + # same seq we use for storing new children... + # For now we just reset previous children which effectively disables caching. + while styledStack.len > 0: + let (styledParent, child, pseudo, cachedChild) = styledStack.pop() # Remove stylesheets on nil - if elem == nil: + if pseudo == PSEUDO_NONE and child == nil: let len = lenstack.pop() author.setLen(author.len - len) continue - if not elem.cssapplied: - let prev = elem.css - let ppseudo = elem.pseudo - elem.resetRules() - elem.applyRules(ua, user, author) - elem.checkRendered(prev, ppseudo) - - # Add nil before the last element (in-stack), so we can remove the - # stylesheets - if elem.sheets.len > 0: - author.add(elem.sheets) - lenstack.add(elem.sheets.len) - stack.add(nil) - - for i in countdown(elem.children.high, 0): - stack.add(elem.children[i]) - -proc applyStylesheets*(document: Document, uass, userss: CSSStylesheet) = + template stack_append(styledParent: StyledNode, child: Node) = + if child.nodeType != ELEMENT_NODE or Element(child).cssapplied: + var cachedChild: StyledNode + for it in styledParent.children: + if it.node == child: + cachedChild = it + break + styledStack.add((styledParent, child, PSEUDO_NONE, cachedChild)) + else: + eprint "else branch" + styledStack.add((styledParent, child, PSEUDO_NONE, nil)) + + template stack_append(styledParent: StyledNode, ps: PseudoElem) = + if Element(styledParent.node).cssapplied: + var cachedChild: StyledNode + for it in styledParent.children: + if it.t == STYLED_ELEMENT and it.pseudo == ps: + cachedChild = it + break + styledStack.add((styledParent, nil, ps, cachedChild)) + else: + eprint "else branch 2" + styledStack.add((styledParent, nil, ps, nil)) + + var styledChild: StyledNode + if cachedChild != nil: + styledChild = cachedChild + if styledParent == nil: + result = styledChild + else: + styledParent.children.add(styledChild) + styledChild.children.setLen(0) + else: + if pseudo != PSEUDO_NONE: + let (ua, user, authordecls) = Element(styledParent.node).calcRules(ua, user, author) + let styledPseudo = pseudo.applyDeclarations(styledParent.computed, ua, user, authordecls) + if styledPseudo != nil: + styledParent.children.add(styledPseudo) + let content = styledPseudo.computed{"content"} + if content.len > 0: + styledPseudo.children.add(StyledNode(t: STYLED_TEXT, text: content)) + else: + assert child != nil + if styledParent != nil: + if child.nodeType == ELEMENT_NODE: + let (ua, user, authordecls) = Element(child).calcRules(ua, user, author) + styledChild = applyStyle(styledParent, Element(child), ua, user, authordecls) + styledParent.children.add(styledChild) + elif child.nodeType == TEXT_NODE: + let text = Text(child) + styledChild = StyledNode(t: STYLED_TEXT, node: child, text: text.data) + styledParent.children.add(styledChild) + else: + # Root element + assert result == nil + let (ua, user, authordecls) = Element(child).calcRules(ua, user, author) + styledChild = applyStyle(styledParent, Element(child), ua, user, authordecls) + result = styledChild + + if styledChild != nil and styledChild.node != nil and styledChild.node.nodeType == ELEMENT_NODE: + let elem = Element(styledChild.node) + # Add a nil before the last element (in-stack), so we can remove the + # stylesheets + if elem.sheets.len > 0: + author.add(elem.sheets) + lenstack.add(elem.sheets.len) + styledStack.add((nil, nil, PSEUDO_NONE, nil)) + + stack_append styledChild, PSEUDO_AFTER + + for i in countdown(elem.childNodes.high, 0): + stack_append styledChild, elem.childNodes[i] + + stack_append styledChild, PSEUDO_BEFORE + +proc applyStylesheets*(document: Document, uass, userss: CSSStylesheet, previousStyled: StyledNode): StyledNode = let uass = uass.applyMediaQuery() let userss = userss.applyMediaQuery() - document.applyRules(uass, userss) + return document.applyRules(uass, userss, previousStyled) proc refreshStyle*(elem: Element) = elem.cssapplied = false diff --git a/src/css/stylednode.nim b/src/css/stylednode.nim new file mode 100644 index 00000000..d6293187 --- /dev/null +++ b/src/css/stylednode.nim @@ -0,0 +1,18 @@ +import css/values +import html/dom + +# Container to hold a style and a node. +# Pseudo elements are implemented using StyledNode objects without nodes. +type + StyledType* = enum + STYLED_ELEMENT, STYLED_TEXT + + StyledNode* = ref object + case t*: StyledType + of STYLED_ELEMENT: + pseudo*: PseudoElem + computed*: CSSComputedValues + of STYLED_TEXT: + text*: string + node*: Node + children*: seq[StyledNode] diff --git a/src/css/values.nim b/src/css/values.nim index 73299f9e..e78af603 100644 --- a/src/css/values.nim +++ b/src/css/values.nim @@ -110,7 +110,7 @@ type of VALUE_DISPLAY: display*: CSSDisplay of VALUE_CONTENT: - content*: seq[Rune] + content*: string of VALUE_WHITESPACE: whitespace*: CSSWhitespace of VALUE_INTEGER: @@ -603,12 +603,12 @@ func cssGlobal*(d: CSSDeclaration): CSSGlobalValueType = of "revert": return VALUE_REVERT return VALUE_NOGLOBAL -func cssString(d: CSSDeclaration): seq[Rune] = +func cssString(d: CSSDeclaration): string = if isToken(d): let tok = getToken(d) case tok.tokenType of CSS_IDENT_TOKEN, CSS_STRING_TOKEN: - return tok.value + return $tok.value else: return func cssDisplay(d: CSSDeclaration): CSSDisplay = diff --git a/src/html/dom.nim b/src/html/dom.nim index 8562caa0..6dbfcc0f 100644 --- a/src/html/dom.nim +++ b/src/html/dom.nim @@ -122,18 +122,14 @@ type HTMLBRElement* = ref object of HTMLElement HTMLMenuElement* = ref object of HTMLElement - ordinalcounter*: int HTMLUListElement* = ref object of HTMLElement - ordinalcounter*: int HTMLOListElement* = ref object of HTMLElement start*: Option[int] - ordinalcounter*: int HTMLLIElement* = ref object of HTMLElement value*: Option[int] - ordinalvalue*: int HTMLStyleElement* = ref object of HTMLElement sheet*: CSSStylesheet @@ -508,14 +504,14 @@ func newText*(document: Document, data: string = ""): Text = result.nodeType = TEXT_NODE result.document = document result.data = data - result.rootNode = result + result.rootNode = result #TODO apparently we shouldn't be doing this func newComment*(document: Document, data: string = ""): Comment = new(result) result.nodeType = COMMENT_NODE result.document = document result.data = data - result.rootNode = result + result.rootNode = result #TODO apparently we shouldn't be doing this # note: we do not implement custom elements func newHTMLElement*(document: Document, tagType: TagType, namespace = Namespace.HTML, prefix = none[string]()): HTMLElement = @@ -538,10 +534,8 @@ func newHTMLElement*(document: Document, tagType: TagType, namespace = Namespace result = new(HTMLOListElement) of TAG_UL: result = new(HTMLUListElement) - HTMLUListElement(result).ordinalcounter = 1 of TAG_MENU: result = new(HTMLMenuElement) - HTMLMenuElement(result).ordinalcounter = 1 of TAG_LI: result = new(HTMLLIElement) of TAG_STYLE: @@ -567,7 +561,7 @@ func newHTMLElement*(document: Document, tagType: TagType, namespace = Namespace result.css = rootProperties() result.namespace = namespace result.namespacePrefix = prefix - result.rootNode = result + result.rootNode = result #TODO apparently we shouldn't be doing this result.document = document func newHTMLElement*(document: Document, localName: string, namespace = Namespace.HTML, prefix = none[string](), tagType = tagType(localName)): Element = @@ -578,7 +572,7 @@ func newHTMLElement*(document: Document, localName: string, namespace = Namespac func newDocument*(): Document = new(result) result.nodeType = DOCUMENT_NODE - result.rootNode = result + result.rootNode = result #TODO apparently we shouldn't be doing this result.document = result func newDocumentType*(document: Document, name: string, publicId = "", systemId = ""): DocumentType = @@ -587,7 +581,7 @@ func newDocumentType*(document: Document, name: string, publicId = "", systemId result.name = name result.publicId = publicId result.systemId = systemId - result.rootNode = result + result.rootNode = result #TODO apparently we shouldn't be doing this func newAttr*(parent: Element, key, value: string): Attr = new(result) @@ -596,7 +590,7 @@ func newAttr*(parent: Element, key, value: string): Attr = result.ownerElement = parent result.name = key result.value = value - result.rootNode = result + result.rootNode = result #TODO apparently we shouldn't be doing this func getElementById*(document: Document, id: string): Element = if id.len == 0: @@ -781,30 +775,6 @@ proc preInsert*(parent, node, before: Node) = proc append*(parent, node: Node) = parent.preInsert(node, nil) -proc applyOrdinal*(elem: HTMLLIElement) = - let val = elem.attri("value") - if val.issome: - elem.ordinalvalue = val.get - else: - let owner = elem.findAncestor({TAG_OL, TAG_UL, TAG_MENU}) - if owner == nil: - elem.ordinalvalue = 1 - else: - case owner.tagType - of TAG_OL: - let ol = HTMLOListElement(owner) - elem.ordinalvalue = ol.ordinalcounter - inc ol.ordinalcounter - of TAG_UL: - let ul = HTMLUListElement(owner) - elem.ordinalvalue = ul.ordinalcounter - inc ul.ordinalcounter - of TAG_MENU: - let menu = HTMLMenuElement(owner) - elem.ordinalvalue = menu.ordinalcounter - inc menu.ordinalcounter - else: discard - proc reset*(element: Element) = case element.tagType of TAG_INPUT: diff --git a/src/io/buffer.nim b/src/io/buffer.nim index e329b777..9fa23fe6 100644 --- a/src/io/buffer.nim +++ b/src/io/buffer.nim @@ -8,6 +8,7 @@ import unicode import css/cascade import css/sheet +import css/stylednode import html/dom import html/tags import html/htmlparser @@ -40,6 +41,7 @@ type attrs*: TermAttributes document*: Document viewport*: Viewport + prevstyled*: StyledNode redraw*: bool reshape*: bool nostatus*: bool @@ -754,7 +756,9 @@ proc render*(buffer: Buffer) = of "text/html": if buffer.viewport == nil: buffer.viewport = Viewport(term: buffer.attrs) - buffer.lines = renderDocument(buffer.document, buffer.attrs, buffer.userstyle, buffer.viewport) + let ret = renderDocument(buffer.document, buffer.attrs, buffer.userstyle, buffer.viewport, buffer.prevstyled) + buffer.lines = ret[0] + buffer.prevstyled = ret[1] else: discard buffer.updateCursor() diff --git a/src/layout/engine.nim b/src/layout/engine.nim index 981a95ce..b15f27b1 100644 --- a/src/layout/engine.nim +++ b/src/layout/engine.nim @@ -2,12 +2,13 @@ import math import options import unicode -import layout/box +import css/stylednode +import css/values import html/tags import html/dom -import css/values -import utils/twtstr import io/term +import layout/box +import utils/twtstr # Build phase @@ -646,12 +647,12 @@ func getInputBox(parent: BoxBuilder, input: HTMLInputElement, viewport: Viewport return textbox # Don't generate empty anonymous inline blocks between block boxes -func canGenerateAnonymousInline(blockgroup: seq[BoxBuilder], computed: CSSComputedValues, text: Text): bool = +func canGenerateAnonymousInline(blockgroup: seq[BoxBuilder], computed: CSSComputedValues, str: string): bool = return blockgroup.len > 0 and blockgroup[^1].computed{"display"} == DISPLAY_INLINE or computed{"white-space"} in {WHITESPACE_PRE_LINE, WHITESPACE_PRE, WHITESPACE_PRE_WRAP} or - not text.data.onlyWhitespace() + not str.onlyWhitespace() -proc generateBlockBox(elem: Element, viewport: Viewport): BlockBoxBuilder +proc generateBlockBox(styledNode: StyledNode, viewport: Viewport): BlockBoxBuilder template flush_block_group(computed: CSSComputedValues) = if blockgroup.len > 0: @@ -667,142 +668,74 @@ template flush_ibox() = blockgroup.add(ibox) ibox = nil -proc generateInlineBoxes(box: BlockBoxBuilder, elem: Element, blockgroup: var seq[BoxBuilder], viewport: Viewport) +proc generateInlineBoxes(box: BlockBoxBuilder, styledNode: StyledNode, blockgroup: var seq[BoxBuilder], viewport: Viewport) -proc generateFromElem(box: BlockBoxBuilder, elem: Element, blockgroup: var seq[BoxBuilder], viewport: Viewport, ibox: var InlineBoxBuilder, listItemCounter: var int) = - if elem.tagType == TAG_BR: - ibox = box.getTextBox() - ibox.newline = true - flush_ibox +proc generateFromElem(box: BlockBoxBuilder, styledNode: StyledNode, blockgroup: var seq[BoxBuilder], viewport: Viewport, ibox: var InlineBoxBuilder, listItemCounter: var int) = + if styledNode.node != nil: + let elem = Element(styledNode.node) + if elem.tagType == TAG_BR: + ibox = box.getTextBox() + ibox.newline = true + flush_ibox - case elem.css{"display"} + case styledNode.computed{"display"} of DISPLAY_BLOCK: - flush_block_group(elem.css) - let childbox = elem.generateBlockBox(viewport) + flush_block_group(styledNode.computed) + let childbox = styledNode.generateBlockBox(viewport) box.children.add(childbox) of DISPLAY_LIST_ITEM: - flush_block_group(elem.css) - let childbox = getListItemBox(elem.css, listItemCounter) - childbox.content = elem.generateBlockBox(viewport) + flush_block_group(styledNode.computed) + let childbox = getListItemBox(styledNode.computed, listItemCounter) + childbox.content = styledNode.generateBlockBox(viewport) box.children.add(childbox) inc listItemCounter of DISPLAY_INLINE: flush_ibox - box.generateInlineBoxes(elem, blockgroup, viewport) + box.generateInlineBoxes(styledNode, blockgroup, viewport) of DISPLAY_INLINE_BLOCK: flush_ibox let childbox = getInlineBlockBox(box.computed) - childbox.content = elem.generateBlockBox(viewport) + childbox.content = styledNode.generateBlockBox(viewport) blockgroup.add(childbox) else: discard #TODO -proc generateInlinePseudoBox(box: BlockBoxBuilder, computed: CSSComputedValues, blockgroup: var seq[BoxBuilder], viewport: Viewport) = +proc generateInlineBoxes(box: BlockBoxBuilder, styledNode: StyledNode, blockgroup: var seq[BoxBuilder], viewport: Viewport) = var ibox: InlineBoxBuilder = nil - if computed{"content"}.len > 0: - ibox = getTextBox(computed) - ibox.text.add($computed{"content"}) - - flush_ibox - -proc generateBlockPseudoBox(computed: CSSComputedValues, viewport: Viewport): BlockBoxBuilder = - let box = getBlockBox(computed) - var blockgroup: seq[BoxBuilder] - var ibox: InlineBoxBuilder = nil - - if computed{"content"}.len > 0: - ibox = getTextBox(computed) - ibox.text.add($computed{"content"}) - flush_ibox - flush_block_group(computed) - - return box - -proc generatePseudo(box: BlockBoxBuilder, elem: Element, blockgroup: var seq[BoxBuilder], viewport: Viewport, ibox: var InlineBoxBuilder, computed: CSSComputedValues) = - case computed{"display"} - of DISPLAY_BLOCK: - flush_block_group(elem.css) - let childbox = generateBlockPseudoBox(computed, viewport) - box.children.add(childbox) - of DISPLAY_LIST_ITEM: - flush_block_group(elem.css) - let childbox = getListItemBox(computed, 1) - childbox.content = generateBlockPseudoBox(computed, viewport) - box.children.add(childbox) - of DISPLAY_INLINE: - flush_ibox - box.generateInlinePseudoBox(computed, blockgroup, viewport) - of DISPLAY_INLINE_BLOCK: - flush_ibox - let childbox = getInlineBlockBox(box.computed) - childbox.content = generateBlockPseudoBox(computed, viewport) - blockgroup.add(childbox) - else: - discard #TODO - -proc generateBoxBefore(box: BlockBoxBuilder, elem: Element, blockgroup: var seq[BoxBuilder], viewport: Viewport, ibox: var InlineBoxBuilder) = - if elem.pseudo[PSEUDO_BEFORE] != nil: - box.generatePseudo(elem, blockgroup, viewport, ibox, elem.pseudo[PSEUDO_BEFORE]) - - if elem.tagType == TAG_INPUT: - flush_ibox - let input = HTMLInputElement(elem) - ibox = box.getInputBox(input, viewport) - -proc generateBoxAfter(box: BlockBoxBuilder, elem: Element, blockgroup: var seq[BoxBuilder], viewport: Viewport, ibox: var InlineBoxBuilder) = - if elem.pseudo[PSEUDO_AFTER] != nil: - box.generatePseudo(elem, blockgroup, viewport, ibox, elem.pseudo[PSEUDO_AFTER]) - -proc generateInlineBoxes(box: BlockBoxBuilder, elem: Element, blockgroup: var seq[BoxBuilder], viewport: Viewport) = - var ibox: InlineBoxBuilder = nil - - generateBoxBefore(box, elem, blockgroup, viewport, ibox) - var listItemCounter = 1 # ordinal value of current list - for child in elem.childNodes: - case child.nodeType - of ELEMENT_NODE: - let child = Element(child) + for child in styledNode.children: + case child.t + of STYLED_ELEMENT: box.generateFromElem(child, blockgroup, viewport, ibox, listItemCounter) - of TEXT_NODE: - let child = Text(child) + of STYLED_TEXT: if ibox == nil: - ibox = getTextBox(elem.css) - ibox.node = elem - ibox.text.add(child.data) - else: discard - - generateBoxAfter(box, elem, blockgroup, viewport, ibox) + ibox = getTextBox(styledNode.computed) + ibox.node = child.node + ibox.text.add(child.text) flush_ibox -proc generateBlockBox(elem: Element, viewport: Viewport): BlockBoxBuilder = - let box = getBlockBox(elem.css) +proc generateBlockBox(styledNode: StyledNode, viewport: Viewport): BlockBoxBuilder = + let elem = Element(styledNode.node) + let box = getBlockBox(styledNode.computed) var blockgroup: seq[BoxBuilder] var ibox: InlineBoxBuilder = nil - generateBoxBefore(box, elem, blockgroup, viewport, ibox) - var listItemCounter = 1 # ordinal value of current list - for child in elem.childNodes: - case child.nodeType - of ELEMENT_NODE: + for child in styledNode.children: + case child.t + of STYLED_ELEMENT: flush_ibox - let child = Element(child) box.generateFromElem(child, blockgroup, viewport, ibox, listItemCounter) - of TEXT_NODE: - let child = Text(child) - if canGenerateAnonymousInline(blockgroup, box.computed, child): + of STYLED_TEXT: + if canGenerateAnonymousInline(blockgroup, box.computed, child.text): if ibox == nil: - ibox = getTextBox(elem.css) - ibox.node = elem - ibox.text.add(child.data) - else: discard - - generateBoxAfter(box, elem, blockgroup, viewport, ibox) + ibox = getTextBox(styledNode.computed) + ibox.node = child.node + ibox.text.add(child.text) flush_ibox if blockgroup.len > 0: @@ -811,10 +744,10 @@ proc generateBlockBox(elem: Element, viewport: Viewport): BlockBoxBuilder = box.children = blockgroup box.inlinelayout = true else: - flush_block_group(elem.css) + flush_block_group(styledNode.computed) return box -proc renderLayout*(viewport: var Viewport, document: Document) = - let builder = document.html.generateBlockBox(viewport) +proc renderLayout*(viewport: var Viewport, document: Document, root: StyledNode) = + let builder = root.generateBlockBox(viewport) viewport.root = buildRootBlock(builder, viewport) diff --git a/src/render/renderdocument.nim b/src/render/renderdocument.nim index b01728dd..196c1496 100644 --- a/src/render/renderdocument.nim +++ b/src/render/renderdocument.nim @@ -3,6 +3,7 @@ import unicode import css/cascade import css/sheet +import css/stylednode import css/values import html/dom import io/cell @@ -249,10 +250,11 @@ proc renderBlockContext(grid: var FlexibleGrid, ctx: BlockContext, x, y: int, te const css = staticRead"res/ua.css" let uastyle = css.parseStylesheet() -proc renderDocument*(document: Document, term: TermAttributes, userstyle: CSSStylesheet, layout: var Viewport): FlexibleGrid = - document.applyStylesheets(uastyle, userstyle) - layout.renderLayout(document) - result.setLen(0) - result.renderBlockContext(layout.root, 0, 0, term) - if result.len == 0: - result.addLine() +proc renderDocument*(document: Document, term: TermAttributes, userstyle: CSSStylesheet, layout: var Viewport, previousStyled: StyledNode): (FlexibleGrid, StyledNode) = + let styledNode = document.applyStylesheets(uastyle, userstyle, previousStyled) + result[1] = styledNode + layout.renderLayout(document, styledNode) + result[0].setLen(0) + result[0].renderBlockContext(layout.root, 0, 0, term) + if result[0].len == 0: + result[0].addLine() |