import unicode import types/enums import html/dom import css/box import css/style import io/buffer import io/cell import utils/twtstr # basically these are the "line boxes". though honestly this is an awful # way to model them... but it's fine for now, I guess. TODO # no it's actually not fine number one priority is making it work TODO TODO TODO proc generateGrids(text: Text, maxwidth: int, maxheight: int, x: int, y: int, fromx: int = x): FlexibleGrid = var r: Rune var rowgrid: FlexibleLine var i = 0 if fromx > x: let m = fromx - x + maxwidth var w = 0 while i < text.data.len: let pi = i fastRuneAt(text.data, i, r) let rw = r.width() if rw + w > m: i = pi break else: rowgrid.add(FlexibleCell(rune: r)) w += rw result.add(rowgrid) if i < text.data.len: rowgrid.setLen(0) var w = 0 while i < text.data.len: let pi = i fastRuneAt(text.data, i, r) let rw = r.width() if rw + w > maxwidth: i = pi w = 0 result.add(rowgrid) rowgrid.setLen(0) else: rowgrid.add(FlexibleCell(rune: r)) w += rw if rowgrid.len > 0: result.add(rowgrid) proc generateBox(text: Text, maxwidth: int, maxheight: int, x: int, y: int, fromx: int): CSSInlineBox = new(result) result.content = text.generateGrids(maxwidth, maxheight, x, y, fromx) result.fromx = fromx result.innerEdge.x1 = x result.innerEdge.y1 = y var height = 0 var width = 0 for grid in result.content: inc height width = max(width, grid.len) height = min(height, maxheight) width = min(width, maxwidth) result.innerEdge.x2 = x + width result.innerEdge.y2 = y + height proc generateBox(elem: Element, maxwidth: int, maxheight: int, x: int = 0, y: int = 0, fromx: int = x): CSSBox proc generateChildBoxes(elem: Element, maxwidth: int, maxheight: int, x: int, y: int, fromx: int = 0): seq[CSSBox] = var cx = fromx var cy = y for child in elem.childNodes: case child.nodeType of TEXT_NODE: let box = Text(child).generateBox(maxwidth, maxheight, x, cy, cx) if box != nil: result.add(box) cy += box.h if box.content.len > 0: cx = box.content[^1].width() of ELEMENT_NODE: let box = Element(child).generateBox(maxwidth, maxheight, x, cy, cx) if box != nil: result.add(box) else: discard proc generateBox(elem: Element, maxwidth: int, maxheight: int, x: int = 0, y: int = 0, fromx: int = x): CSSBox = if elem.cssvalues[RULE_DISPLAY].display == DISPLAY_NONE: return nil result = CSSBlockBox() result.innerEdge.x1 = x result.innerEdge.y1 = y var width = 0 var height = 0 for box in elem.generateChildBoxes(maxwidth, maxheight, x, y, fromx): result.children.add(box) height += box.h height = min(height, maxheight) width = max(width, box.w) width = min(width, maxwidth) result.innerEdge.x2 = x + width result.innerEdge.y2 = y + height proc alignBoxes*(buffer: Buffer) = buffer.rootbox = buffer.document.root.generateBox(buffer.width, buffer.height)