about summary refs log tree commit diff stats
path: root/src/layout
diff options
context:
space:
mode:
authorbptato <nincsnevem662@gmail.com>2024-06-27 21:50:31 +0200
committerbptato <nincsnevem662@gmail.com>2024-06-28 21:26:33 +0200
commit8268ba2cf049be1865875e3e01305a500fa533e2 (patch)
tree7ce60624f9212e65dad0c1a2d168eb6ab7c03ec9 /src/layout
parentf9734e2b3900781901bb5f268137bd9adbfc33ef (diff)
downloadchawan-8268ba2cf049be1865875e3e01305a500fa533e2.tar.gz
img, loader: add image resizing, misc fixes
* resize images with stb_image_resize
* use tee for output handle redirection (redirectToFile blocks)
* cache original image files
* accept lseek in sandbox
* misc stbi fixes

For now, I just pulled in stb_image_resize v1. v2 is an extra 150K in
size, not sure if it's worth the cost. (Either way, we can always switch
later if needed, since the API is almost the same.)

Next step: move sixel/kitty encoders to CGI, and cache their output in
memory instead of the intermediate RGBA representation.
Diffstat (limited to 'src/layout')
-rw-r--r--src/layout/engine.nim30
-rw-r--r--src/layout/renderdocument.nim4
2 files changed, 25 insertions, 9 deletions
diff --git a/src/layout/engine.nim b/src/layout/engine.nim
index a764faad..3acc958e 100644
--- a/src/layout/engine.nim
+++ b/src/layout/engine.nim
@@ -1370,7 +1370,7 @@ proc addInlineBlock(ictx: var InlineContext; state: var InlineState;
   ictx.whitespacenum = 0
 
 proc addInlineImage(ictx: var InlineContext; state: var InlineState;
-    bmp: Bitmap) =
+    bmp: Bitmap; padding: LayoutUnit) =
   let h = int(bmp.height).toLayoutUnit().ceilTo(ictx.cellHeight)
   let iastate = InlineAtomState(
     vertalign: state.fragment.computed{"vertical-align"},
@@ -1381,6 +1381,20 @@ proc addInlineImage(ictx: var InlineContext; state: var InlineState;
     bmp: bmp,
     size: size(w = int(bmp.width), h = h), #TODO overflow
   )
+  let computed = state.fragment.computed
+  let lctx = ictx.lctx
+  if computed{"width"}.canpx(ictx.space.w):
+    let w = computed{"width"}.spx(lctx, ictx.space.w, computed, padding)
+    if not computed{"height"}.canpx(ictx.space.h):
+      # maintain aspect ratio
+      atom.size.h = atom.size.h div atom.size.w * w
+    atom.size.w = w
+  if computed{"height"}.canpx(ictx.space.h):
+    let h = computed{"height"}.spx(lctx, ictx.space.h, computed, padding)
+    if not computed{"width"}.canpx(ictx.space.w):
+      # maintain aspect ratio
+      atom.size.w = atom.size.w div atom.size.h * h
+    atom.size.h = h
   discard ictx.addAtom(state, iastate, atom)
 
 func calcLineHeight(computed: CSSComputedValues; lctx: LayoutContext):
@@ -1421,7 +1435,7 @@ proc layoutInline(ictx: var InlineContext; fragment: InlineFragment) =
   case fragment.t
   of iftNewline: ictx.flushLine(state)
   of iftBox: ictx.addInlineBlock(state, fragment.box)
-  of iftBitmap: ictx.addInlineImage(state, fragment.bmp)
+  of iftBitmap: ictx.addInlineImage(state, fragment.bmp, padding.sum())
   of iftText: ictx.layoutText(state, fragment.text)
   of iftParent:
     for child in fragment.children:
@@ -2636,13 +2650,12 @@ proc pushInline(ctx: var InnerBlockContext; fragment: InlineFragment) =
 
 proc pushInlineText(ctx: var InnerBlockContext; computed: CSSComputedValues;
     styledNode: StyledNode; text: string) =
-  let box = InlineFragment(
+  ctx.pushInline(InlineFragment(
     t: iftText,
     computed: computed,
     node: styledNode,
     text: text
-  )
-  ctx.pushInline(box)
+  ))
 
 proc pushInlineBlock(ctx: var InnerBlockContext; styledNode: StyledNode;
     computed: CSSComputedValues) =
@@ -2788,13 +2801,12 @@ proc buildReplacement(ctx: var InnerBlockContext; child, parent: StyledNode;
     ctx.pushInlineText(computed, parent, child.content.s)
   of ContentImage:
     if child.content.bmp != nil:
-      let wrapper = InlineFragment(
+      ctx.pushInline(InlineFragment(
         t: iftBitmap,
-        computed: computed,
+        computed: parent.computed,
         node: parent,
         bmp: child.content.bmp
-      )
-      ctx.pushInline(wrapper)
+      ))
     else:
       ctx.pushInlineText(computed, parent, "[img]")
   of ContentVideo:
diff --git a/src/layout/renderdocument.nim b/src/layout/renderdocument.nim
index e45b8af4..89afde32 100644
--- a/src/layout/renderdocument.nim
+++ b/src/layout/renderdocument.nim
@@ -218,6 +218,8 @@ type
   PosBitmap* = ref object
     x*: int
     y*: int
+    width*: int
+    height*: int
     bmp*: Bitmap
 
   RenderState = object
@@ -379,6 +381,8 @@ proc renderInlineFragment(grid: var FlexibleGrid; state: var RenderState;
         state.images.add(PosBitmap(
           x: (offset.x div state.attrs.ppc).toInt,
           y: (offset.y div state.attrs.ppl).toInt,
+          width: atom.size.w.toInt,
+          height: atom.size.h.toInt,
           bmp: atom.bmp
         ))
   if fragment.computed{"position"} != PositionStatic: