feat: expand and fix issues in SVG renderer

This commit is contained in:
2026-08-26 12:04:38 +02:00
parent ffc9756e67
commit 8afadb44cb
5 changed files with 1972 additions and 316 deletions
File diff suppressed because it is too large Load Diff
+49 -3
View File
@@ -49,10 +49,56 @@ bool svgdoc_render(SvgDoc* doc, float target_scale, int max_edge) {
if (new_w < 1) new_w = 1;
if (new_h < 1) new_h = 1;
gui::SvgIcon icon = gui::svg_render(
// Supersample ordinary viewing sizes to smooth path and stroke edges.
// Very large zoomed renders stay at 1x to keep memory bounded.
static constexpr int SS = 2;
static constexpr int SS_MAX_OUTPUT_EDGE = 1024;
int longest = new_w > new_h ? new_w : new_h;
int render_ss = longest <= SS_MAX_OUTPUT_EDGE ? SS : 1;
gui::SvgIcon rendered = gui::svg_render(
(const char*)doc->source, doc->source_len,
new_w, new_h, gui::Color::from_rgb(0, 0, 0));
if (!icon.pixels) return false;
new_w * render_ss, new_h * render_ss,
gui::Color::from_rgb(0, 0, 0));
if (!rendered.pixels) return false;
gui::SvgIcon icon = rendered;
if (render_ss > 1) {
uint32_t* downsampled = (uint32_t*)montauk::malloc(
(uint64_t)new_w * (uint64_t)new_h * sizeof(uint32_t));
if (downsampled) {
for (int y = 0; y < new_h; ++y) {
for (int x = 0; x < new_w; ++x) {
uint32_t sum_a = 0, sum_pr = 0, sum_pg = 0, sum_pb = 0;
for (int sy = 0; sy < render_ss; ++sy) {
for (int sx = 0; sx < render_ss; ++sx) {
uint32_t pixel = rendered.pixels[
(y * render_ss + sy) * rendered.width + x * render_ss + sx];
uint32_t a = (pixel >> 24) & 0xff;
sum_a += a;
sum_pr += ((pixel >> 16) & 0xff) * a;
sum_pg += ((pixel >> 8) & 0xff) * a;
sum_pb += (pixel & 0xff) * a;
}
}
uint32_t samples = render_ss * render_ss;
uint32_t a = sum_a / samples;
uint32_t r = sum_a ? sum_pr / sum_a : 0;
uint32_t g = sum_a ? sum_pg / sum_a : 0;
uint32_t b = sum_a ? sum_pb / sum_a : 0;
downsampled[y * new_w + x] = (a << 24) | (r << 16) | (g << 8) | b;
}
}
montauk::mfree(rendered.pixels);
icon = {downsampled, new_w, new_h};
} else {
montauk::mfree(rendered.pixels);
icon = gui::svg_render(
(const char*)doc->source, doc->source_len,
new_w, new_h, gui::Color::from_rgb(0, 0, 0));
if (!icon.pixels) return false;
}
}
if (doc->pixels) montauk::mfree(doc->pixels);
doc->pixels = icon.pixels;