From c9511f99db4bfd58ea361ae8422e2c3a335653ab Mon Sep 17 00:00:00 2001 From: Emery Hemingway Date: Tue, 28 Dec 2021 12:38:40 +0100 Subject: [PATCH] Move xhtml rendering here --- src/private/render/xhtml.nim | 101 +++++++++++++++++++++++++++++++++++ src/zua.nim | 4 +- 2 files changed, 103 insertions(+), 2 deletions(-) create mode 100644 src/private/render/xhtml.nim diff --git a/src/private/render/xhtml.nim b/src/private/render/xhtml.nim new file mode 100644 index 0000000..dbaf6dc --- /dev/null +++ b/src/private/render/xhtml.nim @@ -0,0 +1,101 @@ +# 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)) diff --git a/src/zua.nim b/src/zua.nim index d0399e5..8875a1d 100644 --- a/src/zua.nim +++ b/src/zua.nim @@ -11,8 +11,8 @@ import nimsvg import bumpy, pixie, pixie/fileformats/svg import sdl2 - -import svui, svui/render/xhtml +import svui +import ./private/render/xhtml type Svui = svui.Svui[Ref]