|
|
|
@ -76,6 +76,24 @@ enum
|
|
|
|
|
SHAPE_FLAG_TRANSLATION = 1 << 5,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
typedef enum hvif_line_join
|
|
|
|
|
{
|
|
|
|
|
MITER_JOIN = 0,
|
|
|
|
|
MITER_JOIN_REVERT = 1,
|
|
|
|
|
ROUND_JOIN = 2,
|
|
|
|
|
BEVEL_JOIN = 3,
|
|
|
|
|
MITER_JOIN_ROUND = 4,
|
|
|
|
|
HVIF_LINE_JOIN_TYPE_MAX
|
|
|
|
|
} hvif_line_join;
|
|
|
|
|
|
|
|
|
|
typedef enum hvif_line_cap
|
|
|
|
|
{
|
|
|
|
|
BUTT_CAP,
|
|
|
|
|
SQUARE_CAP,
|
|
|
|
|
ROUND_CAP,
|
|
|
|
|
HVIF_LINE_CAP_TYPE_MAX
|
|
|
|
|
} hvif_line_cap;
|
|
|
|
|
|
|
|
|
|
#define ERROR_RESULT(E) \
|
|
|
|
|
(hvif_result) { .status = E }
|
|
|
|
|
#define SUCCESS_RESULT(I) \
|
|
|
|
@ -96,6 +114,9 @@ struct hvif_matrix
|
|
|
|
|
/* TODO: This is most likely wrong */
|
|
|
|
|
#define MATRIX_ID \
|
|
|
|
|
(hvif_matrix) { 1.0, 0.0, 0.0, 0.0, 1.0, 0.0 }
|
|
|
|
|
/* TODO: This is most likely wrong */
|
|
|
|
|
#define MATRIX_TRANSLATION(P) \
|
|
|
|
|
(hvif_matrix) { P.x, 0.0, 0.0, 0.0, P.y, 0.0 }
|
|
|
|
|
|
|
|
|
|
typedef struct hvif_point hvif_point;
|
|
|
|
|
struct hvif_point
|
|
|
|
@ -156,6 +177,35 @@ typedef uint32_t hvif_color; /* 8bit each: alpha, blue, green, red */
|
|
|
|
|
#define COLOR_SET_RGB(C, R, G, B) \
|
|
|
|
|
(C = (C & (~0xffffff)) | (R & 0xff) | ((G & 0xff) << 8) | ((B & 0xff) << 16))
|
|
|
|
|
|
|
|
|
|
typedef struct hvif_transformer hvif_transformer;
|
|
|
|
|
struct hvif_transformer
|
|
|
|
|
{
|
|
|
|
|
signed transformer_type;
|
|
|
|
|
union
|
|
|
|
|
{
|
|
|
|
|
struct
|
|
|
|
|
{
|
|
|
|
|
hvif_matrix matrix;
|
|
|
|
|
} affine;
|
|
|
|
|
struct
|
|
|
|
|
{
|
|
|
|
|
double width;
|
|
|
|
|
hvif_line_join line_join;
|
|
|
|
|
double miter_limit;
|
|
|
|
|
} contour;
|
|
|
|
|
/* perspective is empty */
|
|
|
|
|
struct
|
|
|
|
|
{
|
|
|
|
|
uint8_t width;
|
|
|
|
|
hvif_line_join line_join;
|
|
|
|
|
hvif_line_cap line_cap;
|
|
|
|
|
double miter_limit;
|
|
|
|
|
} stroke;
|
|
|
|
|
} transformer;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/* Core components of the format */
|
|
|
|
|
|
|
|
|
|
typedef struct hvif_style hvif_style;
|
|
|
|
|
struct hvif_style
|
|
|
|
|
{
|
|
|
|
@ -175,12 +225,28 @@ struct hvif_path
|
|
|
|
|
hvif_point* points;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
typedef struct hvif_shape hvif_shape;
|
|
|
|
|
struct hvif_shape
|
|
|
|
|
{
|
|
|
|
|
uint8_t style_idx;
|
|
|
|
|
uint8_t num_paths;
|
|
|
|
|
uint8_t* path_idxs;
|
|
|
|
|
bool hinting;
|
|
|
|
|
hvif_matrix transformation;
|
|
|
|
|
float min_visibility;
|
|
|
|
|
float max_visibility;
|
|
|
|
|
uint8_t num_transformers;
|
|
|
|
|
hvif_transformer* transformers;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct hvif_image
|
|
|
|
|
{
|
|
|
|
|
uint8_t num_styles;
|
|
|
|
|
hvif_style* styles;
|
|
|
|
|
uint8_t num_paths;
|
|
|
|
|
hvif_path* paths;
|
|
|
|
|
uint8_t num_shapes;
|
|
|
|
|
hvif_shape* shapes;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
uint8_t
|
|
|
|
@ -369,6 +435,9 @@ read_coordinate(FILE* file, float* coord)
|
|
|
|
|
hvif_status
|
|
|
|
|
read_path_points(FILE* file, hvif_path* path)
|
|
|
|
|
{
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
|
printf("%s: read path points.\n", __func__);
|
|
|
|
|
#endif
|
|
|
|
|
/* Every path point is three points: the proper point, in point, out point */
|
|
|
|
|
path->points = calloc(3 * path->num_points, sizeof(hvif_point));
|
|
|
|
|
if (!path->points) return ERROR_NOMEM;
|
|
|
|
@ -379,21 +448,30 @@ read_path_points(FILE* file, hvif_path* path)
|
|
|
|
|
hvif_point point_out;
|
|
|
|
|
hvif_status status;
|
|
|
|
|
|
|
|
|
|
for (unsigned i = 0; i < path->num_points; i += 3) {
|
|
|
|
|
for (unsigned i = 0; i < path->num_points; ++i) {
|
|
|
|
|
switch (path_command_at(path, i)) {
|
|
|
|
|
case PATH_COMMAND_H_LINE:
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
|
printf("%s: read h line.\n", __func__);
|
|
|
|
|
#endif
|
|
|
|
|
point = last;
|
|
|
|
|
status = read_coordinate(file, &point.x);
|
|
|
|
|
if (status != SUCCESS) return status;
|
|
|
|
|
point_in = point_out = point;
|
|
|
|
|
break;
|
|
|
|
|
case PATH_COMMAND_V_LINE:
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
|
printf("%s: read v line.\n", __func__);
|
|
|
|
|
#endif
|
|
|
|
|
point = last;
|
|
|
|
|
status = read_coordinate(file, &point.x);
|
|
|
|
|
if (status != SUCCESS) return status;
|
|
|
|
|
point_in = point_out = point;
|
|
|
|
|
break;
|
|
|
|
|
case PATH_COMMAND_LINE:
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
|
printf("%s: read line.\n", __func__);
|
|
|
|
|
#endif
|
|
|
|
|
status = read_coordinate(file, &point.x);
|
|
|
|
|
if (status != SUCCESS) return status;
|
|
|
|
|
status = read_coordinate(file, &point.y);
|
|
|
|
@ -401,6 +479,9 @@ read_path_points(FILE* file, hvif_path* path)
|
|
|
|
|
point_in = point_out = point;
|
|
|
|
|
break;
|
|
|
|
|
case PATH_COMMAND_CURVE:
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
|
printf("%s: read curve.\n", __func__);
|
|
|
|
|
#endif
|
|
|
|
|
status = read_coordinate(file, &point.x);
|
|
|
|
|
if (status != SUCCESS) return status;
|
|
|
|
|
status = read_coordinate(file, &point.y);
|
|
|
|
@ -418,9 +499,10 @@ read_path_points(FILE* file, hvif_path* path)
|
|
|
|
|
point_in = point_out = point;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
path->points[i] = point;
|
|
|
|
|
path->points[i + 1] = point_in;
|
|
|
|
|
path->points[i + 2] = point_out;
|
|
|
|
|
unsigned base = i * 3;
|
|
|
|
|
path->points[base] = point;
|
|
|
|
|
path->points[base + 1] = point_in;
|
|
|
|
|
path->points[base + 2] = point_out;
|
|
|
|
|
last = point;
|
|
|
|
|
}
|
|
|
|
|
return SUCCESS;
|
|
|
|
@ -436,33 +518,179 @@ create_static_commands(
|
|
|
|
|
hvif_status
|
|
|
|
|
read_path(FILE* file, hvif_path* path)
|
|
|
|
|
{
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
|
printf("%s: read path.\n", __func__);
|
|
|
|
|
#endif
|
|
|
|
|
uint8_t flags;
|
|
|
|
|
if (fread(&flags, 1, 1, file) != 1) { return ERROR_PATH; }
|
|
|
|
|
if (fread(&path->num_points, 1, 1, file) != 1) { return ERROR_PATH; }
|
|
|
|
|
if (fread(&flags, 1, 1, file) != 1) { return ERROR_EOF; }
|
|
|
|
|
if (fread(&path->num_points, 1, 1, file) != 1) { return ERROR_EOF; }
|
|
|
|
|
|
|
|
|
|
path->closed = flags & PATH_FLAG_CLOSED;
|
|
|
|
|
uint8_t num_command_bytes = (path->num_points + 3) / 4;
|
|
|
|
|
path->commands = calloc(num_command_bytes, 1);
|
|
|
|
|
if (!path->commands) return ERROR_NOMEM;
|
|
|
|
|
|
|
|
|
|
if ((flags & PATH_FLAG_USES_COMMANDS) && (flags & PATH_FLAG_NO_CURVES)) {
|
|
|
|
|
if ((flags & PATH_FLAG_USES_COMMANDS) && (flags & PATH_FLAG_NO_CURVES))
|
|
|
|
|
return ERROR_PATH;
|
|
|
|
|
}
|
|
|
|
|
if (flags & PATH_FLAG_USES_COMMANDS) {
|
|
|
|
|
if (fread(&flags, 1, num_command_bytes, file) != num_command_bytes) {
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
|
printf(
|
|
|
|
|
"%s: path uses %u commands (%u bytes).\n", __func__, path->num_points,
|
|
|
|
|
num_command_bytes);
|
|
|
|
|
#endif
|
|
|
|
|
if (
|
|
|
|
|
fread(path->commands, 1, num_command_bytes, file) != num_command_bytes) {
|
|
|
|
|
return ERROR_PATH;
|
|
|
|
|
}
|
|
|
|
|
} else if (flags & PATH_FLAG_NO_CURVES) {
|
|
|
|
|
create_static_commands(
|
|
|
|
|
num_command_bytes, path->commands, 0xFF); /* 0b11111111: all curves */
|
|
|
|
|
} else { /* All lines */
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
|
printf("%s: path no curves.\n", __func__);
|
|
|
|
|
#endif
|
|
|
|
|
create_static_commands(
|
|
|
|
|
num_command_bytes, path->commands, 0xAA); /* 0b10101010: all lines */
|
|
|
|
|
} else { /* All curves */
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
|
printf("%s: path all curves.\n", __func__);
|
|
|
|
|
#endif
|
|
|
|
|
create_static_commands(
|
|
|
|
|
num_command_bytes, path->commands, 0xFF); /* 0b11111111: all curves */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return read_path_points(file, path);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
hvif_status
|
|
|
|
|
read_transformer(FILE* file, hvif_transformer* transformer)
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
uint8_t byte;
|
|
|
|
|
if (fread(&byte, 1, 1, file) != 1) return ERROR_EOF;
|
|
|
|
|
|
|
|
|
|
switch (byte) {
|
|
|
|
|
case TRANSFORMER_TYPE_AFFINE:
|
|
|
|
|
transformer->transformer_type = byte;
|
|
|
|
|
char buffer[18];
|
|
|
|
|
hvif_matrix matrix;
|
|
|
|
|
if (fread(buffer, 1, 18, file) != 18) return ERROR_EOF;
|
|
|
|
|
hvif_decode(matrix, buffer);
|
|
|
|
|
transformer->transformer.affine.matrix = matrix;
|
|
|
|
|
break;
|
|
|
|
|
case TRANSFORMER_TYPE_CONTOUR:
|
|
|
|
|
transformer->transformer_type = byte;
|
|
|
|
|
if (fread(&byte, 1, 1, file) != 1) return ERROR_EOF;
|
|
|
|
|
transformer->transformer.contour.width = byte - 128.0;
|
|
|
|
|
|
|
|
|
|
if (fread(&byte, 1, 1, file) != 1) return ERROR_EOF;
|
|
|
|
|
if (byte >= HVIF_LINE_JOIN_TYPE_MAX) return ERROR_SHAPE;
|
|
|
|
|
transformer->transformer.contour.line_join = byte;
|
|
|
|
|
|
|
|
|
|
if (fread(&byte, 1, 1, file) != 1) return ERROR_EOF;
|
|
|
|
|
transformer->transformer.contour.miter_limit = byte;
|
|
|
|
|
break;
|
|
|
|
|
case TRANSFORMER_TYPE_PERSPECTIVE:
|
|
|
|
|
transformer->transformer_type = byte;
|
|
|
|
|
/* This seems to not do anything right now */
|
|
|
|
|
return ERROR_SHAPE;
|
|
|
|
|
break;
|
|
|
|
|
case TRANSFORMER_TYPE_STROKE:
|
|
|
|
|
transformer->transformer_type = byte;
|
|
|
|
|
if (fread(&byte, 1, 1, file) != 1) return ERROR_EOF;
|
|
|
|
|
transformer->transformer.stroke.width = byte - 128.0;
|
|
|
|
|
|
|
|
|
|
if (fread(&byte, 1, 1, file) != 1) return ERROR_EOF;
|
|
|
|
|
uint8_t line_join = byte & 15;
|
|
|
|
|
if (line_join >= HVIF_LINE_JOIN_TYPE_MAX) return ERROR_SHAPE;
|
|
|
|
|
uint8_t line_cap = byte >> 4;
|
|
|
|
|
;
|
|
|
|
|
if (line_cap >= HVIF_LINE_CAP_TYPE_MAX) return ERROR_SHAPE;
|
|
|
|
|
transformer->transformer.stroke.line_join = line_join;
|
|
|
|
|
transformer->transformer.stroke.line_cap = line_cap;
|
|
|
|
|
|
|
|
|
|
if (fread(&byte, 1, 1, file) != 1) return ERROR_EOF;
|
|
|
|
|
transformer->transformer.stroke.miter_limit = byte;
|
|
|
|
|
break;
|
|
|
|
|
default: return ERROR_SHAPE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
hvif_status
|
|
|
|
|
read_shape(FILE* file, hvif_image const* const image, hvif_shape* shape)
|
|
|
|
|
{
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
|
printf("%s: start.\n", __func__);
|
|
|
|
|
#endif
|
|
|
|
|
uint8_t shape_type;
|
|
|
|
|
if (fread(&shape_type, 1, 1, file) != 1) { return ERROR_EOF; }
|
|
|
|
|
|
|
|
|
|
/* the official decoder skips unkown shapes, we are a bit more strict */
|
|
|
|
|
if (shape_type != SHAPE_TYPE_PATH_SOURCE) return ERROR_SHAPE;
|
|
|
|
|
|
|
|
|
|
if (fread(&shape->style_idx, 1, 1, file) != 1) { return ERROR_EOF; }
|
|
|
|
|
if (shape->style_idx > image->num_styles) { return ERROR_SHAPE; }
|
|
|
|
|
|
|
|
|
|
if (fread(&shape->num_paths, 1, 1, file) != 1) { return ERROR_EOF; }
|
|
|
|
|
shape->path_idxs = calloc(shape->num_paths, 1);
|
|
|
|
|
if (!shape->path_idxs) return ERROR_NOMEM;
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
|
printf(
|
|
|
|
|
"%s: style %u and %u paths.\n", __func__, shape->style_idx,
|
|
|
|
|
shape->num_paths);
|
|
|
|
|
#endif
|
|
|
|
|
for (unsigned i = 0; i < shape->num_paths; ++i) {
|
|
|
|
|
if (fread(&shape->path_idxs[i], 1, 1, file) != 1) { return ERROR_EOF; }
|
|
|
|
|
if (shape->path_idxs[i] > image->num_paths) { return ERROR_SHAPE; }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint8_t shape_flags;
|
|
|
|
|
if (fread(&shape_flags, 1, 1, file) != 1) { return ERROR_EOF; }
|
|
|
|
|
shape->hinting = shape_flags & SHAPE_FLAG_HINTING;
|
|
|
|
|
|
|
|
|
|
hvif_matrix transformation;
|
|
|
|
|
if (shape_flags & SHAPE_FLAG_TRANSFORM) {
|
|
|
|
|
char buffer[18];
|
|
|
|
|
if (fread(buffer, 1, 18, file) != 18) { return ERROR_EOF; }
|
|
|
|
|
hvif_decode(transformation, buffer);
|
|
|
|
|
} else if (shape_flags & SHAPE_FLAG_TRANSLATION) {
|
|
|
|
|
hvif_point point;
|
|
|
|
|
hvif_status status;
|
|
|
|
|
status = read_coordinate(file, &point.x);
|
|
|
|
|
if (status != SUCCESS) return status;
|
|
|
|
|
status = read_coordinate(file, &point.y);
|
|
|
|
|
if (status != SUCCESS) return status;
|
|
|
|
|
transformation = MATRIX_TRANSLATION(point);
|
|
|
|
|
} else {
|
|
|
|
|
transformation = MATRIX_ID;
|
|
|
|
|
}
|
|
|
|
|
shape->transformation = transformation;
|
|
|
|
|
|
|
|
|
|
if (shape_flags & SHAPE_FLAG_LOD_SCALE) {
|
|
|
|
|
uint8_t scale;
|
|
|
|
|
if (fread(&scale, 1, 1, file) != 1) { return ERROR_EOF; }
|
|
|
|
|
shape->min_visibility = scale / 63.75;
|
|
|
|
|
if (fread(&scale, 1, 1, file) != 1) { return ERROR_EOF; }
|
|
|
|
|
shape->max_visibility = scale / 63.75;
|
|
|
|
|
} else {
|
|
|
|
|
shape->min_visibility = -1.0;
|
|
|
|
|
shape->max_visibility = -1.0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
shape->num_transformers = 0;
|
|
|
|
|
shape->transformers = 0;
|
|
|
|
|
if (shape_flags & SHAPE_FLAG_HAS_TRANSFORMERS) {
|
|
|
|
|
if (fread(&shape->num_transformers, 1, 1, file) != 1) { return ERROR_EOF; }
|
|
|
|
|
shape->transformers =
|
|
|
|
|
calloc(shape->num_transformers, sizeof(hvif_transformer));
|
|
|
|
|
if (!shape->num_transformers) return ERROR_NOMEM;
|
|
|
|
|
for (unsigned i = 0; i < shape->num_transformers; ++i) {
|
|
|
|
|
hvif_status s = read_transformer(file, &shape->transformers[i]);
|
|
|
|
|
if (s != SUCCESS) return s;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
hvif_result
|
|
|
|
|
hvif_from_file(FILE* file)
|
|
|
|
|
{
|
|
|
|
@ -472,10 +700,10 @@ hvif_from_file(FILE* file)
|
|
|
|
|
printf("%s: checking magic number.\n", __func__);
|
|
|
|
|
#endif
|
|
|
|
|
char magic_buffer[4];
|
|
|
|
|
if (fread(magic_buffer, 1, 4, file) != 4) { return ERROR_RESULT(ERROR_EOF); }
|
|
|
|
|
if (fread(magic_buffer, 1, 4, file) != 4) return ERROR_RESULT(ERROR_EOF);
|
|
|
|
|
uint32_t read_magic;
|
|
|
|
|
hvif_decode(read_magic, magic_buffer);
|
|
|
|
|
if (read_magic != magic) { return ERROR_RESULT(ERROR_MAGIC); }
|
|
|
|
|
if (read_magic != magic) return ERROR_RESULT(ERROR_MAGIC);
|
|
|
|
|
|
|
|
|
|
hvif_image* image = calloc(1, sizeof(hvif_image));
|
|
|
|
|
if (!image) return ERROR_RESULT(ERROR_NOMEM);
|
|
|
|
@ -505,7 +733,7 @@ hvif_from_file(FILE* file)
|
|
|
|
|
return ERROR_RESULT(ERROR_EOF);
|
|
|
|
|
}
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
|
printf("%s: reading %u paths.\n", __func__, image->num_styles);
|
|
|
|
|
printf("%s: reading %u paths.\n", __func__, image->num_paths);
|
|
|
|
|
#endif
|
|
|
|
|
image->paths = calloc(image->num_paths, sizeof(hvif_path));
|
|
|
|
|
if (!image->paths) {
|
|
|
|
@ -519,10 +747,26 @@ hvif_from_file(FILE* file)
|
|
|
|
|
return ERROR_RESULT(s);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (fread(&image->num_shapes, 1, 1, file) != 1) {
|
|
|
|
|
hvif_free(image);
|
|
|
|
|
return ERROR_RESULT(ERROR_EOF);
|
|
|
|
|
}
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
|
printf("%s: incomplete parsing stopped.\n", __func__);
|
|
|
|
|
debug_print_bytes(file);
|
|
|
|
|
printf("%s: reading %u shapes.\n", __func__, image->num_shapes);
|
|
|
|
|
#endif
|
|
|
|
|
image->shapes = calloc(image->num_shapes, sizeof(hvif_shape));
|
|
|
|
|
if (!image->shapes) {
|
|
|
|
|
hvif_free(image);
|
|
|
|
|
return ERROR_RESULT(ERROR_NOMEM);
|
|
|
|
|
}
|
|
|
|
|
for (unsigned i = 0; i < image->num_shapes; ++i) {
|
|
|
|
|
hvif_status s = read_shape(file, image, &image->shapes[i]);
|
|
|
|
|
if (s != SUCCESS) {
|
|
|
|
|
hvif_free(image);
|
|
|
|
|
return ERROR_RESULT(s);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return SUCCESS_RESULT(image);
|
|
|
|
|
}
|
|
|
|
@ -530,14 +774,27 @@ hvif_from_file(FILE* file)
|
|
|
|
|
void
|
|
|
|
|
hvif_free(hvif_image* image)
|
|
|
|
|
{
|
|
|
|
|
for (unsigned i = 0; i < image->num_styles; ++i) {
|
|
|
|
|
free(image->styles[i].colors);
|
|
|
|
|
free(image->styles[i].offsets);
|
|
|
|
|
}
|
|
|
|
|
for (unsigned i = 0; i < image->num_paths; ++i) {
|
|
|
|
|
free(image->paths[i].commands);
|
|
|
|
|
free(image->paths[i].points);
|
|
|
|
|
if (image->styles) {
|
|
|
|
|
for (unsigned i = 0; i < image->num_styles; ++i) {
|
|
|
|
|
free(image->styles[i].colors);
|
|
|
|
|
free(image->styles[i].offsets);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
free(image->styles);
|
|
|
|
|
if (image->paths) {
|
|
|
|
|
for (unsigned i = 0; i < image->num_paths; ++i) {
|
|
|
|
|
free(image->paths[i].commands);
|
|
|
|
|
free(image->paths[i].points);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
free(image->paths);
|
|
|
|
|
if (image->shapes) {
|
|
|
|
|
for (unsigned i = 0; i < image->num_shapes; ++i) {
|
|
|
|
|
free(NULL);
|
|
|
|
|
free(image->shapes[i].path_idxs);
|
|
|
|
|
free(image->shapes[i].transformers);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
free(image->shapes);
|
|
|
|
|
free(image);
|
|
|
|
|
}
|
|
|
|
|