diff options
author | bptato <nincsnevem662@gmail.com> | 2024-06-29 12:32:17 +0200 |
---|---|---|
committer | bptato <nincsnevem662@gmail.com> | 2024-06-29 12:50:16 +0200 |
commit | 2e50aa23237da76802d2a61cb7426bf51c122d14 (patch) | |
tree | 9ed3f42f9ef3f6a6f97c4118bc5fbc90248f00ce /src/local | |
parent | e7786e39e38ddf5ec75b95cc19e1bee108cd37d2 (diff) | |
download | chawan-2e50aa23237da76802d2a61cb7426bf51c122d14.tar.gz |
dom, pager: cache images from network
With many limitations: * slightly randomized expiry, so it's harder to fingerprint * only images. so e.g. CSS is still left uncached * it's per-buffer and non-persistent, so images are still redownloaded for every new page load so it's more of an image sharing between placements than true caching.
Diffstat (limited to 'src/local')
-rw-r--r-- | src/local/container.nim | 12 | ||||
-rw-r--r-- | src/local/pager.nim | 37 | ||||
-rw-r--r-- | src/local/term.nim | 28 |
3 files changed, 44 insertions, 33 deletions
diff --git a/src/local/container.nim b/src/local/container.nim index a7702101..d78f9120 100644 --- a/src/local/container.nim +++ b/src/local/container.nim @@ -99,6 +99,8 @@ type CachedImage* = ref object loaded*: bool + width*: int + height*: int bmp*: NetworkBitmap Container* = ref object @@ -2038,10 +2040,12 @@ proc highlightMarks*(container: Container; display: var FixedGrid; hlformat.bgcolor = hlcolor display[y * display.width + x].format = hlformat -func findCachedImage*(container: Container; id: int): CachedImage = - for image in container.cachedImages: - if image.bmp.imageId == id: - return image +func findCachedImage*(container: Container; image: PosBitmap): CachedImage = + let imageId = NetworkBitmap(image.bmp).imageId + for it in container.cachedImages: + if it.bmp.imageId == imageId and it.width == image.width and + it.height == image.height: + return it return nil proc handleEvent*(container: Container) = diff --git a/src/local/pager.nim b/src/local/pager.nim index cdc08422..9f5eb593 100644 --- a/src/local/pager.nim +++ b/src/local/pager.nim @@ -474,17 +474,14 @@ proc redraw(pager: Pager) {.jsfunc.} = pager.container.select.redraw = true proc loadCachedImage(pager: Pager; container: Container; image: PosBitmap) = - #TODO this is kinda dumb, because we cannot unload cached images. - # ideally the filesystem cache should serve as the only cache, but right - # now it's just sort of a temporary place before the image is dumped to - # memory. - # maybe allow the buffer to add a cache file? or receive a separate "image - # load start" event in container, and then add one in the pager? - # the first option seems better; it's simpler, and buffers can add arbitrary - # cache files if they just tell the pager it's an image anyway. + #TODO we should only cache the final output in memory, not the full bitmap. let bmp = NetworkBitmap(image.bmp) let request = newRequest(newURL("cache:" & $bmp.cacheId).get) - let cachedImage = CachedImage(bmp: bmp) + let cachedImage = CachedImage( + bmp: bmp, + width: image.width, + height: image.height + ) pager.loader.shareCachedItem(bmp.cacheId, pager.loader.clientPid, container.process) pager.loader.fetch(request).then(proc(res: JSResult[Response]): @@ -508,15 +505,18 @@ proc loadCachedImage(pager: Pager; container: Container; image: PosBitmap) = response.body.sclose() return r ).then(proc(res: JSResult[Response]): EmptyPromise = + if res.isNone: + pager.loader.removeCachedItem(bmp.cacheId) + return newResolvedPromise() let response = res.get # take target sizes bmp.width = uint64(image.width) bmp.height = uint64(image.height) - return response.saveToBitmap(bmp) - ).then(proc() = - container.redraw = true - cachedImage.loaded = true - pager.loader.removeCachedItem(bmp.cacheId) + return response.saveToBitmap(bmp).then(proc() = + container.redraw = true + cachedImage.loaded = true + pager.loader.removeCachedItem(bmp.cacheId) + ) ) container.cachedImages.add(cachedImage) @@ -525,9 +525,8 @@ proc initImages(pager: Pager; container: Container) = for image in container.images: var imageId = -1 if image.bmp of NetworkBitmap: - # add cache file to pager, but source it from the container. let bmp = NetworkBitmap(image.bmp) - let cached = container.findCachedImage(bmp.imageId) + let cached = container.findCachedImage(image) imageId = bmp.imageId if cached == nil: pager.loadCachedImage(container, image) @@ -538,7 +537,7 @@ proc initImages(pager: Pager; container: Container) = else: imageId = pager.imageId inc pager.imageId - let canvasImage = pager.term.loadImage(image.bmp, container.process, imageId, + let canvasImage = pager.term.loadImage(image, container.process, imageId, image.x - container.fromx, image.y - container.fromy, pager.bufWidth, pager.bufHeight) if canvasImage != nil: @@ -548,6 +547,7 @@ proc initImages(pager: Pager; container: Container) = proc draw*(pager: Pager) = var redraw = false + var imageRedraw = false let container = pager.container if container != nil: if container.redraw: @@ -558,6 +558,7 @@ proc draw*(pager: Pager) = container.highlightMarks(pager.display.grid, hlcolor) container.redraw = false pager.display.redraw = true + imageRedraw = true if (let select = container.select; select != nil and select.redraw): select.drawSelect(pager.display.grid) select.redraw = false @@ -580,7 +581,7 @@ proc draw*(pager: Pager) = pager.term.writeGrid(pager.status.grid, 0, pager.attrs.height - 1) pager.status.redraw = false redraw = true - if container != nil and pager.term.imageMode != imNone: + if imageRedraw and pager.term.imageMode != imNone: # init images only after term canvas has been finalized pager.initImages(container) if redraw: diff --git a/src/local/term.nim b/src/local/term.nim index 546b16fa..8dcff9ba 100644 --- a/src/local/term.nim +++ b/src/local/term.nim @@ -7,10 +7,14 @@ import std/termios import std/unicode import bindings/termcap +import chagashi/charset +import chagashi/decoder +import chagashi/encoder import config/config import img/bitmap import io/posixstream import js/base64 +import layout/renderdocument import types/cell import types/color import types/opt @@ -18,10 +22,6 @@ import types/winattrs import utils/strwidth import utils/twtstr -import chagashi/charset -import chagashi/decoder -import chagashi/encoder - #TODO switch away from termcap... type @@ -66,7 +66,7 @@ type damaged: bool marked*: bool kittyId: int - bmp: Bitmap + pbmp: PosBitmap Terminal* = ref object cs*: Charset @@ -222,6 +222,9 @@ const ANSIColorMap = [ rgb(255, 255, 255) ] +template bmp(image: CanvasImage): Bitmap = + image.pbmp.bmp + proc flush*(term: Terminal) = term.outfile.flushFile() @@ -616,9 +619,12 @@ proc outputGrid*(term: Terminal) = term.cursorx = -1 term.cursory = -1 -func findImage(term: Terminal; pid, imageId: int): CanvasImage = +func findImage(term: Terminal; pid, imageId: int; pbmp: PosBitmap): + CanvasImage = for it in term.canvasImages: - if it.pid == pid and it.imageId == imageId: + if it.pid == pid and it.imageId == imageId and + it.pbmp.width == pbmp.width and it.pbmp.height == pbmp.height and + it.pbmp.x == pbmp.x and it.pbmp.y == pbmp.y: return it return nil @@ -660,9 +666,9 @@ proc clearImages*(term: Terminal; maxh: int) = term.clearImage(image, maxh) image.marked = false -proc loadImage*(term: Terminal; bmp: Bitmap; pid, imageId, x, y, maxw, +proc loadImage*(term: Terminal; pbmp: PosBitmap; pid, imageId, x, y, maxw, maxh: int): CanvasImage = - if (let image = term.findImage(pid, imageId); image != nil): + if (let image = term.findImage(pid, imageId, pbmp); image != nil): # reuse image on screen if image.x != x or image.y != y: # only clear sixels; with kitty we just move the existing image @@ -672,7 +678,7 @@ proc loadImage*(term: Terminal; bmp: Bitmap; pid, imageId, x, y, maxw, # no longer on screen return nil elif term.imageMode == imSixel: - # check if any line our image is on is damaged + # check if any line of our image is damaged let ey = min(image.y + int(image.bmp.height), maxh) let mx = (image.offx + image.dispw) div term.attrs.ppc for y in max(image.y, 0) ..< ey: @@ -684,7 +690,7 @@ proc loadImage*(term: Terminal; bmp: Bitmap; pid, imageId, x, y, maxw, image.marked = true return image # new image - let image = CanvasImage(bmp: bmp, pid: pid, imageId: imageId) + let image = CanvasImage(pbmp: pbmp, pid: pid, imageId: imageId) if term.positionImage(image, x, y, maxw, maxh): return image # no longer on screen |