diff options
Diffstat (limited to '')
-rw-r--r-- | image.c | 186 |
1 files changed, 186 insertions, 0 deletions
@@ -0,0 +1,186 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/types.h> + +#include <stdlib.h> +#include <string.h> + +#include "tmux.h" + +static struct images all_images = TAILQ_HEAD_INITIALIZER(all_images); +static u_int all_images_count; + +static void +image_free(struct image *im) +{ + struct screen *s = im->s; + + TAILQ_REMOVE(&all_images, im, all_entry); + all_images_count--; + + TAILQ_REMOVE(&s->images, im, entry); + sixel_free(im->data); + free(im->fallback); + free(im); +} + +int +image_free_all(struct screen *s) +{ + struct image *im, *im1; + int redraw = !TAILQ_EMPTY(&s->images); + + TAILQ_FOREACH_SAFE(im, &s->images, entry, im1) + image_free(im); + return (redraw); +} + +/* Create text placeholder for an image. */ +static void +image_fallback(char **ret, u_int sx, u_int sy) +{ + char *buf, *label; + u_int py, size, lsize; + + /* Allocate first line. */ + lsize = xasprintf(&label, "SIXEL IMAGE (%ux%u)\r\n", sx, sy) + 1; + if (sx < lsize - 3) + size = lsize - 1; + else + size = sx + 2; + + /* Remaining lines. Every placeholder line has \r\n at the end. */ + size += (sx + 2) * (sy - 1) + 1; + *ret = buf = xmalloc(size); + + /* Render first line. */ + if (sx < lsize - 3) { + memcpy(buf, label, lsize); + buf += lsize - 1; + } else { + memcpy(buf, label, lsize - 3); + buf += lsize - 3; + memset(buf, '+', sx - lsize + 3); + buf += sx - lsize + 3; + snprintf(buf, 3, "\r\n"); + buf += 2; + } + + /* Remaining lines. */ + for (py = 1; py < sy; py++) { + memset(buf, '+', sx); + buf += sx; + snprintf(buf, 3, "\r\n"); + buf += 2; + } + + free(label); +} + +struct image* +image_store(struct screen *s, struct sixel_image *si) +{ + struct image *im; + + im = xcalloc(1, sizeof *im); + im->s = s; + im->data = si; + + im->px = s->cx; + im->py = s->cy; + sixel_size_in_cells(si, &im->sx, &im->sy); + + image_fallback(&im->fallback, im->sx, im->sy); + + TAILQ_INSERT_TAIL(&s->images, im, entry); + + TAILQ_INSERT_TAIL(&all_images, im, all_entry); + if (++all_images_count == 10/*XXX*/) + image_free(TAILQ_FIRST(&all_images)); + + return (im); +} + +int +image_check_line(struct screen *s, u_int py, u_int ny) +{ + struct image *im, *im1; + int redraw = 0; + + TAILQ_FOREACH_SAFE(im, &s->images, entry, im1) { + if (py + ny > im->py && py < im->py + im->sy) { + image_free(im); + redraw = 1; + } + } + return (redraw); +} + +int +image_check_area(struct screen *s, u_int px, u_int py, u_int nx, u_int ny) +{ + struct image *im, *im1; + int redraw = 0; + + TAILQ_FOREACH_SAFE(im, &s->images, entry, im1) { + if (py + ny <= im->py || py >= im->py + im->sy) + continue; + if (px + nx <= im->px || px >= im->px + im->sx) + continue; + image_free(im); + redraw = 1; + } + return (redraw); +} + +int +image_scroll_up(struct screen *s, u_int lines) +{ + struct image *im, *im1; + int redraw = 0; + u_int sx, sy; + struct sixel_image *new; + + TAILQ_FOREACH_SAFE(im, &s->images, entry, im1) { + if (im->py >= lines) { + im->py -= lines; + redraw = 1; + continue; + } + if (im->py + im->sy <= lines) { + image_free(im); + redraw = 1; + continue; + } + sx = im->sx; + sy = (im->py + im->sy) - lines; + + new = sixel_scale(im->data, 0, 0, 0, im->sy - sy, sx, sy, 1); + sixel_free(im->data); + im->data = new; + + im->py = 0; + sixel_size_in_cells(im->data, &im->sx, &im->sy); + + free(im->fallback); + image_fallback(&im->fallback, im->sx, im->sy); + redraw = 1; + } + return (redraw); +} |