about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
authorbptato <nincsnevem662@gmail.com>2024-12-03 19:43:22 +0100
committerbptato <nincsnevem662@gmail.com>2024-12-03 19:43:22 +0100
commit6d92a2e6679c481c8a88fc50d750e2ea8af67a23 (patch)
treee462bef801a80242cbb42608595d6377236af799 /src
parent05b97c934468ef23cf83f11083b1b9aef883dfb0 (diff)
downloadchawan-6d92a2e6679c481c8a88fc50d750e2ea8af67a23.tar.gz
pager, term: use cell offset with kitty images
Gets rid of rounding errors when positioning images.

Theoretically this is possible with Sixel too, but as always, it's
ten times as difficult to implement as with Kitty, so I'll leave it
for later.
Diffstat (limited to 'src')
-rw-r--r--src/css/layout.nim2
-rw-r--r--src/css/render.nim12
-rw-r--r--src/local/pager.nim4
-rw-r--r--src/local/term.nim31
4 files changed, 35 insertions, 14 deletions
diff --git a/src/css/layout.nim b/src/css/layout.nim
index fe5afdcc..2e1fcd03 100644
--- a/src/css/layout.nim
+++ b/src/css/layout.nim
@@ -1599,7 +1599,7 @@ proc addInlineImage(ictx: var InlineContext; state: var InlineState;
   let atom = InlineAtom(
     t: iatImage,
     bmp: bmp,
-    size: size(w = int(bmp.width), h = int(bmp.height)) #TODO overflow
+    size: size(w = bmp.width, h = bmp.height) #TODO overflow
   )
   let computed = state.fragment.computed
   let lctx = ictx.lctx
diff --git a/src/css/render.nim b/src/css/render.nim
index 8e8185dc..d7d57e35 100644
--- a/src/css/render.nim
+++ b/src/css/render.nim
@@ -230,6 +230,8 @@ type
   PosBitmap* = ref object
     x*: int
     y*: int
+    offx*: int
+    offy*: int
     width*: int
     height*: int
     bmp*: NetworkBitmap
@@ -367,9 +369,15 @@ proc renderInlineFragment(grid: var FlexibleGrid; state: var RenderState;
         # "paint" background, i.e. add formatting (but don't actually color it)
         grid.paintBackground(state, defaultColor, x1, y1, x2, y2, fragment.node,
           noPaint = true)
+        let x = (offset.x div state.attrs.ppc).toInt
+        let y = (offset.y div state.attrs.ppl).toInt
+        let offx = (offset.x - x.toLayoutUnit * state.attrs.ppc).toInt
+        let offy = (offset.y - y.toLayoutUnit * state.attrs.ppl).toInt
         state.images.add(PosBitmap(
-          x: (offset.x div state.attrs.ppc).toInt,
-          y: (offset.y div state.attrs.ppl).toInt,
+          x: x,
+          y: y,
+          offx: offx,
+          offy: offy,
           width: atom.size.w.toInt,
           height: atom.size.h.toInt,
           bmp: atom.bmp
diff --git a/src/local/pager.nim b/src/local/pager.nim
index 6fe2ce63..61833418 100644
--- a/src/local/pager.nim
+++ b/src/local/pager.nim
@@ -697,8 +697,8 @@ proc initImages(pager: Pager; container: Container) =
     let canvasImage = pager.term.loadImage(cached.data, container.process,
       imageId, image.x - container.fromx, image.y - container.fromy,
       image.width, image.height, image.x, image.y, pager.bufWidth,
-      pager.bufHeight, erry, offx, dispw, cached.preludeLen, cached.transparent,
-      redrawNext)
+      pager.bufHeight, erry, offx, dispw, image.offx, image.offy,
+      cached.preludeLen, cached.transparent, redrawNext)
     if canvasImage != nil:
       newImages.add(canvasImage)
   pager.term.clearImages(pager.bufHeight)
diff --git a/src/local/term.nim b/src/local/term.nim
index bc9919b8..3820b16d 100644
--- a/src/local/term.nim
+++ b/src/local/term.nim
@@ -91,6 +91,10 @@ type
     # offset (crop start)
     offx: int
     offy: int
+    # kitty only: X/Y offset *inside* cell. (TODO implement for sixel too)
+    # has nothing to do with offx/offy.
+    offx2: int
+    offy2: int
     # size cap (crop end)
     # Note: this 0-based, so the final display size is
     # (dispw - offx, disph - offy)
@@ -710,12 +714,17 @@ func findImage(term: Terminal; pid, imageId: int; rx, ry, width, height,
 
 # x, y, maxw, maxh in cells
 # x, y can be negative, then image starts outside the screen
-proc positionImage(term: Terminal; image: CanvasImage; x, y, maxw, maxh: int):
-    bool =
+proc positionImage(term: Terminal; image: CanvasImage;
+    x, y, maxw, maxh, offx2, offy2: int): bool =
   image.x = x
   image.y = y
-  let xpx = x * term.attrs.ppc
-  let ypx = y * term.attrs.ppl
+  image.offx2 = offx2
+  image.offy2 = offy2
+  var xpx = x * term.attrs.ppc
+  var ypx = y * term.attrs.ppl
+  if term.imageMode == imKitty:
+    xpx += image.offx2
+    ypx += image.offy2
   # calculate offset inside image to start from
   image.offx = -min(xpx, 0)
   image.offy = -min(ypx, 0)
@@ -790,8 +799,8 @@ proc checkImageDamage*(term: Terminal; maxw, maxh: int) =
               term.lineDamage[y] = mx
 
 proc loadImage*(term: Terminal; data: Blob; pid, imageId, x, y, width, height,
-    rx, ry, maxw, maxh, erry, offx, dispw, preludeLen: int; transparent: bool;
-    redrawNext: var bool): CanvasImage =
+    rx, ry, maxw, maxh, erry, offx, dispw, offx2, offy2, preludeLen: int;
+    transparent: bool; redrawNext: var bool): CanvasImage =
   if (let image = term.findImage(pid, imageId, rx, ry, width, height, erry,
         offx, dispw); image != nil):
     # reuse image on screen
@@ -799,7 +808,7 @@ proc loadImage*(term: Terminal; data: Blob; pid, imageId, x, y, width, height,
       # only clear sixels; with kitty we just move the existing image
       if term.imageMode == imSixel:
         term.clearImage(image, maxh)
-      if not term.positionImage(image, x, y, maxw, maxh):
+      if not term.positionImage(image, x, y, maxw, maxh, offx2, offy2):
         # no longer on screen
         image.dead = true
         return nil
@@ -814,13 +823,15 @@ proc loadImage*(term: Terminal; data: Blob; pid, imageId, x, y, width, height,
     data: data,
     rx: rx,
     ry: ry,
+    offx2: offx2,
+    offy2: offy2,
     width: width,
     height: height,
     erry: erry,
     transparent: transparent,
     preludeLen: preludeLen
   )
-  if term.positionImage(image, x, y, maxw, maxh):
+  if term.positionImage(image, x, y, maxw, maxh, offx2, offy2):
     redrawNext = true
     return image
   # no longer on screen
@@ -909,6 +920,7 @@ proc outputKittyImage(term: Terminal; x, y: int; image: CanvasImage) =
   var outs = term.cursorGoto(x, y) &
     APC & "GC=1,s=" & $image.width & ",v=" & $image.height &
     ",x=" & $image.offx & ",y=" & $image.offy &
+    ",X=" & $image.offx2 & ",Y=" & $image.offy2 &
     ",w=" & $(image.dispw - image.offx) &
     ",h=" & $(image.disph - image.offy) &
     # for now, we always use placement id 1
@@ -966,7 +978,8 @@ proc clearCanvas*(term: Terminal) =
   let maxh = term.attrs.height - 1
   var newImages: seq[CanvasImage] = @[]
   for image in term.canvasImages:
-    if term.positionImage(image, image.x, image.y, maxw, maxh):
+    if term.positionImage(image, image.x, image.y, maxw, maxh, image.offx2,
+        image.offy2):
       image.damaged = true
       image.marked = true
       newImages.add(image)