diff --git a/boredos.iso b/boredos.iso index c4b3383..d0ca768 100644 Binary files a/boredos.iso and b/boredos.iso differ diff --git a/src/kernel/userland/browser.c b/src/kernel/userland/browser.c index 3f4629c..3e2758a 100644 --- a/src/kernel/userland/browser.c +++ b/src/kernel/userland/browser.c @@ -340,22 +340,37 @@ static void decode_image(unsigned char *data, int len, RenderElement *el) { el->img_current_frame = 0; el->next_frame_tick = sys_system(16, 0, 0, 0, 0) + (delays[0] * 60 / 1000); + uint32_t step_x = (img_w_orig << 16) / fit_w; + uint32_t step_y = (img_h_orig << 16) / fit_h; + for (int i = 0; i < frame_count; i++) { el->img_frames[i] = malloc(fit_w * fit_h * sizeof(uint32_t)); if (el->img_frames[i]) { unsigned char *src_frame = rgba + (i * img_w_orig * img_h_orig * 4); - for (int y = 0; y < fit_h; y++) { - int sy = y * img_h_orig / fit_h; - for (int x = 0; x < fit_w; x++) { - int sx = x * img_w_orig / fit_w; - int idx = (sy * img_w_orig + sx) * 4; - uint32_t r = src_frame[idx]; - uint32_t g = src_frame[idx+1]; - uint32_t b = src_frame[idx+2]; - uint32_t a = src_frame[idx+3]; - el->img_frames[i][y * fit_w + x] = (a << 24) | (r << 16) | (g << 8) | b; + uint16_t *src_h_table = malloc(fit_h * sizeof(uint16_t)); + uint16_t *src_w_table = malloc(fit_w * sizeof(uint16_t)); + + if (src_h_table && src_w_table) { + for (int y = 0; y < fit_h; y++) src_h_table[y] = (y * step_y) >> 16; + for (int x = 0; x < fit_w; x++) src_w_table[x] = (x * step_x) >> 16; + + for (int y = 0; y < fit_h; y++) { + int sy = src_h_table[y]; + uint32_t src_row_off = sy * img_w_orig; + uint32_t dst_row_off = y * fit_w; + for (int x = 0; x < fit_w; x++) { + int sx = src_w_table[x]; + int idx = (src_row_off + sx) * 4; + uint32_t r = src_frame[idx]; + uint32_t g = src_frame[idx+1]; + uint32_t b = src_frame[idx+2]; + uint32_t a = src_frame[idx+3]; + el->img_frames[i][dst_row_off + x] = (a << 24) | (r << 16) | (g << 8) | b; + } } } + if (src_h_table) free(src_h_table); + if (src_w_table) free(src_w_table); } el->img_delays[i] = delays[i]; } @@ -364,16 +379,20 @@ static void decode_image(unsigned char *data, int len, RenderElement *el) { } else { el->img_pixels = malloc(fit_w * fit_h * sizeof(uint32_t)); if (el->img_pixels) { + uint32_t step_x = (img_w_orig << 16) / fit_w; + uint32_t step_y = (img_h_orig << 16) / fit_h; for (int y = 0; y < fit_h; y++) { - int sy = y * img_h_orig / fit_h; + int sy = (y * step_y) >> 16; + uint32_t src_row_off = sy * img_w_orig; + uint32_t dst_row_off = y * fit_w; for (int x = 0; x < fit_w; x++) { - int sx = x * img_w_orig / fit_w; - int idx = (sy * img_w_orig + sx) * 4; + int sx = (x * step_x) >> 16; + int idx = (src_row_off + sx) * 4; uint32_t r = rgba[idx]; uint32_t g = rgba[idx+1]; uint32_t b = rgba[idx+2]; uint32_t a = rgba[idx+3]; - el->img_pixels[y * fit_w + x] = (a << 24) | (r << 16) | (g << 8) | b; + el->img_pixels[dst_row_off + x] = (a << 24) | (r << 16) | (g << 8) | b; } } el->img_w = fit_w; el->img_h = fit_h; diff --git a/src/kernel/userland/stb_image.h b/src/kernel/userland/stb_image.h index 4539d93..4b103ce 100644 --- a/src/kernel/userland/stb_image.h +++ b/src/kernel/userland/stb_image.h @@ -6669,35 +6669,44 @@ static void stbi__out_gif_code(stbi__gif *g, stbi__uint16 code) { stbi_uc *p, *c; int idx; + stbi__uint16 stack[4096]; + int top = 0; + stbi__uint16 current = code; - // recurse to decode the prefixes, since the linked-list is backwards, - // and working backwards through an interleaved image would be nasty - if (g->codes[code].prefix >= 0) - stbi__out_gif_code(g, g->codes[code].prefix); - - if (g->cur_y >= g->max_y) return; - - idx = g->cur_x + g->cur_y; - p = &g->out[idx]; - g->history[idx / 4] = 1; - - c = &g->color_table[g->codes[code].suffix * 4]; - if (c[3] > 128) { // don't render transparent pixels; - p[0] = c[2]; - p[1] = c[1]; - p[2] = c[0]; - p[3] = c[3]; + // Follow the chain of prefixes to the root, pushing suffixes onto the stack + while (current != (stbi__uint16)-1) { + if (top >= 4096) break; + stack[top++] = current; + current = (stbi__uint16)g->codes[current].prefix; } - g->cur_x += 4; - if (g->cur_x >= g->max_x) { - g->cur_x = g->start_x; - g->cur_y += g->step; + // Pop and process suffixes in order + while (top > 0) { + stbi__uint16 c_code = stack[--top]; + if (g->cur_y >= g->max_y) continue; - while (g->cur_y >= g->max_y && g->parse > 0) { - g->step = (1 << g->parse) * g->line_size; - g->cur_y = g->start_y + (g->step >> 1); - --g->parse; + idx = g->cur_x + g->cur_y; + p = &g->out[idx]; + g->history[idx / 4] = 1; + + c = &g->color_table[g->codes[c_code].suffix * 4]; + if (c[3] > 128) { // don't render transparent pixels; + p[0] = c[2]; + p[1] = c[1]; + p[2] = c[0]; + p[3] = c[3]; + } + g->cur_x += 4; + + if (g->cur_x >= g->max_x) { + g->cur_x = g->start_x; + g->cur_y += g->step; + + while (g->cur_y >= g->max_y && g->parse > 0) { + g->step = (1 << g->parse) * g->line_size; + g->cur_y = g->start_y + (g->step >> 1); + --g->parse; + } } } } @@ -6963,15 +6972,46 @@ static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, i } } -static void *stbi__load_gif_main_outofmem(stbi__gif *g, stbi_uc *out, int **delays) +static int stbi__gif_count_frames(stbi__context *s) { - STBI_FREE(g->out); - STBI_FREE(g->history); - STBI_FREE(g->background); + int layers = 0; + stbi_uc flags; + int tag; + int off = s->read_from_callbacks ? 0 : (int)(s->img_buffer - s->img_buffer_original); - if (out) STBI_FREE(out); - if (delays && *delays) STBI_FREE(*delays); - return stbi__errpuc("outofmem", "Out of memory"); + stbi__skip(s, 6); // GIF87a/GIF89a + stbi__skip(s, 4); // w, h + flags = stbi__get8(s); + stbi__skip(s, 2); + if (flags & 0x80) stbi__skip(s, 3 * (2 << (flags & 7))); + + while (!stbi__at_eof(s)) { + tag = stbi__get8(s); + if (tag == 0x2C) { + layers++; + stbi__skip(s, 8); + flags = stbi__get8(s); + if (flags & 0x80) stbi__skip(s, 3 * (2 << (flags & 7))); + stbi__get8(s); // LZW size + while (1) { + int len = stbi__get8(s); + if (len == 0) break; + stbi__skip(s, len); + } + } else if (tag == 0x21) { + stbi__get8(s); + while (1) { + int len = stbi__get8(s); + if (len == 0) break; + stbi__skip(s, len); + } + } else if (tag == 0x3B) break; + else break; + } + + stbi__rewind(s); + if (off) stbi__skip(s, off); + return layers; } static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, int *z, int *comp, int req_comp) @@ -6983,17 +7023,28 @@ static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, stbi_uc *two_back = 0; stbi__gif g; int stride; - int out_size = 0; - int delays_size = 0; - - STBI_NOTUSED(out_size); - STBI_NOTUSED(delays_size); + int total_layers = 0; memset(&g, 0, sizeof(g)); + + total_layers = stbi__gif_count_frames(s); + if (total_layers <= 0) return stbi__errpuc("no frames", "Corrupt GIF"); + + // Initial header parse to get dimensions + if (!stbi__gif_header(s, &g, comp, 0)) return 0; + stride = g.w * g.h * 4; + stbi__rewind(s); // Rewind again for the main loop + + out = (stbi_uc*)stbi__malloc(total_layers * stride); + if (!out) return stbi__errpuc("outofmem", "Out of memory"); + if (delays) { - *delays = 0; + *delays = (int*)stbi__malloc(total_layers * sizeof(int)); + if (!*delays) { STBI_FREE(out); return stbi__errpuc("outofmem", "Out of memory"); } } + memset(&g, 0, sizeof(g)); // Reset for real load + do { u = stbi__gif_load_next(s, &g, comp, req_comp, two_back); if (u == (stbi_uc *) s) u = 0; // end of animated gif marker @@ -7002,39 +7053,12 @@ static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, *x = g.w; *y = g.h; ++layers; - stride = g.w * g.h * 4; + + if (layers > total_layers) break; // Defensive - if (out) { - void *tmp = (stbi_uc*) STBI_REALLOC_SIZED( out, out_size, layers * stride ); - if (!tmp) - return stbi__load_gif_main_outofmem(&g, out, delays); - else { - out = (stbi_uc*) tmp; - out_size = layers * stride; - } - - if (delays) { - int *new_delays = (int*) STBI_REALLOC_SIZED( *delays, delays_size, sizeof(int) * layers ); - if (!new_delays) - return stbi__load_gif_main_outofmem(&g, out, delays); - *delays = new_delays; - delays_size = layers * sizeof(int); - } - } else { - out = (stbi_uc*)stbi__malloc( layers * stride ); - if (!out) - return stbi__load_gif_main_outofmem(&g, out, delays); - out_size = layers * stride; - if (delays) { - *delays = (int*) stbi__malloc( layers * sizeof(int) ); - if (!*delays) - return stbi__load_gif_main_outofmem(&g, out, delays); - delays_size = layers * sizeof(int); - } - } memcpy( out + ((layers - 1) * stride), u, stride ); if (layers >= 2) { - two_back = out - 2 * stride; + two_back = out + (layers - 2) * stride; } if (delays) {