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

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:16:59 -08:00
committed by GitHub
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) {