about summary refs log tree commit diff stats
path: root/src/layout
diff options
context:
space:
mode:
authorbptato <nincsnevem662@gmail.com>2022-07-16 14:14:06 +0200
committerbptato <nincsnevem662@gmail.com>2022-07-16 14:15:52 +0200
commit8cd503c88693171f9887716440cdc110fdca2bb3 (patch)
tree7416b86ab677b8bf38c0bd89009991899e516660 /src/layout
parent368794ad19514deb7397d4eb2f0e5b72862d28e5 (diff)
downloadchawan-8cd503c88693171f9887716440cdc110fdca2bb3.tar.gz
Use StyledNodes instead of passing the entire DOM to the layout engine
This moves pseudo element generation to the cascading phase.
For now it also breaks style caching.
Diffstat (limited to 'src/layout')
-rw-r--r--src/layout/engine.nim157
1 files changed, 45 insertions, 112 deletions
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)