aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorHarry Jeffery <harry@exec64.co.uk>2019-08-30 00:40:29 +0100
committerHarry Jeffery <harry@exec64.co.uk>2019-08-30 00:40:29 +0100
commit8b2aaf102f76921721209459eea10bed2094a730 (patch)
tree6942c0e840252e8832aa0a8276435045525a40b4 /src
parent4c0123bb3b449a2ea45b3e831db725d853bb03a1 (diff)
downloadimv-8b2aaf102f76921721209459eea10bed2094a730.tar.gz
source: Refactor out common async logic
Diffstat (limited to 'src')
-rw-r--r--src/backend_freeimage.c207
-rw-r--r--src/backend_libjpeg.c139
-rw-r--r--src/backend_libpng.c132
-rw-r--r--src/backend_librsvg.c116
-rw-r--r--src/backend_libtiff.c149
-rw-r--r--src/image.c2
-rw-r--r--src/imv.c59
-rw-r--r--src/source.c132
-rw-r--r--src/source.h79
-rw-r--r--src/source_private.h24
-rw-r--r--src/viewport.c2
11 files changed, 414 insertions, 627 deletions
diff --git a/src/backend_freeimage.c b/src/backend_freeimage.c
index bdddff2..f3b8d7e 100644
--- a/src/backend_freeimage.c
+++ b/src/backend_freeimage.c
@@ -1,28 +1,35 @@
#include "backend.h"
-#include "source.h"
+#include "bitmap.h"
+#include "image.h"
#include "log.h"
-
-#include <assert.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
+#include "source.h"
+#include "source_private.h"
#include <FreeImage.h>
+#include <stdlib.h>
struct private {
+ char *path;
FIMEMORY *memory;
FREE_IMAGE_FORMAT format;
FIMULTIBITMAP *multibitmap;
FIBITMAP *last_frame;
+ int num_frames;
+ int next_frame;
+ int width;
+ int height;
};
-static void source_free(struct imv_source *src)
+static void free_private(void *raw_private)
{
- pthread_mutex_lock(&src->busy);
- free(src->name);
- src->name = NULL;
+ if (!raw_private) {
+ return;
+ }
+
+ struct private *private = raw_private;
- struct private *private = src->private;
+ free(private->path);
+ private->path = NULL;
if (private->memory) {
FreeImage_CloseMemory(private->memory);
@@ -40,11 +47,6 @@ static void source_free(struct imv_source *src)
}
free(private);
- src->private = NULL;
-
- pthread_mutex_unlock(&src->busy);
- pthread_mutex_destroy(&src->busy);
- free(src);
}
static struct imv_image *to_image(FIBITMAP *in_bmp)
@@ -95,55 +97,20 @@ static FIBITMAP *normalise_bitmap(FIBITMAP *input)
return output;
}
-static void report_error(struct imv_source *src, const char *error)
+static void first_frame(void *raw_private, struct imv_image **image, int *frametime)
{
- imv_log(IMV_ERROR, "freeimage: %s\n", error);
-
- assert(src->callback);
-
- struct imv_source_message msg;
- msg.source = src;
- msg.user_data = src->user_data;
- msg.image = NULL;
- msg.error = error;
+ *image = NULL;
+ *frametime = 0;
- pthread_mutex_unlock(&src->busy);
- src->callback(&msg);
-}
-
-static void send_bitmap(struct imv_source *src, FIBITMAP *fibitmap, int frametime)
-{
- imv_log(IMV_DEBUG, "freeimage: returning bitmap\n");
- assert(src->callback);
-
- struct imv_source_message msg;
- msg.source = src;
- msg.user_data = src->user_data;
- msg.image = to_image(fibitmap);
- msg.frametime = frametime;
- msg.error = NULL;
-
- pthread_mutex_unlock(&src->busy);
- src->callback(&msg);
-}
-
-static void *first_frame(struct imv_source *src)
-{
- /* Don't run if this source is already active */
- if (pthread_mutex_trylock(&src->busy)) {
- return NULL;
- }
imv_log(IMV_DEBUG, "freeimage: first_frame called\n");
FIBITMAP *bmp = NULL;
- struct private *private = src->private;
-
- int frametime = 0;
+ struct private *private = raw_private;
if (private->format == FIF_GIF) {
- if (src->name) {
- private->multibitmap = FreeImage_OpenMultiBitmap(FIF_GIF, src->name,
+ if (private->path) {
+ private->multibitmap = FreeImage_OpenMultiBitmap(FIF_GIF, private->path,
/* don't create file */ 0,
/* read only */ 1,
/* keep in memory */ 1,
@@ -153,110 +120,109 @@ static void *first_frame(struct imv_source *src)
private->memory,
/* flags */ GIF_LOAD256);
} else {
- report_error(src, "src->name and private->memory both NULL");
- return NULL;
+ imv_log(IMV_ERROR, "private->path and private->memory both NULL");
+ return;
}
if (!private->multibitmap) {
- report_error(src, "first frame already loaded");
- return NULL;
+ imv_log(IMV_ERROR, "first frame already loaded");
+ return;
}
FIBITMAP *frame = FreeImage_LockPage(private->multibitmap, 0);
- src->num_frames = FreeImage_GetPageCount(private->multibitmap);
+ private->num_frames = FreeImage_GetPageCount(private->multibitmap);
/* Get duration of first frame */
FITAG *tag = NULL;
FreeImage_GetMetadata(FIMD_ANIMATION, frame, "FrameTime", &tag);
- if(FreeImage_GetTagValue(tag)) {
- frametime = *(int*)FreeImage_GetTagValue(tag);
+ if (FreeImage_GetTagValue(tag)) {
+ *frametime = *(int*)FreeImage_GetTagValue(tag);
} else {
- frametime = 100; /* default value for gifs */
+ *frametime = 100; /* default value for gifs */
}
bmp = FreeImage_ConvertTo24Bits(frame);
FreeImage_UnlockPage(private->multibitmap, frame, 0);
} else { /* not a gif */
- src->num_frames = 1;
+ private->num_frames = 1;
int flags = (private->format == FIF_JPEG) ? JPEG_EXIFROTATE : 0;
FIBITMAP *fibitmap = NULL;
- if (src->name) {
- fibitmap = FreeImage_Load(private->format, src->name, flags);
+ if (private->path) {
+ fibitmap = FreeImage_Load(private->format, private->path, flags);
} else if (private->memory) {
fibitmap = FreeImage_LoadFromMemory(private->format, private->memory, flags);
}
if (!fibitmap) {
- report_error(src, "FreeImage_Load returned NULL");
- return NULL;
+ imv_log(IMV_ERROR, "FreeImage_Load returned NULL");
+ return;
}
bmp = normalise_bitmap(fibitmap);
}
- src->width = FreeImage_GetWidth(bmp);
- src->height = FreeImage_GetHeight(bmp);
+ private->width = FreeImage_GetWidth(bmp);
+ private->height = FreeImage_GetHeight(bmp);
private->last_frame = bmp;
- send_bitmap(src, bmp, frametime);
- return NULL;
+ private->next_frame = 1 % private->num_frames;
+
+ *image = to_image(bmp);
}
-static void *next_frame(struct imv_source *src)
+static void next_frame(void *raw_private, struct imv_image **image, int *frametime)
{
- /* Don't run if this source is already active */
- if (pthread_mutex_trylock(&src->busy)) {
- return NULL;
- }
+ *image = NULL;
+ *frametime = 0;
+
+ struct private *private = raw_private;
- struct private *private = src->private;
- if (src->num_frames == 1) {
- send_bitmap(src, private->last_frame, 0);
- return NULL;
+ if (private->num_frames == 1) {
+ *image = to_image(private->last_frame);
+ return;
}
FITAG *tag = NULL;
char disposal_method = 0;
- int frametime = 0;
short top = 0;
short left = 0;
- FIBITMAP *frame = FreeImage_LockPage(private->multibitmap, src->next_frame);
+ FIBITMAP *frame = FreeImage_LockPage(private->multibitmap, private->next_frame);
FIBITMAP *frame32 = FreeImage_ConvertTo32Bits(frame);
/* First frame is always going to use the raw frame */
- if(src->next_frame > 0) {
+ if (private->next_frame > 0) {
FreeImage_GetMetadata(FIMD_ANIMATION, frame, "DisposalMethod", &tag);
- if(FreeImage_GetTagValue(tag)) {
+ if (FreeImage_GetTagValue(tag)) {
disposal_method = *(char*)FreeImage_GetTagValue(tag);
}
}
FreeImage_GetMetadata(FIMD_ANIMATION, frame, "FrameLeft", &tag);
- if(FreeImage_GetTagValue(tag)) {
+ if (FreeImage_GetTagValue(tag)) {
left = *(short*)FreeImage_GetTagValue(tag);
}
FreeImage_GetMetadata(FIMD_ANIMATION, frame, "FrameTop", &tag);
- if(FreeImage_GetTagValue(tag)) {
+ if (FreeImage_GetTagValue(tag)) {
top = *(short*)FreeImage_GetTagValue(tag);
}
FreeImage_GetMetadata(FIMD_ANIMATION, frame, "FrameTime", &tag);
- if(FreeImage_GetTagValue(tag)) {
- frametime = *(int*)FreeImage_GetTagValue(tag);
+ if (FreeImage_GetTagValue(tag)) {
+ *frametime = *(int*)FreeImage_GetTagValue(tag);
}
/* some gifs don't provide a frame time at all */
- if(frametime == 0) {
- frametime = 100;
+ if (*frametime == 0) {
+ *frametime = 100;
}
FreeImage_UnlockPage(private->multibitmap, frame, 0);
/* If this frame is inset, we need to expand it for compositing */
- if(src->width != (int)FreeImage_GetWidth(frame32) ||
- src->height != (int)FreeImage_GetHeight(frame32)) {
- FIBITMAP *expanded = FreeImage_Allocate(src->width, src->height, 32, 0,0,0);
+ if (private->width != (int)FreeImage_GetWidth(frame32) ||
+ private->height != (int)FreeImage_GetHeight(frame32)) {
+ FIBITMAP *expanded = FreeImage_Allocate(private->width, private->height, 32, 0,0,0);
FreeImage_Paste(expanded, frame32, left, top, 255);
FreeImage_Unload(frame32);
frame32 = expanded;
@@ -265,7 +231,7 @@ static void *next_frame(struct imv_source *src)
switch(disposal_method) {
case 0: /* nothing specified, fall through to compositing */
case 1: /* composite over previous frame */
- if(private->last_frame && src->next_frame > 0) {
+ if (private->last_frame && private->next_frame > 0) {
FIBITMAP *bg_frame = FreeImage_ConvertTo24Bits(private->last_frame);
FreeImage_Unload(private->last_frame);
FIBITMAP *comp = FreeImage_Composite(frame32, 1, NULL, bg_frame);
@@ -281,25 +247,30 @@ static void *next_frame(struct imv_source *src)
}
break;
case 2: /* TODO - set to background, composite over that */
- if(private->last_frame) {
+ if (private->last_frame) {
FreeImage_Unload(private->last_frame);
}
private->last_frame = frame32;
break;
case 3: /* TODO - restore to previous content */
- if(private->last_frame) {
+ if (private->last_frame) {
FreeImage_Unload(private->last_frame);
}
private->last_frame = frame32;
break;
}
- src->next_frame = (src->next_frame + 1) % src->num_frames;
+ private->next_frame = (private->next_frame + 1) % private->num_frames;
- send_bitmap(src, private->last_frame, frametime);
- return NULL;
+ *image = to_image(private->last_frame);
}
+static const struct imv_source_vtable vtable = {
+ .load_first_frame = first_frame,
+ .load_next_frame = next_frame,
+ .free = free_private
+};
+
static enum backend_result open_path(const char *path, struct imv_source **src)
{
imv_log(IMV_DEBUG, "freeimage: open_path(%s)\n", path);
@@ -312,21 +283,9 @@ static enum backend_result open_path(const char *path, struct imv_source **src)
struct private *private = calloc(1, sizeof(struct private));
private->format = fmt;
+ private->path = strdup(path);
- struct imv_source *source = calloc(1, sizeof *source);
- source->name = strdup(path);
- source->width = 0;
- source->height = 0;
- source->num_frames = 0;
- pthread_mutex_init(&source->busy, NULL);
- source->load_first_frame = &first_frame;
- source->load_next_frame = &next_frame;
- source->free = &source_free;
- source->callback = NULL;
- source->user_data = NULL;
- source->private = private;
- *src = source;
-
+ *src = imv_source_create(&vtable, private);
return BACKEND_SUCCESS;
}
@@ -344,21 +303,9 @@ static enum backend_result open_memory(void *data, size_t len, struct imv_source
struct private *private = calloc(1, sizeof(struct private));
private->format = fmt;
private->memory = fmem;
+ private->path = NULL;
- struct imv_source *source = calloc(1, sizeof *source);
- source->name = NULL;
- source->width = 0;
- source->height = 0;
- source->num_frames = 0;
- pthread_mutex_init(&source->busy, NULL);
- source->load_first_frame = &first_frame;
- source->load_next_frame = &next_frame;
- source->free = &source_free;
- source->callback = NULL;
- source->user_data = NULL;
- source->private = private;
- *src = source;
-
+ *src = imv_source_create(&vtable, private);
return BACKEND_SUCCESS;
}
diff --git a/src/backend_libjpeg.c b/src/backend_libjpeg.c
index 34dfb43..c9d70df 100644
--- a/src/backend_libjpeg.c
+++ b/src/backend_libjpeg.c
@@ -1,5 +1,8 @@
#include "backend.h"
+#include "bitmap.h"
+#include "image.h"
#include "source.h"
+#include "source_private.h"
#include <assert.h>
#include <stdlib.h>
@@ -16,15 +19,16 @@ struct private {
void *data;
size_t len;
tjhandle jpeg;
+ int width;
+ int height;
};
-static void source_free(struct imv_source *src)
+static void free_private(void *raw_private)
{
- pthread_mutex_lock(&src->busy);
- free(src->name);
- src->name = NULL;
-
- struct private *private = src->private;
+ if (!raw_private) {
+ return;
+ }
+ struct private *private = raw_private;
tjDestroy(private->jpeg);
if (private->fd >= 0) {
munmap(private->data, private->len);
@@ -34,77 +38,38 @@ static void source_free(struct imv_source *src)
}
private->data = NULL;
- free(src->private);
- src->private = NULL;
-
- pthread_mutex_unlock(&src->busy);
- pthread_mutex_destroy(&src->busy);
- free(src);
-}
-
-static struct imv_image *to_image(int width, int height, void *bitmap)
-{
- struct imv_bitmap *bmp = malloc(sizeof *bmp);
- bmp->width = width;
- bmp->height = height;
- bmp->format = IMV_ABGR;
- bmp->data = bitmap;
- struct imv_image *image = imv_image_create_from_bitmap(bmp);
- return image;
-}
-
-static void report_error(struct imv_source *src)
-{
- assert(src->callback);
-
- struct imv_source_message msg;
- msg.source = src;
- msg.user_data = src->user_data;
- msg.image = NULL;
- msg.error = "Internal error";
-
- pthread_mutex_unlock(&src->busy);
- src->callback(&msg);
+ free(private);
}
-static void send_bitmap(struct imv_source *src, void *bitmap)
+static void load_image(void *raw_private, struct imv_image **image, int *frametime)
{
- assert(src->callback);
+ *image = NULL;
+ *frametime = 0;
- struct imv_source_message msg;
- msg.source = src;
- msg.user_data = src->user_data;
- msg.image = to_image(src->width, src->height, bitmap);
- msg.frametime = 0;
- msg.error = NULL;
+ struct private *private = raw_private;
- pthread_mutex_unlock(&src->busy);
- src->callback(&msg);
-}
-
-static void *load_image(struct imv_source *src)
-{
- /* Don't run if this source is already active */
- if (pthread_mutex_trylock(&src->busy)) {
- return NULL;
- }
-
- struct private *private = src->private;
-
- void *bitmap = malloc(src->height * src->width * 4);
+ void *bitmap = malloc(private->height * private->width * 4);
int rcode = tjDecompress2(private->jpeg, private->data, private->len,
- bitmap, src->width, 0, src->height, TJPF_RGBA, TJFLAG_FASTDCT);
+ bitmap, private->width, 0, private->height, TJPF_RGBA, TJFLAG_FASTDCT);
if (rcode) {
free(bitmap);
- report_error(src);
- return NULL;
+ return;
}
- send_bitmap(src, bitmap);
- return NULL;
+ struct imv_bitmap *bmp = malloc(sizeof *bmp);
+ bmp->width = private->width;
+ bmp->height = private->height;
+ bmp->format = IMV_ABGR;
+ bmp->data = bitmap;
+ *image = imv_image_create_from_bitmap(bmp);
}
+static const struct imv_source_vtable vtable = {
+ .load_first_frame = load_image,
+ .free = free_private
+};
+
static enum backend_result open_path(const char *path, struct imv_source **src)
{
struct private private;
@@ -135,9 +100,8 @@ static enum backend_result open_path(const char *path, struct imv_source **src)
return BACKEND_UNSUPPORTED;
}
- int width, height;
int rcode = tjDecompressHeader(private.jpeg, private.data, private.len,
- &width, &height);
+ &private.width, &private.height);
if (rcode) {
tjDestroy(private.jpeg);
munmap(private.data, private.len);
@@ -145,22 +109,10 @@ static enum backend_result open_path(const char *path, struct imv_source **src)
return BACKEND_UNSUPPORTED;
}
- struct imv_source *source = calloc(1, sizeof *source);
- source->name = strdup(path);
- source->width = width;
- source->height = height;
- source->num_frames = 1;
- source->next_frame = 1;
- pthread_mutex_init(&source->busy, NULL);
- source->load_first_frame = &load_image;
- source->load_next_frame = NULL;
- source->free = &source_free;
- source->callback = NULL;
- source->user_data = NULL;
- source->private = malloc(sizeof private);
- memcpy(source->private, &private, sizeof private);
-
- *src = source;
+ struct private *new_private = malloc(sizeof private);
+ memcpy(new_private, &private, sizeof private);
+
+ *src = imv_source_create(&vtable, new_private);
return BACKEND_SUCCESS;
}
@@ -177,30 +129,17 @@ static enum backend_result open_memory(void *data, size_t len, struct imv_source
return BACKEND_UNSUPPORTED;
}
- int width, height;
int rcode = tjDecompressHeader(private.jpeg, private.data, private.len,
- &width, &height);
+ &private.width, &private.height);
if (rcode) {
tjDestroy(private.jpeg);
return BACKEND_UNSUPPORTED;
}
- struct imv_source *source = calloc(1, sizeof *source);
- source->name = strdup("-");
- source->width = width;
- source->height = height;
- source->num_frames = 1;
- source->next_frame = 1;
- pthread_mutex_init(&source->busy, NULL);
- source->load_first_frame = &load_image;
- source->load_next_frame = NULL;
- source->free = &source_free;
- source->callback = NULL;
- source->user_data = NULL;
- source->private = malloc(sizeof private);
- memcpy(source->private, &private, sizeof private);
-
- *src = source;
+ struct private *new_private = malloc(sizeof private);
+ memcpy(new_private, &private, sizeof private);
+
+ *src = imv_source_create(&vtable, new_private);
return BACKEND_SUCCESS;
}
diff --git a/src/backend_libpng.c b/src/backend_libpng.c
index 88a163e..ef94028 100644
--- a/src/backend_libpng.c
+++ b/src/backend_libpng.c
@@ -1,11 +1,11 @@
#include "backend.h"
-#include "source.h"
+#include "bitmap.h"
+#include "image.h"
#include "log.h"
+#include "source.h"
+#include "source_private.h"
-#include <assert.h>
#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
#include <png.h>
@@ -15,104 +15,64 @@ struct private {
png_infop info;
};
-static void source_free(struct imv_source *src)
+static void free_private(void *raw_private)
{
- pthread_mutex_lock(&src->busy);
- free(src->name);
- src->name = NULL;
+ if (!raw_private) {
+ return;
+ }
- struct private *private = src->private;
+ struct private *private = raw_private;
png_destroy_read_struct(&private->png, &private->info, NULL);
if (private->file) {
fclose(private->file);
}
-
- free(src->private);
- src->private = NULL;
-
- pthread_mutex_unlock(&src->busy);
- pthread_mutex_destroy(&src->busy);
- free(src);
-}
-
-static struct imv_image *to_image(int width, int height, void *bitmap)
-{
- struct imv_bitmap *bmp = malloc(sizeof *bmp);
- bmp->width = width;
- bmp->height = height;
- bmp->format = IMV_ABGR;
- bmp->data = bitmap;
- struct imv_image *image = imv_image_create_from_bitmap(bmp);
- return image;
-}
-
-static void report_error(struct imv_source *src)
-{
- assert(src->callback);
-
- struct imv_source_message msg;
- msg.source = src;
- msg.user_data = src->user_data;
- msg.image = NULL;
- msg.error = "Internal error";
-
- pthread_mutex_unlock(&src->busy);
- src->callback(&msg);
+ free(private);
}
-
-static void send_bitmap(struct imv_source *src, void *bitmap)
+static void load_image(void *raw_private, struct imv_image **image, int *frametime)
{
- assert(src->callback);
-
- struct imv_source_message msg;
- msg.source = src;
- msg.user_data = src->user_data;
- msg.image = to_image(src->width, src->height, bitmap);
- msg.frametime = 0;
- msg.error = NULL;
-
- pthread_mutex_unlock(&src->busy);
- src->callback(&msg);
-}
-
-static void *load_image(struct imv_source *src)
-{
- /* Don't run if this source is already active */
- if (pthread_mutex_trylock(&src->busy)) {
- return NULL;
- }
-
- struct private *private = src->private;
+ *image = NULL;
+ *frametime = 0;
+ struct private *private = raw_private;
if (setjmp(png_jmpbuf(private->png))) {
- report_error(src);
- return NULL;
+ return;
}
- png_bytep *rows = malloc(sizeof(png_bytep) * src->height);
+ const int width = png_get_image_width(private->png, private->info);
+ const int height = png_get_image_height(private->png, private->info);
+
+ png_bytep *rows = malloc(sizeof(png_bytep) * height);
size_t row_len = png_get_rowbytes(private->png, private->info);
- rows[0] = malloc(src->height * row_len);
- for (int y = 1; y < src->height; ++y) {
+ rows[0] = malloc(height * row_len);
+ for (int y = 1; y < height; ++y) {
rows[y] = rows[0] + row_len * y;
}
if (setjmp(png_jmpbuf(private->png))) {
- free(rows[0]);
- free(rows);
- report_error(src);
- return NULL;
+ return;
}
png_read_image(private->png, rows);
- void *bmp = rows[0];
+ void *raw_bmp = rows[0];
free(rows);
fclose(private->file);
private->file = NULL;
- send_bitmap(src, bmp);
- return NULL;
+
+
+ struct imv_bitmap *bmp = malloc(sizeof *bmp);
+ bmp->width = width;
+ bmp->height = height;
+ bmp->format = IMV_ABGR;
+ bmp->data = raw_bmp;
+ *image = imv_image_create_from_bitmap(bmp);
}
+static const struct imv_source_vtable vtable = {
+ .load_first_frame = load_image,
+ .free = free_private
+};
+
static enum backend_result open_path(const char *path, struct imv_source **src)
{
@@ -127,7 +87,7 @@ static enum backend_result open_path(const char *path, struct imv_source **src)
return BACKEND_UNSUPPORTED;
}
- struct private *private = malloc(sizeof *private);
+ struct private *private = calloc(1, sizeof *private);
private->file = f;
private->png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (!private->png) {
@@ -168,30 +128,14 @@ static enum backend_result open_path(const char *path, struct imv_source **src)
png_get_bit_depth(private->png, private->info),
png_get_color_type(private->png, private->info));
- struct imv_source *source = calloc(1, sizeof *source);
- source->name = strdup(path);
if (setjmp(png_jmpbuf(private->png))) {
- free(source->name);
- free(source);
png_destroy_read_struct(&private->png, &private->info, NULL);
fclose(private->file);
free(private);
return BACKEND_UNSUPPORTED;
}
- source->width = png_get_image_width(private->png, private->info);
- source->height = png_get_image_height(private->png, private->info);
- source->num_frames = 1;
- source->next_frame = 1;
- pthread_mutex_init(&source->busy, NULL);
- source->load_first_frame = &load_image;
- source->load_next_frame = NULL;
- source->free = &source_free;
- source->callback = NULL;
- source->user_data = NULL;
- source->private = private;
-
- *src = source;
+ *src = imv_source_create(&vtable, private);
return BACKEND_SUCCESS;
}
diff --git a/src/backend_librsvg.c b/src/backend_librsvg.c
index ff27477..9023b10 100644
--- a/src/backend_librsvg.c
+++ b/src/backend_librsvg.c
@@ -1,12 +1,12 @@
#include "backend.h"
+#include "image.h"
#include "source.h"
+#include "source_private.h"
-#include <assert.h>
+#include <librsvg/rsvg.h>
#include <stdlib.h>
#include <string.h>
-#include <librsvg/rsvg.h>
-
/* Some systems like GNU/Hurd don't define PATH_MAX */
#ifndef PATH_MAX
#define PATH_MAX 4096
@@ -15,85 +15,40 @@
struct private {
void *data;
size_t len;
+ char path[PATH_MAX+8];
};
-static void source_free(struct imv_source *src)
-{
- pthread_mutex_lock(&src->busy);
- free(src->name);
- src->name = NULL;
-
- struct private *private = src->private;
- free(private);
- src->private = NULL;
-
- pthread_mutex_unlock(&src->busy);
- pthread_mutex_destroy(&src->busy);
- free(src);
-}
-
-static void report_error(struct imv_source *src)
+static void free_private(void *raw_private)
{
- assert(src->callback);
-
- struct imv_source_message msg;
- msg.source = src;
- msg.user_data = src->user_data;
- msg.image = NULL;
- msg.error = "Internal error";
-
- pthread_mutex_unlock(&src->busy);
- src->callback(&msg);
+ free(raw_private);
}
-static void send_svg(struct imv_source *src, RsvgHandle *handle)
+static void load_image(void *raw_private, struct imv_image **image, int *frametime)
{
- assert(src->callback);
+ *image = NULL;
+ *frametime = 0;
- struct imv_source_message msg;
- msg.source = src;
- msg.user_data = src->user_data;
- msg.image = imv_image_create_from_svg(handle);
- msg.frametime = 0;
- msg.error = NULL;
-
- pthread_mutex_unlock(&src->busy);
- src->callback(&msg);
-}
-
-static void *load_image(struct imv_source *src)
-{
- /* Don't run if this source is already active */
- if (pthread_mutex_trylock(&src->busy)) {
- return NULL;
- }
+ struct private *private = raw_private;
RsvgHandle *handle = NULL;
GError *error = NULL;
- struct private *private = src->private;
if (private->data) {
handle = rsvg_handle_new_from_data(private->data, private->len, &error);
} else {
- char path[PATH_MAX+8];
- snprintf(path, sizeof path, "file://%s", src->name);
- handle = rsvg_handle_new_from_file(path, &error);
+ handle = rsvg_handle_new_from_file(private->path, &error);
}
- if (!handle) {
- report_error(src);
- return NULL;
+ if (handle) {
+ *image = imv_image_create_from_svg(handle);
}
-
- RsvgDimensionData dim;
- rsvg_handle_get_dimensions(handle, &dim);
- src->width = dim.width;
- src->height = dim.height;
-
- send_svg(src, handle);
- return NULL;
}
+static const struct imv_source_vtable vtable = {
+ .load_first_frame = load_image,
+ .free = free_private
+};
+
static enum backend_result open_path(const char *path, struct imv_source **src)
{
/* Look for an <SVG> tag near the start of the file */
@@ -113,23 +68,9 @@ static enum backend_result open_path(const char *path, struct imv_source **src)
struct private *private = malloc(sizeof *private);
private->data = NULL;
private->len = 0;
+ snprintf(private->path, sizeof private->path, "file://%s", path);
- struct imv_source *source = calloc(1, sizeof *source);
- source->name = strdup(path);
-
- source->width = 1024;
- source->height = 1024;
- source->num_frames = 1;
- source->next_frame = 1;
- pthread_mutex_init(&source->busy, NULL);
- source->load_first_frame = &load_image;
- source->load_next_frame = NULL;
- source->free = &source_free;
- source->callback = NULL;
- source->user_data = NULL;
- source->private = private;
-
- *src = source;
+ *src = imv_source_create(&vtable, private);
return BACKEND_SUCCESS;
}
@@ -151,22 +92,7 @@ static enum backend_result open_memory(void *data, size_t len, struct imv_source
private->data = data;
private->len = len;
- struct imv_source *source = calloc(1, sizeof *source);
- source->name = strdup("-");
-
- source->width = 1024;
- source->height = 1024;
- source->num_frames = 1;
- source->next_frame = 1;
- pthread_mutex_init(&source->busy, NULL);
- source->load_first_frame = &load_image;
- source->load_next_frame = NULL;
- source->free = &source_free;
- source->callback = NULL;
- source->user_data = NULL;
- source->private = private;
-
- *src = source;
+ *src = imv_source_create(&vtable, private);
return BACKEND_SUCCESS;
}
diff --git a/src/backend_libtiff.c b/src/backend_libtiff.c
index de7fc70..b0e955f 100644
--- a/src/backend_libtiff.c
+++ b/src/backend_libtiff.c
@@ -1,20 +1,19 @@
#include "backend.h"
+#include "bitmap.h"
+#include "image.h"
#include "source.h"
+#include "source_private.h"
-#include <assert.h>
#include <stdlib.h>
-#include <stdio.h>
-#include <sys/mman.h>
#include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-
#include <tiffio.h>
struct private {
TIFF *tiff;
void *data;
size_t pos, len;
+ int width;
+ int height;
};
static tsize_t mem_read(thandle_t data, tdata_t buffer, tsize_t len)
@@ -60,93 +59,53 @@ static toff_t mem_size(thandle_t data)
return private->len;
}
-static void source_free(struct imv_source *src)
+static void free_private(void *raw_private)
{
- pthread_mutex_lock(&src->busy);
- free(src->name);
- src->name = NULL;
+ if (!raw_private) {
+ return;
+ }
- struct private *private = src->private;
+ struct private *private = raw_private;
TIFFClose(private->tiff);
private->tiff = NULL;
- free(src->private);
- src->private = NULL;
-
- pthread_mutex_unlock(&src->busy);
- pthread_mutex_destroy(&src->busy);
- free(src);
-}
-
-static struct imv_image *to_image(int width, int height, void *bitmap)
-{
- struct imv_bitmap *bmp = malloc(sizeof *bmp);
- bmp->width = width;
- bmp->height = height;
- bmp->format = IMV_ABGR;
- bmp->data = bitmap;
- struct imv_image *image = imv_image_create_from_bitmap(bmp);
- return image;
-}
-
-static void report_error(struct imv_source *src)
-{
- assert(src->callback);
-
- struct imv_source_message msg;
- msg.source = src;
- msg.user_data = src->user_data;
- msg.image = NULL;
- msg.error = "Internal error";
-
- pthread_mutex_unlock(&src->busy);
- src->callback(&msg);
+ free(private);
}
-static void send_bitmap(struct imv_source *src, void *bitmap)
+static void load_image(void *raw_private, struct imv_image **image, int *frametime)
{
- assert(src->callback);
+ *image = NULL;
+ *frametime = 0;
- struct imv_source_message msg;
- msg.source = src;
- msg.user_data = src->user_data;
- msg.image = to_image(src->width, src->height, bitmap);
- msg.frametime = 0;
- msg.error = NULL;
-
- pthread_mutex_unlock(&src->busy);
- src->callback(&msg);
-}
-
-static void *load_image(struct imv_source *src)
-{
- /* Don't run if this source is already active */
- if (pthread_mutex_trylock(&src->busy)) {
- return NULL;
- }
-
- struct private *private = src->private;
+ struct private *private = raw_private;
/* libtiff suggests using their own allocation routines to support systems
* with segmented memory. I have no desire to support that, so I'm just
* going to use vanilla malloc/free. Systems where that isn't acceptable
* don't have upstream support from imv.
*/
- void *bitmap = malloc(src->height * src->width * 4);
- int rcode = TIFFReadRGBAImageOriented(private->tiff, src->width, src->height,
+ void *bitmap = malloc(private->height * private->width * 4);
+ int rcode = TIFFReadRGBAImageOriented(private->tiff, private->width, private->height,
bitmap, ORIENTATION_TOPLEFT, 0);
/* 1 = success, unlike the rest of *nix */
if (rcode != 1) {
- free(bitmap);
- report_error(src);
- return NULL;
+ return;
}
- send_bitmap(src, bitmap);
- return NULL;
+ struct imv_bitmap *bmp = malloc(sizeof *bmp);
+ bmp->width = private->width;
+ bmp->height = private->height;
+ bmp->format = IMV_ABGR;
+ bmp->data = bitmap;
+ *image = imv_image_create_from_bitmap(bmp);
}
+static const struct imv_source_vtable vtable = {
+ .load_first_frame = load_image,
+ .free = free_private
+};
+
static enum backend_result open_path(const char *path, struct imv_source **src)
{
struct private private;
@@ -157,26 +116,13 @@ static enum backend_result open_path(const char *path, struct imv_source **src)
return BACKEND_UNSUPPORTED;
}
- unsigned int width, height;
- TIFFGetField(private.tiff, TIFFTAG_IMAGEWIDTH, &width);
- TIFFGetField(private.tiff, TIFFTAG_IMAGELENGTH, &height);
-
- struct imv_source *source = calloc(1, sizeof *source);
- source->name = strdup(path);
- source->width = width;
- source->height = height;
- source->num_frames = 1;
- source->next_frame = 1;
- pthread_mutex_init(&source->busy, NULL);
- source->load_first_frame = &load_image;
- source->load_next_frame = NULL;
- source->free = &source_free;
- source->callback = NULL;
- source->user_data = NULL;
- source->private = malloc(sizeof private);
- memcpy(source->private, &private, sizeof private);
-
- *src = source;
+ TIFFGetField(private.tiff, TIFFTAG_IMAGEWIDTH, &private.width);
+ TIFFGetField(private.tiff, TIFFTAG_IMAGELENGTH, &private.height);
+
+ struct private *new_private = malloc(sizeof private);
+ memcpy(new_private, &private, sizeof private);
+
+ *src = imv_source_create(&vtable, new_private);
return BACKEND_SUCCESS;
}
@@ -195,25 +141,10 @@ static enum backend_result open_memory(void *data, size_t len, struct imv_source
return BACKEND_UNSUPPORTED;
}
- unsigned int width, height;
- TIFFGetField(private->tiff, TIFFTAG_IMAGEWIDTH, &width);
- TIFFGetField(private->tiff, TIFFTAG_IMAGELENGTH, &height);
-
- struct imv_source *source = calloc(1, sizeof *source);
- source->name = strdup("-");
- source->width = width;
- source->height = height;
- source->num_frames = 1;
- source->next_frame = 1;
- pthread_mutex_init(&source->busy, NULL);
- source->load_first_frame = &load_image;
- source->load_next_frame = NULL;
- source->free = &source_free;
- source->callback = NULL;
- source->user_data = NULL;
- source->private = private;
-
- *src = source;
+ TIFFGetField(private->tiff, TIFFTAG_IMAGEWIDTH, &private->width);
+ TIFFGetField(private->tiff, TIFFTAG_IMAGELENGTH, &private->height);
+
+ *src = imv_source_create(&vtable, private);
return BACKEND_SUCCESS;
}
diff --git a/src/image.c b/src/image.c
index f4df7c9..e4cda9d 100644
--- a/src/image.c
+++ b/src/image.c
@@ -2,6 +2,8 @@
#include "bitmap.h"
+#include <stdlib.h>
+
struct imv_image {
int width;
int height;
diff --git a/src/imv.c b/src/imv.c
index 4aa167a..a612bb2 100644
--- a/src/imv.c
+++ b/src/imv.c
@@ -4,9 +4,11 @@
#include <ctype.h>
#include <errno.h>
#include <getopt.h>
+#include <pthread.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
+#include <time.h>
#include <unistd.h>
#include <wordexp.h>
@@ -59,9 +61,6 @@ struct internal_event {
bool is_new_image;
} new_image;
struct {
- char *error;
- } bad_image;
- struct {
char *path;
} new_path;
struct {
@@ -318,37 +317,6 @@ static double cur_time(void)
return ts.tv_sec + (double)ts.tv_nsec * 0.000000001;
}
-static void *async_free_source_thread(void *raw)
-{
- struct imv_source *src = raw;
- src->free(src);
- return NULL;
-}
-
-static void async_free_source(struct imv_source *src)
-{
- typedef void *(*thread_func)(void*);
- pthread_t thread;
- pthread_create(&thread, NULL, (thread_func)async_free_source_thread, src);
- pthread_detach(thread);
-}
-
-static void async_load_first_frame(struct imv_source *src)
-{
- typedef void *(*thread_func)(void*);
- pthread_t thread;
- pthread_create(&thread, NULL, (thread_func)src->load_first_frame, src);
- pthread_detach(thread);
-}
-
-static void async_load_next_frame(struct imv_source *src)
-{
- typedef void *(*thread_func)(void*);
- pthread_t thread;
- pthread_create(&thread, NULL, (thread_func)src->load_next_frame, src);
- pthread_detach(thread);
-}
-
static void source_callback(struct imv_source_message *msg)
{
struct imv *imv = msg->user_data;
@@ -376,8 +344,6 @@ static void source_callback(struct imv_source_message *msg)
imv->last_source = msg->source;
} else {
event->type = BAD_IMAGE;
- /* TODO: Something more elegant with error messages */
- event->data.bad_image.error = strdup(msg->error);
}
struct imv_event e = {
@@ -601,7 +567,7 @@ void imv_free(struct imv *imv)
imv_binds_free(imv->binds);
imv_navigator_free(imv->navigator);
if (imv->current_source) {
- imv->current_source->free(imv->current_source);
+ imv_source_free(imv->current_source);
}
imv_commands_free(imv->commands);
imv_console_free(imv->console);
@@ -960,12 +926,11 @@ int imv_run(struct imv *imv)
if (result == BACKEND_SUCCESS) {
if (imv->current_source) {
- async_free_source(imv->current_source);
+ imv_source_async_free(imv->current_source);
}
imv->current_source = new_source;
- imv->current_source->callback = &source_callback;
- imv->current_source->user_data = imv;
- async_load_first_frame(imv->current_source);
+ imv_source_set_callback(imv->current_source, &source_callback, imv);
+ imv_source_async_load_first_frame(imv->current_source);
imv->loading = true;
imv_viewport_set_playing(imv->view, true);
@@ -1016,8 +981,8 @@ int imv_run(struct imv *imv)
imv->need_redraw = true;
/* Trigger loading of a new frame, now this one's being displayed */
- if (imv->current_source && imv->current_source->load_next_frame) {
- async_load_next_frame(imv->current_source);
+ if (imv->current_source) {
+ imv_source_async_load_next_frame(imv->current_source);
}
}
@@ -1128,8 +1093,8 @@ static void handle_new_image(struct imv *imv, struct imv_image *image, int frame
imv->next_frame.duration = 0.0;
/* If this is an animated image, we should kick off loading the next frame */
- if (imv->current_source && imv->current_source->load_next_frame && frametime) {
- async_load_next_frame(imv->current_source);
+ if (imv->current_source && frametime) {
+ imv_source_async_load_next_frame(imv->current_source);
}
}
@@ -1614,8 +1579,8 @@ static void command_next_frame(struct list *args, const char *argstr, void *data
(void)args;
(void)argstr;
struct imv *imv = data;
- if (imv->current_source && imv->current_source->load_next_frame) {
- async_load_next_frame(imv->current_source);
+ if (imv->current_source) {
+ imv_source_async_load_next_frame(imv->current_source);
imv->next_frame.force_next_frame = true;
}
}
diff --git a/src/source.c b/src/source.c
new file mode 100644
index 0000000..6203dfe
--- /dev/null
+++ b/src/source.c
@@ -0,0 +1,132 @@
+#include "source.h"
+#include "source_private.h"
+
+#include <pthread.h>
+#include <stdlib.h>
+
+struct imv_source {
+ /* pointers to implementation's functions */
+ const struct imv_source_vtable *vtable;
+
+ /* pointer to implementation data */
+ void *private;
+
+ /* Attempted to be locked by load_first_frame or load_next_frame.
+ * If the mutex can't be locked, the call is aborted.
+ * Used to prevent the source from having multiple worker threads at once.
+ * Released by the source before calling the message callback with a result.
+ */
+ pthread_mutex_t busy;
+
+ /* callback function */
+ imv_source_callback callback;
+ /* callback data */
+ void *callback_data;
+};
+
+struct imv_source *imv_source_create(const struct imv_source_vtable *vtable, void *private)
+{
+ struct imv_source *source = calloc(1, sizeof *source);
+ source->vtable = vtable;
+ source->private = private;
+ pthread_mutex_init(&source->busy, NULL);
+ return source;
+}
+
+static void *free_thread(void *src)
+{
+ imv_source_free(src);
+ return NULL;
+}
+
+void imv_source_async_free(struct imv_source *src)
+{
+ pthread_t thread;
+ pthread_create(&thread, NULL, free_thread, src);
+ pthread_detach(thread);
+}
+
+static void *first_frame_thread(void *src)
+{
+ imv_source_load_first_frame(src);
+ return NULL;
+}
+
+void imv_source_async_load_first_frame(struct imv_source *src)
+{
+ pthread_t thread;
+ pthread_create(&thread, NULL, first_frame_thread, src);
+ pthread_detach(thread);
+}
+
+static void *next_frame_thread(void *src)
+{
+ imv_source_load_next_frame(src);
+ return NULL;
+}
+void imv_source_async_load_next_frame(struct imv_source *src)
+{
+ pthread_t thread;
+ pthread_create(&thread, NULL, next_frame_thread, src);
+ pthread_detach(thread);
+}
+
+void imv_source_free(struct imv_source *src)
+{
+ pthread_mutex_lock(&src->busy);
+ src->vtable->free(src->private);
+ pthread_mutex_unlock(&src->busy);
+ pthread_mutex_destroy(&src->busy);
+ free(src);
+}
+
+void imv_source_load_first_frame(struct imv_source *src)
+{
+ if (!src->vtable->load_first_frame) {
+ return;
+ }
+
+ if (pthread_mutex_trylock(&src->busy)) {
+ return;
+ }
+
+ struct imv_source_message msg = {
+ .source = src,
+ .user_data = src->callback_data
+ };
+
+ src->vtable->load_first_frame(src->private, &msg.image, &msg.frametime);
+
+ pthread_mutex_unlock(&src->busy);
+
+ src->callback(&msg);
+}
+
+void imv_source_load_next_frame(struct imv_source *src)
+{
+ if (!src->vtable->load_next_frame) {
+ return;
+ }
+
+ if (pthread_mutex_trylock(&src->busy)) {
+ return;
+ }
+
+ struct imv_source_message msg = {
+ .source = src,
+ .user_data = src->callback_data
+ };
+
+ src->vtable->load_next_frame(src->private, &msg.image, &msg.frametime);
+
+ pthread_mutex_unlock(&src->busy);
+
+ src->callback(&msg);
+}
+
+void imv_source_set_callback(struct imv_source *src, imv_source_callback callback,
+ void *data)
+{
+ src->callback = callback;
+ src->callback_data = data;
+}
diff --git a/src/source.h b/src/source.h
index d55e560..f843d85 100644
--- a/src/source.h
+++ b/src/source.h
@@ -1,72 +1,47 @@
#ifndef IMV_SOURCE_H
#define IMV_SOURCE_H
-#include <pthread.h>
-#include <stdbool.h>
-#include "image.h"
-
-struct imv_source_message {
- /* Pointer to sender of message */
- struct imv_source *source;
-
- /* User-supplied pointer */
- void *user_data;
-
- /* Receiver is responsible for destroying image */
- struct imv_image *image;
-
- /* If an animated gif, the frame's duration in milliseconds, else 0 */
- int frametime;
-
- /* Error message if image was NULL */
- const char *error;
-};
-
/* While imv_image represents a single frame of an image, be it a bitmap or
* vector image, imv_source represents an open handle to an image file, which
* can emit one or more imv_images.
*/
-struct imv_source {
- /* usually the path of the image this is the source of */
- char *name;
+struct imv_source;
- /* source's image dimensions */
- int width;
- int height;
+struct imv_source_message;
+struct imv_image;
- /* Usually 1, more if animated */
- int num_frames;
+/* Clean up a source. Blocks if the source is active in the background. Async
+ * version does not block, performing cleanup in another thread */
+void imv_source_async_free(struct imv_source *src);
+void imv_source_free(struct imv_source *src);
- /* Next frame to be loaded, 0-indexed */
- int next_frame;
+/* Load the first frame. Silently aborts if source is already loading. Async
+ * version performs loading in background. */
+void imv_source_async_load_first_frame(struct imv_source *src);
+void imv_source_load_first_frame(struct imv_source *src);
- /* Attempted to be locked by load_first_frame or load_next_frame.
- * If the mutex can't be locked, the call is aborted.
- * Used to prevent the source from having multiple worker threads at once.
- * Released by the source before calling the message callback with a result.
- */
- pthread_mutex_t busy;
+/* Load the next frame. Silently aborts if source is already loading. Async
+ * version performs loading in background. */
+void imv_source_async_load_next_frame(struct imv_source *src);
+void imv_source_load_next_frame(struct imv_source *src);
- /* Trigger loading of the first frame. Returns 0 on success. */
- void *(*load_first_frame)(struct imv_source *src);
+typedef void (*imv_source_callback)(struct imv_source_message *message);
- /* Trigger loading of next frame. Returns 0 on success. */
- void *(*load_next_frame)(struct imv_source *src);
+/* Sets the callback function to be called when frame loading completes */
+void imv_source_set_callback(struct imv_source *src, imv_source_callback callback, void *data);
- /* Safely free contents of this source. After this returns
- * it is safe to dealocate/overwrite the imv_source instance.
- */
- void (*free)(struct imv_source *src);
-
- /* User-specified callback for returning messages */
- void (*callback)(struct imv_source_message *message);
+struct imv_source_message {
+ /* Pointer to sender of message */
+ struct imv_source *source;
- /* User-specified pointer, included in returned messages */
+ /* User-supplied pointer */
void *user_data;
- /* Implementation private data */
- void *private;
-};
+ /* Receiver is responsible for destroying image */
+ struct imv_image *image;
+ /* If an animated gif, the frame's duration in milliseconds, else 0 */
+ int frametime;
+};
#endif
diff --git a/src/source_private.h b/src/source_private.h
new file mode 100644
index 0000000..39b41fe
--- /dev/null
+++ b/src/source_private.h
@@ -0,0 +1,24 @@
+#ifndef IMV_SOURCE_PRIVATE_H
+#define IMV_SOURCE_PRIVATE_H
+
+struct imv_image;
+struct imv_source;
+
+struct imv_source_vtable {
+ /* Loads the first frame, if successful puts output in image and duration
+ * (in milliseconds) in frametime. If unsuccessful, image shall be NULL. A
+ * still image should use a frametime of 0.
+ */
+ void (*load_first_frame)(void *private, struct imv_image **image, int *frametime);
+ /* Loads the next frame, if successful puts output in image and duration
+ * (in milliseconds) in frametime. If unsuccessful, image shall be NULL.
+ */
+ void (*load_next_frame)(void *private, struct imv_image **image, int *frametime);
+ /* Cleans up the private section of a source */
+ void (*free)(void *private);
+};
+
+/* Build a source given its vtable and a pointer to the private data */
+struct imv_source *imv_source_create(const struct imv_source_vtable *vt, void *private);
+
+#endif
diff --git a/src/viewport.c b/src/viewport.c
index 5b8b3c7..c894f26 100644
--- a/src/viewport.c
+++ b/src/viewport.c
@@ -1,5 +1,7 @@
#include "viewport.h"
+#include <stdlib.h>
+
struct imv_viewport {
double scale;
struct {