# SPDX-FileCopyrightText: ☭ 2021 Emery Hemingway # SPDX-License-Identifier: Unlicense import std/sequtils import pixie, pixie/systemtypefaces import svui type Typesetting* = object h1, h2, h3, p: Font proc newFont(typeface: Typeface, size: float32): Font = result = newFont(typeface) result.size = size proc initTypesetting*(): Typesetting = let typeface = readTypeface findSystemTypeface(family = "Gentium Plus") result.h1 = newFont(typeface, 24) result.h2 = newFont(typeface, 20) result.h3 = newFont(typeface, 16) result.p = newFont(typeface, 12) proc body(xhtml: Xhtml): XmlElement = for e in xhtml.elements: if e.orKind == XmlNodeKind.`XmlElement` and e.xmlElement.name == "body": return e.xmlElement raise newException(ValueError, "no body in XHTML document") proc name(node: XmlNode): string = node.xmlElement.name proc text(node: XmlNode): string = case node.orKind of XmlNodeKind.XmlElement: for e in node.xmlElement.elements: result.add e.text of XmlNodeKind.XmlText: result.add node.xmlText.data func height(arr: Arrangement): float = if arr.positions.len > 0: result = arr.positions[arr.positions.high].y proc add(result: var Arrangement; other: sink Arrangement) = if result.lines.len == 0: result = other else: let runeOff = result.runes.len add(result.lines, map(other.lines, proc (x: (int, int)): (int, int) = (x[0]+runeOff, x[1]+runeOff))) add(result.spans, map(other.spans, proc (x: (int, int)): (int, int) = (x[0]+runeOff, x[1]+runeOff))) add(result.fonts, other.fonts) add(result.runes, other.runes) let yOff = result.positions[result.positions.high].y add(result.positions, map(other.positions, proc(pos: Vec2): Vec2 = vec2(pos.x, pos.y + yOff))) add(result.selectionRects, map(other.selectionRects, proc(rect: Rect): Rect = rect(rect.x, rect.y + yOff, rect.w, rect.h))) proc render*(ts: Typesetting; xhtml: Xhtml): Image = # TODO: render by font size, not by wh var wh = computeBounds(ts.p, "X") wh.x = wh.x * 80 wh.y = wh.y * 50 let margin = wh / 9.0 var printSpace = wh * (7.0 / 9.0) pages = @[Arrangement()] proc pageEnd(): float = let pi = pages.high li = pages[pi].lines.high ci = pages[pi].lines[li][1] pages[pi].positions[ci].y proc append(span: Span) = var arr = typeset(@[span], printSpace) if pages[pages.high].height + arr.height < printSpace.y: pages[pages.high].add arr else: discard for e in xhtml.body.elements: let tag = e.name case tag of "h1": append newSpan(e.text & "\n", ts.h1) of "h2": append newSpan("\n" & e.text & "\n", ts.h2) of "h3": append newSpan("\n" & e.text & "\n", ts.h3) of "p": append newSpan(" " & e.text & "\n\n", ts.p) else: discard # raise newException(ValueError, "unhandled element in XHTML :" & tag) result = newImage(int wh.x, int wh.y) fill(result, rgba(255, 255, 255, 255)) fillText(result, pages[0], translate(margin))