kittygfx: placement with rows (r) param scrolls properly out of viewport

Fixes #2332

Two bugs fixed to fix this behavior:

1. Our destination height didn't account for the top-left being
   offscreen.

2. We were using the wrong height for the source rectangle. When a rows
   param (r=) is specified, the image height and destination height are
   at different scales. We were using the viewport scale for the offset
   but it should be the image scale.
This commit is contained in:
Mitchell Hashimoto
2024-12-23 14:09:33 -08:00
parent 0f7a089659
commit bd90a6dd3b
2 changed files with 42 additions and 4 deletions

View File

@ -1821,6 +1821,21 @@ fn prepKittyPlacement(
break :offset_y @intCast(offset_pixels);
} else 0;
// If we specify `rows` then our offset above is in viewport space
// and not in the coordinate space of the source image. Without `rows`
// that's one and the same.
const source_offset_y: u32 = if (p.rows > 0) source_offset_y: {
// Determine the scale factor to apply for this row height.
const image_height: f64 = @floatFromInt(image.height);
const viewport_height: f64 = @floatFromInt(p.rows * self.grid_metrics.cell_height);
const scale: f64 = image_height / viewport_height;
// Apply the scale to the offset
const offset_y_f64: f64 = @floatFromInt(offset_y);
const source_offset_y_f64: f64 = offset_y_f64 * scale;
break :source_offset_y @intFromFloat(@round(source_offset_y_f64));
} else offset_y;
// We need to prep this image for upload if it isn't in the cache OR
// it is in the cache but the transmit time doesn't match meaning this
// image is different.
@ -1834,7 +1849,7 @@ fn prepKittyPlacement(
// Calculate the source rectangle
const source_x = @min(image.width, p.source_x);
const source_y = @min(image.height, p.source_y + offset_y);
const source_y = @min(image.height, p.source_y + source_offset_y);
const source_width = if (p.source_width > 0)
@min(image.width - source_x, p.source_width)
else
@ -1846,7 +1861,11 @@ fn prepKittyPlacement(
// Calculate the width/height of our image.
const dest_width = if (p.columns > 0) p.columns * self.grid_metrics.cell_width else source_width;
const dest_height = if (p.rows > 0) p.rows * self.grid_metrics.cell_height else source_height;
const dest_height = if (p.rows > 0) rows: {
// Clip to the viewport to handle scrolling. offset_y is already in
// viewport scale so we can subtract it directly.
break :rows (p.rows * self.grid_metrics.cell_height) - offset_y;
} else source_height;
// Accumulate the placement
if (image.width > 0 and image.height > 0) {

View File

@ -1052,6 +1052,21 @@ fn prepKittyPlacement(
break :offset_y @intCast(offset_pixels);
} else 0;
// If we specify `rows` then our offset above is in viewport space
// and not in the coordinate space of the source image. Without `rows`
// that's one and the same.
const source_offset_y: u32 = if (p.rows > 0) source_offset_y: {
// Determine the scale factor to apply for this row height.
const image_height: f64 = @floatFromInt(image.height);
const viewport_height: f64 = @floatFromInt(p.rows * self.grid_metrics.cell_height);
const scale: f64 = image_height / viewport_height;
// Apply the scale to the offset
const offset_y_f64: f64 = @floatFromInt(offset_y);
const source_offset_y_f64: f64 = offset_y_f64 * scale;
break :source_offset_y @intFromFloat(@round(source_offset_y_f64));
} else offset_y;
// We need to prep this image for upload if it isn't in the cache OR
// it is in the cache but the transmit time doesn't match meaning this
// image is different.
@ -1065,7 +1080,7 @@ fn prepKittyPlacement(
// Calculate the source rectangle
const source_x = @min(image.width, p.source_x);
const source_y = @min(image.height, p.source_y + offset_y);
const source_y = @min(image.height, p.source_y + source_offset_y);
const source_width = if (p.source_width > 0)
@min(image.width - source_x, p.source_width)
else
@ -1077,7 +1092,11 @@ fn prepKittyPlacement(
// Calculate the width/height of our image.
const dest_width = if (p.columns > 0) p.columns * self.grid_metrics.cell_width else source_width;
const dest_height = if (p.rows > 0) p.rows * self.grid_metrics.cell_height else source_height;
const dest_height = if (p.rows > 0) rows: {
// Clip to the viewport to handle scrolling. offset_y is already in
// viewport scale so we can subtract it directly.
break :rows (p.rows * self.grid_metrics.cell_height) - offset_y;
} else source_height;
// Accumulate the placement
if (image.width > 0 and image.height > 0) {