about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--src/css/values.nim32
-rw-r--r--src/io/term.nim6
-rw-r--r--src/layout/box.nim13
-rw-r--r--src/layout/engine.nim78
-rw-r--r--src/render/renderdocument.nim78
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()