emile: add infrastructure for callback to request what to do with image.

First use of this infrastructure is to make JPEG decoding interruptible.
This commit is contained in:
Cedric BAIL 2016-12-06 16:22:56 -08:00
parent 889944fefe
commit c8fef4a556
2 changed files with 79 additions and 1 deletions

View File

@ -125,6 +125,9 @@ struct _Emile_Image
Eina_Bool (*data)(Emile_Image *image, Emile_Image_Property *prop, unsigned int property_size, void *pixels, Emile_Image_Load_Error *error);
void (*close)(Emile_Image *image);
Emile_Action_Cb cancelled;
const void *cancelled_data;
Emile_Colorspace cspace;
Eina_Bool bin_source : 1;
@ -136,6 +139,27 @@ struct _Emile_Image
Eina_Bool load_opts : 1;
};
static inline Eina_Bool
_emile_image_cancelled_is(Emile_Image *image)
{
if (!image->cancelled) return EINA_FALSE;
return image->cancelled((void*) image->cancelled_data, image, EMILE_ACTION_CANCELLED);
}
#define EMILE_IMAGE_TASK_CHECK(Image, Count, Mask, Error, Error_Handler) \
do { \
Count++; \
if ((Count & Mask) == Mask) \
{ \
Count = 0; \
if (_emile_image_cancelled_is(Image)) \
{ \
*Error = EMILE_IMAGE_LOAD_ERROR_CANCELLED; \
goto Error_Handler; \
} \
} \
} while (0);
static const unsigned char *
_emile_image_file_source_map(Emile_Image *image, unsigned int *length)
{
@ -1629,6 +1653,7 @@ _emile_jpeg_data(Emile_Image *image,
Eina_Bool ptrag_free = EINA_FALSE;
Eina_Bool r = EINA_FALSE;
unsigned int length;
unsigned short count = 0;
if (sizeof(Emile_Image_Property) != property_size)
return EINA_FALSE;
@ -1852,6 +1877,9 @@ _emile_jpeg_data(Emile_Image *image,
line[i] = data + (i * w * 4);
for (l = 0; l < h; l += cinfo.rec_outbuf_height)
{
// Check for continuing every 16 scanlines fetch
EMILE_IMAGE_TASK_CHECK(image, count, 0xF, error, on_error);
jpeg_read_scanlines(&cinfo, line, cinfo.rec_outbuf_height);
scans = cinfo.rec_outbuf_height;
if ((h - l) < scans)
@ -1998,6 +2026,9 @@ _emile_jpeg_data(Emile_Image *image,
line[i] = data + (i * w * 3);
for (l = 0; l < h; l += cinfo.rec_outbuf_height)
{
// Check for continuing every 16 scanlines fetch
EMILE_IMAGE_TASK_CHECK(image, count, 0xF, error, on_error);
jpeg_read_scanlines(&cinfo, line, cinfo.rec_outbuf_height);
scans = cinfo.rec_outbuf_height;
if ((h - l) < scans)
@ -2060,6 +2091,9 @@ _emile_jpeg_data(Emile_Image *image,
line[i] = data + (i * w);
for (l = 0; l < h; l += cinfo.rec_outbuf_height)
{
// Check for continuing every 16 scanlines fetch
EMILE_IMAGE_TASK_CHECK(image, count, 0xF, error, on_error);
jpeg_read_scanlines(&cinfo, line, cinfo.rec_outbuf_height);
scans = cinfo.rec_outbuf_height;
if ((h - l) < scans)
@ -2410,6 +2444,17 @@ emile_image_jpeg_file_open(Eina_File *source,
return _emile_image_bind(ei, opts, animated, error);
}
EAPI void
emile_image_register(Emile_Image *image, Emile_Action_Cb callback, Emile_Action action, const void *data)
{
if (!image) return ;
// We only handle one type of callback for now
if (action != EMILE_ACTION_CANCELLED) return ;
image->cancelled_data = data;
image->cancelled = callback;
}
EAPI void
emile_image_close(Emile_Image *image)
{
@ -2476,6 +2521,9 @@ emile_load_error_str(Emile_Image *source EINA_UNUSED,
case EMILE_IMAGE_LOAD_ERROR_UNKNOWN_FORMAT:
return "Unexpected file format.";
case EMILE_IMAGE_LOAD_ERROR_CANCELLED:
return "Loading was stopped by an external request.";
}
return NULL;
}

View File

@ -102,7 +102,8 @@ typedef enum _Emile_Image_Load_Error
EMILE_IMAGE_LOAD_ERROR_PERMISSION_DENIED = 3, /**< Permission denied to an existing file (or path) */
EMILE_IMAGE_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED = 4, /**< Allocation of resources failure prevented load */
EMILE_IMAGE_LOAD_ERROR_CORRUPT_FILE = 5, /**< File corrupt (but was detected as a known format) */
EMILE_IMAGE_LOAD_ERROR_UNKNOWN_FORMAT = 6 /**< File is not a known format */
EMILE_IMAGE_LOAD_ERROR_UNKNOWN_FORMAT = 6, /**< File is not a known format */
EMILE_IMAGE_LOAD_ERROR_CANCELLED = 7 /**< File loading has been cancelled */
} Emile_Image_Load_Error; /**< Emile image load error codes one can get - see emile_load_error_str() too. */
/**
@ -141,6 +142,25 @@ typedef struct _Emile_Image_Animated Emile_Image_Animated;
*/
typedef struct _Emile_Image_Property Emile_Image_Property;
/**
* @enum _Emile_Action
* @typedef Emile_Action
* What action emile is refering to.
* @since 1.19
*/
typedef enum _Emile_Action
{
EMILE_ACTION_NONE = 0,
EMILE_ACTION_CANCELLED = 1
} Emile_Action;
/**
* @typedef Emile_Action_Cb
* A callback triggered by emile to learn what to do about a specific action.
* @since 1.19
*/
typedef Eina_Bool (*Emile_Action_Cb)(void *data, Emile_Image *image, Emile_Action action);
struct _Emile_Image_Property
{
struct
@ -285,6 +305,16 @@ EAPI Eina_Bool emile_image_head(Emile_Image * image, Emile_Image_Property * prop
*/
EAPI Eina_Bool emile_image_data(Emile_Image * image, Emile_Image_Property * prop, unsigned int property_size, void *pixels, Emile_Image_Load_Error * error);
/**
* Register a callback for emile to ask what to do during the processing of an image
*
* @param image The Emile_Image handler to register on.
* @param callback The callback to use
* @param action The action this callback is triggered on.
* @since 1.19
*/
EAPI void emile_image_register(Emile_Image *image, Emile_Action_Cb callback, Emile_Action action, const void *data);
/**
* Close an opened image handler.
*