diff options
author | bptato <nincsnevem662@gmail.com> | 2022-01-23 13:42:24 +0100 |
---|---|---|
committer | bptato <nincsnevem662@gmail.com> | 2022-01-23 13:42:24 +0100 |
commit | d97776fb627720bc4bd5841ffffcd8c9af712f3c (patch) | |
tree | fde0f696f78fa4cb197edcee7308403d1d6d22b6 /src | |
parent | 0b19885b33c53e2250a3a91326e5f146ccfa1492 (diff) | |
download | chawan-d97776fb627720bc4bd5841ffffcd8c9af712f3c.tar.gz |
Use pixels as the base unit for the layout
Diffstat (limited to 'src')
-rw-r--r-- | src/css/values.nim | 32 | ||||
-rw-r--r-- | src/io/term.nim | 6 | ||||
-rw-r--r-- | src/layout/box.nim | 13 | ||||
-rw-r--r-- | src/layout/engine.nim | 78 | ||||
-rw-r--r-- | src/render/renderdocument.nim | 78 |
5 files changed, 95 insertions, 112 deletions
diff --git a/src/css/values.nim b/src/css/values.nim index 436ef95e..e4f6e944 100644 --- a/src/css/values.nim +++ b/src/css/values.nim @@ -232,6 +232,38 @@ func cells*(l: CSSLength, d: int, term: TermAttributes, p: Option[int], o: bool) of UNIT_VMIN: px(min(w, h) / 100 * l.num, d) of UNIT_VMAX: px(max(w, h) / 100 * l.num, d) +func em_to_px(em: float64, term: TermAttributes): int = + int(em * float64(term.ppl)) + +func ch_to_px(ch: float64, term: TermAttributes): int = + int(ch * float64(term.ppc)) + +# 水 width, we assume it's 2 chars +func ic_to_px(ic: float64, term: TermAttributes): int = + int(ic * float64(term.ppc) * 2) + +# x-letter height, we assume it's em/2 +func ex_to_px(ex: float64, term: TermAttributes): int = + int(ex * float64(term.ppc) / 2) + +func px*(l: CSSLength, term: TermAttributes, p: int): int {.inline.} = + case l.unit + of UNIT_EM, UNIT_REM: em_to_px(l.num, term) + of UNIT_CH: ch_to_px(l.num, term) + of UNIT_IC: ic_to_px(l.num, term) + of UNIT_EX: ex_to_px(l.num, term) + of UNIT_PERC: int(p / 100 * l.num) + of UNIT_PX: int(l.num) + of UNIT_CM: int(l.num * 37.8) + of UNIT_MM: int(l.num * 3.78) + of UNIT_IN: int(l.num * 96) + of UNIT_PC: int(l.num * 96 / 6) + of UNIT_PT: int(l.num * 96 / 72) + of UNIT_VW: int(term.width_px / 100 * l.num) + of UNIT_VH: int(term.height_px / 100 * l.num) + of UNIT_VMIN: int(min(term.width_px, term.width_px) / 100 * l.num) + of UNIT_VMAX: int(max(term.width_px, term.width_px) / 100 * l.num) + func listMarker*(t: CSSListStyleType, i: int): string = case t of LIST_STYLE_TYPE_NONE: return "" diff --git a/src/io/term.nim b/src/io/term.nim index d1cacf7c..838ba77a 100644 --- a/src/io/term.nim +++ b/src/io/term.nim @@ -17,12 +17,12 @@ proc getTermAttributes*(): TermAttributes = when defined(posix): var win: IOctl_WinSize if ioctl(cint(getOsFileHandle(stdout)), TIOCGWINSZ, addr win) != -1: + result.ppc = int(win.ws_xpixel) div int(win.ws_col) + result.ppl = int(win.ws_ypixel) div int(win.ws_row) result.width = int(win.ws_col) - 1 result.height = int(win.ws_row) - result.width_px = int(win.ws_xpixel) + result.width_px = int(win.ws_xpixel) - result.ppc result.height_px = int(win.ws_ypixel) - result.ppc = int(win.ws_xpixel) div int(win.ws_col) - result.ppl = int(win.ws_ypixel) div int(win.ws_row) result.cell_ratio = result.ppl / result.ppc return #fail diff --git a/src/layout/box.nim b/src/layout/box.nim index e5e3f2fa..48265fde 100644 --- a/src/layout/box.nim +++ b/src/layout/box.nim @@ -63,19 +63,6 @@ type compheight*: Option[int] done*: bool - RowBox* = object - x*: int - y*: int - width*: int - height*: int - color*: CSSColor - fontstyle*: CSSFontStyle - fontweight*: int - textdecoration*: CSSTextDecoration - str*: string - nodes*: seq[Node] - bottom*: int - InlineBox* = ref object of CSSBox text*: seq[string] ictx*: InlineContext diff --git a/src/layout/engine.nim b/src/layout/engine.nim index 3f16c8ac..eba40f7c 100644 --- a/src/layout/engine.nim +++ b/src/layout/engine.nim @@ -20,6 +20,9 @@ func cells_h(l: CSSLength, state: Viewport, p: Option[int]): int = func cells_h(l: CSSLength, state: Viewport, p: int): int = return l.cells_in(state, state.term.ppl, p.some, false) +func px(l: CSSLength, state: Viewport, p = 0): int {.inline.} = + return px(l, state.term, p) + type InlineState = object ictx: InlineContext skip: bool @@ -28,6 +31,27 @@ type InlineState = object maxwidth: int specified: CSSSpecifiedValues +func whitespacepre(specified: CSSSpecifiedValues): bool {.inline.} = + specified{"white-space"} in {WHITESPACE_PRE, WHITESPACE_PRE_WRAP} + +func cellwidth(ictx: InlineContext): int {.inline.} = + ictx.viewport.term.ppc + +func cellheight(ictx: InlineContext): int {.inline.} = + ictx.viewport.term.ppl + +# Whitespace between words +func computeShift(ictx: InlineContext, specified: CSSSpecifiedValues): int = + if ictx.whitespace: + if ictx.thisrow.atoms.len > 0 or specified.whitespacepre: + let spacing = specified{"word-spacing"} + if spacing.auto: + return ictx.cellwidth + #return spacing.cells_w(ictx.viewport, 0) + return spacing.px(ictx.viewport) + ictx.whitespace = false + return 0 + proc newWord(state: var InlineState) = let word = InlineWord() let specified = state.specified @@ -46,20 +70,6 @@ proc finishRow(ictx: InlineContext) = ictx.width = max(ictx.width, oldrow.width) ictx.thisrow = InlineRow(rely: oldrow.rely + oldrow.height) -func whitespacepre(specified: CSSSpecifiedValues): bool {.inline.} = - specified{"white-space"} in {WHITESPACE_PRE, WHITESPACE_PRE_WRAP} - -# Whitespace between words -func computeShift(ictx: InlineContext, specified: CSSSpecifiedValues): int = - if ictx.whitespace: - if ictx.thisrow.atoms.len > 0 or specified.whitespacepre: - let spacing = specified{"word-spacing"} - if spacing.auto: - return 1 - return spacing.cells_w(ictx.viewport, 0) - ictx.whitespace = false - return 0 - proc addAtom(ictx: InlineContext, atom: InlineAtom, maxwidth: int, specified: CSSSpecifiedValues) = var shift = ictx.computeShift(specified) # Line wrapping @@ -81,13 +91,13 @@ proc addWord(state: var InlineState) = if state.word.str != "": let row = state.ictx.thisrow var word = state.word - word.height = 1 + word.height = state.ictx.cellheight state.ictx.addAtom(word, state.maxwidth, state.specified) state.newWord() # Start a new line, even if the previous one is empty proc flushLine(ictx: InlineContext) = - ictx.thisrow.height = max(ictx.thisrow.height, 1) + ictx.thisrow.height = max(ictx.thisrow.height, ictx.cellheight) ictx.finishRow() proc checkWrap(state: var InlineState, r: Rune) = @@ -96,11 +106,11 @@ proc checkWrap(state: var InlineState, r: Rune) = let shift = state.ictx.computeShift(state.specified) case state.specified{"word-break"} of WORD_BREAK_BREAK_ALL: - if state.ictx.thisrow.width + state.word.width + shift + r.width() > state.maxwidth: + if state.ictx.thisrow.width + state.word.width + shift + r.width() * state.ictx.cellwidth > state.maxwidth: state.addWord() state.ictx.finishRow() of WORD_BREAK_KEEP_ALL: - if state.ictx.thisrow.width + state.word.width + shift + r.width() > state.maxwidth: + if state.ictx.thisrow.width + state.word.width + shift + r.width() * state.ictx.cellwidth > state.maxwidth: state.ictx.finishRow() else: discard @@ -135,7 +145,7 @@ proc renderText*(ictx: InlineContext, str: string, maxwidth: int, specified: CSS fastRuneAt(str, i, r) state.checkWrap(r) state.word.str &= r - state.word.width += r.width() + state.word.width += r.width() * state.ictx.cellwidth state.addWord() @@ -147,18 +157,24 @@ proc computedDimensions(bctx: BlockContext, width: int, height: Option[int]) = if pwidth.auto: bctx.compwidth = width else: - bctx.compwidth = pwidth.cells_w(bctx.viewport, width) + #bctx.compwidth = pwidth.cells_w(bctx.viewport, width) + bctx.compwidth = pwidth.px(bctx.viewport, width) - let mlef = bctx.specified{"margin-left"}.cells_w(bctx.viewport, width) - let mrig = bctx.specified{"margin-right"}.cells_w(bctx.viewport, width) + #let mlef = bctx.specified{"margin-left"}.cells_w(bctx.viewport, width) + #let mrig = bctx.specified{"margin-right"}.cells_w(bctx.viewport, width) + let mlef = bctx.specified{"margin-left"}.px(bctx.viewport, width) + let mrig = bctx.specified{"margin-right"}.px(bctx.viewport, width) bctx.relx = mlef bctx.compwidth -= mlef bctx.compwidth -= mrig let pheight = bctx.specified{"height"} if not pheight.auto: - if pheight.unit != UNIT_PERC or height.issome: - bctx.compheight = pheight.cells_h(bctx.viewport, height).some + #bctx.compheight = pheight.cells_h(bctx.viewport, height).some + if pheight.unit != UNIT_PERC: + bctx.compheight = pheight.px(bctx.viewport).some + elif height.issome: + bctx.compheight = pheight.px(bctx.viewport, height.get).some proc newBlockContext_common(parent: BlockContext, box: CSSBox): BlockContext {.inline.} = new(result) @@ -185,7 +201,7 @@ proc newBlockContext(viewport: Viewport): BlockContext = new(result) result.specified = rootProperties() result.viewport = viewport - result.computedDimensions(viewport.term.width, none(int)) + result.computedDimensions(viewport.term.width_px, none(int)) proc newInlineContext(bctx: BlockContext): InlineContext = new(result) @@ -211,7 +227,8 @@ proc arrangeBlocks(bctx: BlockContext) = let child = bctx.nested[i] bctx.margin_top = child.margin_top - let mtop = bctx.specified{"margin-top"}.cells_h(bctx.viewport, bctx.compwidth) + #let mtop = bctx.specified{"margin-top"}.cells_h(bctx.viewport, bctx.compwidth) + let mtop = bctx.specified{"margin-top"}.px(bctx.viewport, bctx.compwidth) if mtop > bctx.margin_top or mtop < 0: bctx.margin_top = mtop - bctx.margin_top @@ -230,7 +247,8 @@ proc arrangeBlocks(bctx: BlockContext) = inc i bctx.margin_bottom = margin_todo - let mbot = bctx.specified{"margin-bottom"}.cells_h(bctx.viewport, bctx.compwidth) + #let mbot = bctx.specified{"margin-bottom"}.cells_h(bctx.viewport, bctx.compwidth) + let mbot = bctx.specified{"margin-bottom"}.px(bctx.viewport, bctx.compwidth) if mbot > bctx.margin_bottom or mbot < 0: bctx.margin_bottom = mbot - bctx.margin_bottom @@ -295,8 +313,10 @@ proc alignInlines(bctx: BlockContext, inlines: seq[CSSBox]) = if bctx.compheight.issome: bctx.height = bctx.compheight.get bctx.width = max(ictx.width, ictx.width) - bctx.margin_top = bctx.specified{"margin-top"}.cells_h(bctx.viewport, bctx.compwidth) - bctx.margin_bottom = bctx.specified{"margin-bottom"}.cells_h(bctx.viewport, bctx.compwidth) + #bctx.margin_top = bctx.specified{"margin-top"}.cells_h(bctx.viewport, bctx.compwidth) + #bctx.margin_bottom = bctx.specified{"margin-bottom"}.cells_h(bctx.viewport, bctx.compwidth) + bctx.margin_top = bctx.specified{"margin-top"}.px(bctx.viewport, bctx.compwidth) + bctx.margin_bottom = bctx.specified{"margin-bottom"}.px(bctx.viewport, bctx.compwidth) proc alignBlocks(bctx: BlockContext, blocks: seq[CSSBox]) = # Box contains block boxes. diff --git a/src/render/renderdocument.nim b/src/render/renderdocument.nim index 9d5e0dcd..8d0b53b1 100644 --- a/src/render/renderdocument.nim +++ b/src/render/renderdocument.nim @@ -11,63 +11,6 @@ import layout/box import layout/engine import utils/twtstr -func formatFromLine(line: RowBox): Formatting = - result.fgcolor = line.color.cellColor() - if line.fontstyle in { FONT_STYLE_ITALIC, FONT_STYLE_OBLIQUE }: - result.italic = true - if line.fontweight > 500: - result.bold = true - if line.textdecoration == TEXT_DECORATION_UNDERLINE: - result.underline = true - if line.textdecoration == TEXT_DECORATION_OVERLINE: - result.overline = true - if line.textdecoration == TEXT_DECORATION_LINE_THROUGH: - result.strike = true - -proc setRowBox(lines: var FlexibleGrid, line: RowBox) = - var r: Rune - - var x = line.x - var i = 0 - while x < 0: - fastRuneAt(line.str, i, r) - x += r.width() - let linestr = line.str.substr(i) - i = 0 - - let y = line.y - - while lines.len <= y: - lines.addLine() - - var cx = 0 - while cx < x and i < lines[y].str.len: - fastRuneAt(lines[y].str, i, r) - cx += r.width() - - let ostr = lines[y].str.substr(i) - let oformats = lines[y].formats.subformats(i) - lines[y].setLen(i) - - lines.addFormat(y, i, line.formatFromLine(), line.nodes) - - var nx = cx - if nx < x: - lines[y].str &= ' '.repeat(x - nx) - nx = x - - lines[y].str &= linestr - nx += linestr.width() - - i = 0 - while cx < nx and i < ostr.len: - fastRuneAt(ostr, i, r) - cx += r.width() - - if i < ostr.len: - let oline = FlexibleLine(str: ostr.substr(i), formats: oformats.subformats(i)) - lines[y].add(oline) - func formatFromWord(word: InlineWord): Formatting = result.fgcolor = word.color.cellColor() if word.fontstyle in { FONT_STYLE_ITALIC, FONT_STYLE_OBLIQUE }: @@ -81,10 +24,11 @@ func formatFromWord(word: InlineWord): Formatting = if word.textdecoration == TEXT_DECORATION_LINE_THROUGH: result.strike = true -proc setRowWord(lines: var FlexibleGrid, word: InlineWord, x, y: int) = +proc setRowWord(lines: var FlexibleGrid, word: InlineWord, x, y: int, term: TermAttributes) = var r: Rune - var x = x + let y = y div term.ppl + var x = x div term.ppc var i = 0 while x < 0: fastRuneAt(word.str, i, r) @@ -123,9 +67,9 @@ proc setRowWord(lines: var FlexibleGrid, word: InlineWord, x, y: int) = let oline = FlexibleLine(str: ostr.substr(i), formats: oformats.subformats(i)) lines[y].add(oline) -proc renderBlockContext(grid: var FlexibleGrid, ctx: BlockContext, x, y: int) +proc renderBlockContext(grid: var FlexibleGrid, ctx: BlockContext, x, y: int, term: TermAttributes) -proc renderInlineContext(grid: var FlexibleGrid, ctx: InlineContext, x, y: int) = +proc renderInlineContext(grid: var FlexibleGrid, ctx: InlineContext, x, y: int, term: TermAttributes) = for row in ctx.rows: let x = x + row.relx let y = y + row.rely + row.height @@ -135,20 +79,20 @@ proc renderInlineContext(grid: var FlexibleGrid, ctx: InlineContext, x, y: int) let y = y - atom.height if atom of BlockContext: let ctx = BlockContext(atom) - grid.renderBlockContext(ctx, x + ctx.relx, y + ctx.rely) + grid.renderBlockContext(ctx, x + ctx.relx, y + ctx.rely, term) elif atom of InlineWord: let word = InlineWord(atom) - grid.setRowWord(word, x + word.relx, y) + grid.setRowWord(word, x + word.relx, y, term) -proc renderBlockContext(grid: var FlexibleGrid, ctx: BlockContext, x, y: int) = +proc renderBlockContext(grid: var FlexibleGrid, ctx: BlockContext, x, y: int, term: TermAttributes) = var x = x var y = y if ctx.inline != nil: assert ctx.nested.len == 0 - grid.renderInlineContext(ctx.inline, x + ctx.inline.relx, y) + grid.renderInlineContext(ctx.inline, x + ctx.inline.relx, y, term) else: for ctx in ctx.nested: - grid.renderBlockContext(ctx, x + ctx.relx, y + ctx.rely) + grid.renderBlockContext(ctx, x + ctx.relx, y + ctx.rely, term) const css = staticRead"res/ua.css" let uastyle = css.parseStylesheet() @@ -156,6 +100,6 @@ proc renderDocument*(document: Document, attrs: TermAttributes, userstyle: CSSSt document.applyStylesheets(uastyle, userstyle) layout.renderLayout(document) result.setLen(0) - result.renderBlockContext(layout.root.bctx, 0, 0) + result.renderBlockContext(layout.root.bctx, 0, 0, layout.term) if result.len == 0: result.addLine() |