commit 363db8ac933bf0edddf320e7a999abaed7fe6756
parent fdafe328e5c6b9b4c4cc7d300cde2f922753e84b
Author: nibo <nibo@relim.de>
Date: Wed, 23 Oct 2024 14:35:03 +0200
Add 'cho_image_tag_parse'
Diffstat:
| M | chordpro.c | | | 434 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------- |
| M | chordpro.h | | | 21 | +++++++++++---------- |
| M | out_pdf.c | | | 2 | +- |
| M | util.c | | | 95 | +++++++++++++++++++++++++++++++++++++++++++------------------------------------ |
| M | util.h | | | 30 | +++++++++++++----------------- |
5 files changed, 425 insertions(+), 157 deletions(-)
diff --git a/chordpro.c b/chordpro.c
@@ -595,6 +595,9 @@ cho_font_copy(struct Font *font)
void
cho_font_free(struct Font *font)
{
+ if (!font) {
+ return;
+ }
free(font->name);
free(font);
}
@@ -602,6 +605,9 @@ cho_font_free(struct Font *font)
void
cho_fonts_free(struct Font **fonts)
{
+ if (!fonts) {
+ return;
+ }
struct Font **start = fonts;
while (*fonts) {
cho_font_free(*fonts);
@@ -925,6 +931,9 @@ cho_style_new_default(void)
void
cho_style_free(struct Style *style)
{
+ if (!style) {
+ return;
+ }
cho_font_free(style->font);
free(style->foreground_color);
free(style->background_color);
@@ -1419,6 +1428,9 @@ cho_tag_attr_new(void)
static void
cho_tag_attr_free(struct Attr *attr)
{
+ if (!attr) {
+ return;
+ }
free(attr->name);
free(attr->value);
free(attr);
@@ -1427,6 +1439,9 @@ cho_tag_attr_free(struct Attr *attr)
static void
cho_tag_attrs_free(struct Attr **attrs)
{
+ if (!attrs) {
+ return;
+ }
struct Attr **start = attrs;
while (*attrs) {
cho_tag_attr_free(*attrs);
@@ -1449,8 +1464,13 @@ cho_tag_new(void)
static void
cho_tag_free(struct Tag *tag)
{
+ if (!tag) {
+ return;
+ }
free(tag->name);
- cho_style_free(tag->style);
+ if (tag->style) {
+ cho_style_free(tag->style);
+ }
if (tag->attrs)
cho_tag_attrs_free(tag->attrs);
free(tag);
@@ -1502,6 +1522,9 @@ cho_metadata_new(void)
static void
cho_metadata_free(struct ChoMetadata *meta)
{
+ if (!meta) {
+ return;
+ }
free(meta->name);
free(meta->value);
if (meta->style) {
@@ -1696,6 +1719,9 @@ cho_chord_complete(struct ChoChord *first, struct ChoChord *second)
static void
cho_chord_free(struct ChoChord *chord)
{
+ if (!chord) {
+ return;
+ }
cho_style_free(chord->style);
free(chord->name);
free(chord->root);
@@ -1947,16 +1973,20 @@ cho_image_new(void)
image->x = NULL;
image->y = NULL;
image->anchor = AN_FLOAT;
- image->dx = EMPTY;
- image->dy = EMPTY;
- image->w = EMPTY;
- image->h = EMPTY;
+ image->dx = NULL;
+ image->dy = NULL;
+ image->w = NULL;
+ image->h = NULL;
+ image->bbox = false;
return image;
}
static void
cho_image_free(struct ChoImage *image)
{
+ if (!image) {
+ return;
+ }
free(image->id);
free(image->src);
if (image->width) {
@@ -1971,13 +2001,25 @@ cho_image_free(struct ChoImage *image)
if (image->spread_space) {
free(image->spread_space);
}
+ free(image->href);
if (image->x) {
free(image->x);
}
if (image->y) {
free(image->y);
}
- free(image->href);
+ if (image->dx) {
+ free(image->dx);
+ }
+ if (image->dy) {
+ free(image->dy);
+ }
+ if (image->w) {
+ free(image->w);
+ }
+ if (image->h) {
+ free(image->h);
+ }
free(image);
}
@@ -1988,20 +2030,21 @@ cho_image_copy(struct ChoImage *image)
copy->is_asset = image->is_asset;
copy->id = strdup(image->id);
copy->src = strdup(image->src);
- copy->width = double_or_percent_copy(image->width);
- copy->height = double_or_percent_copy(image->height);
- copy->scale = double_or_percent_copy(image->scale);
+ copy->width = size_copy(image->width);
+ copy->height = size_copy(image->height);
+ copy->scale = size_copy(image->scale);
copy->align = image->align;
copy->border = image->border;
- copy->spread_space = double_or_percent_copy(image->spread_space);
+ copy->spread_space = size_copy(image->spread_space);
copy->href = strdup(image->href);
- copy->x = double_or_percent_copy(image->x);
- copy->y = double_or_percent_copy(image->y);
+ copy->x = size_copy(image->x);
+ copy->y = size_copy(image->y);
copy->anchor = image->anchor;
- copy->dx = image->dx;
- copy->dy = image->dy;
- copy->w = image->w;
- copy->h = image->h;
+ copy->dx = size_copy(image->dx);
+ copy->dy = size_copy(image->dy);
+ copy->w = size_copy(image->w);
+ copy->h = size_copy(image->h);
+ copy->bbox = image->bbox;
return copy;
}
@@ -2034,24 +2077,24 @@ cho_debug_image_print(struct ChoImage *image)
printf("src: NULL\n");
}
if (image->width) {
- printf("width: %s\n", double_or_percent_to_string(image->width));
+ printf("width: %s\n", size_to_string(image->width));
} else {
printf("width: NULL\n");
}
if (image->height) {
- printf("height: %s\n", double_or_percent_to_string(image->height));
+ printf("height: %s\n", size_to_string(image->height));
} else {
printf("height: NULL\n");
}
if (image->scale) {
- printf("scale: %s\n", double_or_percent_to_string(image->scale));
+ printf("scale: %s\n", size_to_string(image->scale));
} else {
printf("scale: NULL\n");
}
printf("align: %s\n", alignment_enums[image->align]);
printf("border: %.1f\n", image->border);
if (image->spread_space) {
- printf("spread_space: %s\n", double_or_percent_to_string(image->spread_space));
+ printf("spread_space: %s\n", size_to_string(image->spread_space));
} else {
printf("spread_space: NULL\n");
}
@@ -2061,20 +2104,37 @@ cho_debug_image_print(struct ChoImage *image)
printf("href: NULL\n");
}
if (image->x) {
- printf("x: %s\n", double_or_percent_to_string(image->x));
+ printf("x: %s\n", size_to_string(image->x));
} else {
printf("x: NULL\n");
}
if (image->y) {
- printf("y: %s\n", double_or_percent_to_string(image->y));
+ printf("y: %s\n", size_to_string(image->y));
} else {
printf("y: NULL\n");
}
printf("anchor: %s\n", anchor_enums[image->anchor]);
- printf("dx: %.1f\n", image->dx);
- printf("dy: %.1f\n", image->dy);
- printf("w: %.1f\n", image->w);
- printf("h: %.1f\n", image->h);
+ if (image->dx) {
+ printf("dx: %s\n", size_to_string(image->dx));
+ } else {
+ printf("dx: NULL\n");
+ }
+ if (image->dy) {
+ printf("dy: %s\n", size_to_string(image->dy));
+ } else {
+ printf("dy: NULL\n");
+ }
+ if (image->w) {
+ printf("w: %s\n", size_to_string(image->w));
+ } else {
+ printf("w: NULL\n");
+ }
+ if (image->h) {
+ printf("h: %s\n", size_to_string(image->h));
+ } else {
+ printf("h: NULL\n");
+ }
+ printf("bbox: %d\n", image->bbox);
printf("---- END IMAGE ------\n");
}
#endif /* DEBUG */
@@ -2083,6 +2143,7 @@ static bool
cho_image_option_parse(struct ChoImage *image, const char *name, const char *value)
{
char *endptr;
+ struct Size *size;
if (!strcmp(name, "id")) {
image->id = strdup(value);
} else
@@ -2090,25 +2151,40 @@ cho_image_option_parse(struct ChoImage *image, const char *name, const char *val
image->src = strdup(value);
} else
if (!strcmp(name, "width")) {
- image->width = double_or_percent_create(value);
- if (!image->width) {
+ size = size_create(value);
+ if (!size) {
cho_log(LOG_ERR, "Invalid value in option 'width' in image directive.");
return false;
}
+ if (size->type == ST_EM || size->type == ST_EX) {
+ cho_log(LOG_ERR, "Invalid type of value in option 'width' in image directive. Allowed types are: points, percentage.");
+ return false;
+ }
+ image->width = size;
} else
if (!strcmp(name, "height")) {
- image->height = double_or_percent_create(value);
- if (!image->height) {
+ size = size_create(value);
+ if (!size) {
cho_log(LOG_ERR, "Invalid value in option 'height' in image directive.");
return false;
}
+ if (size->type == ST_EM || size->type == ST_EX) {
+ cho_log(LOG_ERR, "Invalid type of value in option 'height' in image directive. Allowed types are: point, percentage.");
+ return false;
+ }
+ image->height = size;
} else
if (!strcmp(name, "scale")) {
- image->scale = double_or_percent_create(value);
- if (!image->scale) {
+ size = size_create(value);
+ if (!size) {
cho_log(LOG_ERR, "Invalid value in option 'scale' in image directive.");
return false;
}
+ if (size->type == ST_EM || size->type == ST_EX) {
+ cho_log(LOG_ERR, "Invalid type of value in option 'scale' in image directive. Allowed types are: point, percentage.");
+ return false;
+ }
+ image->scale = size;
} else
if (!strcmp(name, "align")) {
if (!strcmp(value, "left")) {
@@ -2132,28 +2208,43 @@ cho_image_option_parse(struct ChoImage *image, const char *name, const char *val
}
} else
if (!strcmp(name, "spread")) {
- image->spread_space = double_or_percent_create(value);
- if (!image->spread_space) {
+ size = size_create(value);
+ if (!size) {
cho_log(LOG_ERR, "Invalid value in option 'spread' in image directive.");
return false;
}
+ if (size->type == ST_EM || size->type == ST_EX) {
+ cho_log(LOG_ERR, "Invalid type of value in option 'spread' in image directive. Allowed types are: point, percentage.");
+ return false;
+ }
+ image->spread_space = size;
} else
if (!strcmp(name, "href")) {
image->href = strdup(value);
} else
if (!strcmp(name, "x")) {
- image->x = double_or_percent_create(value);
- if (!image->x) {
+ size = size_create(value);
+ if (!size) {
cho_log(LOG_ERR, "Invalid value in option 'x' in image directive.");
return false;
}
+ if (size->type == ST_EM || size->type == ST_EX) {
+ cho_log(LOG_ERR, "Invalid type of value in option 'x' in image directive. Allowed types are: point, percentage.");
+ return false;
+ }
+ image->x = size;
} else
if (!strcmp(name, "y")) {
- image->y = double_or_percent_create(value);
- if (!image->y) {
+ size = size_create(value);
+ if (!size) {
cho_log(LOG_ERR, "Invalid value in option 'y' in image directive.");
return false;
}
+ if (size->type == ST_EM || size->type == ST_EX) {
+ cho_log(LOG_ERR, "Invalid type of value in option 'y' in image directive. Allowed types are: point, percentage.");
+ return false;
+ }
+ image->y = size;
} else
if (!strcmp(name, "anchor")) {
if (!strcmp(value, "paper")) {
@@ -2291,9 +2382,134 @@ cho_image_directive_parse(const char *str)
return image;
}
-/* static struct ChoImage *cho_image_tag_parse(const char *str)
+static struct ChoImage *
+cho_image_tag_parse(struct Attr **attrs)
{
-} */
+ struct ChoImage *image = cho_image_new();
+ struct Size *size;
+ int a;
+ for (a = 0; attrs[a]; a++) {
+ if (!strcmp(attrs[a]->name, "src")) {
+ image->src = strdup(attrs[a]->value);
+ } else
+ if (!strcmp(attrs[a]->name, "id")) {
+ image->id = strdup(attrs[a]->value);
+ } else
+ if (!strcmp(attrs[a]->name, "width")) {
+ size = size_create(attrs[a]->value);
+ if (!size) {
+ cho_log(LOG_ERR, "Invalid value in attribute 'width' in 'img' tag.");
+ return false;
+ }
+ if (size->type == ST_PERCENT) {
+ cho_log(LOG_ERR, "Invalid type of value in attribute 'width' in 'img' tag. Allowed types are: point, em, ex.");
+ return false;
+ }
+ image->width = size;
+ } else
+ if (!strcmp(attrs[a]->name, "height")) {
+ size = size_create(attrs[a]->value);
+ if (!size) {
+ cho_log(LOG_ERR, "Invalid value in attribute 'height' in 'img' tag.");
+ return false;
+ }
+ if (size->type == ST_PERCENT) {
+ cho_log(LOG_ERR, "Invalid type of value in attribute 'height' in 'img' tag. Allowed types are: point, em, ex.");
+ return false;
+ }
+ image->height = size;
+ } else
+ if (!strcmp(attrs[a]->name, "dx")) {
+ size = size_create(attrs[a]->value);
+ if (!size) {
+ cho_log(LOG_ERR, "Invalid value in attribute 'dx' in 'img' tag.");
+ return false;
+ }
+ if (size->type == ST_PERCENT) {
+ cho_log(LOG_ERR, "Invalid type of value in attribute 'dx' in 'img' tag. Allowed types are: point, em, ex.");
+ return false;
+ }
+ image->dx = size;
+ } else
+ if (!strcmp(attrs[a]->name, "dy")) {
+ size = size_create(attrs[a]->value);
+ if (!size) {
+ cho_log(LOG_ERR, "Invalid value in attribute 'dy' in 'img' tag.");
+ return false;
+ }
+ if (size->type == ST_PERCENT) {
+ cho_log(LOG_ERR, "Invalid type of value in attribute 'dy' in 'img' tag. Allowed types are: point, em, ex.");
+ return false;
+ }
+ image->dy = size;
+ } else
+ if (!strcmp(attrs[a]->name, "scale")) {
+ size = size_create(attrs[a]->value);
+ if (!size) {
+ cho_log(LOG_ERR, "Invalid value in attribute 'scale' in 'img' tag.");
+ return false;
+ }
+ if (size->type == ST_EM || size->type == ST_EX) {
+ cho_log(LOG_ERR, "Invalid type of value in attribute 'scale' in 'img' tag. Allowed types are: point, percent");
+ return false;
+ }
+ image->scale = size;
+ } else
+ if (!strcmp(attrs[a]->name, "align")) {
+ if (!strcmp(attrs[a]->value, "left")) {
+ image->align = A_LEFT;
+ } else
+ if (!strcmp(attrs[a]->value, "right")) {
+ image->align = A_RIGHT;
+ } else
+ if (!strcmp(attrs[a]->value, "center")) {
+ image->align = A_CENTER;
+ } else {
+ cho_log(LOG_ERR, "Invalid value in attribute 'align' in 'img' tag.");
+ return NULL;
+ }
+ } else
+ if (!strcmp(attrs[a]->name, "bbox")) {
+ if (!strcmp(attrs[a]->value, "1")) {
+ image->bbox = true;
+ } else
+ if (!strcmp(attrs[a]->value, "0")) {
+ image->bbox = false;
+ } else {
+ cho_log(LOG_ERR, "Invalid value in attribute 'bbox' in 'img' tag.");
+ return NULL;
+ }
+ } else
+ if (!strcmp(attrs[a]->name, "w")) {
+ size = size_create(attrs[a]->value);
+ if (!size) {
+ cho_log(LOG_ERR, "Invalid value in attribute 'w' in 'img' tag.");
+ return false;
+ }
+ if (size->type != ST_POINT) {
+ cho_log(LOG_ERR, "Invalid type of value in attribute 'w' in 'img' tag. Allowed type is: point");
+ return false;
+ }
+ image->w = size;
+ } else
+ if (!strcmp(attrs[a]->name, "h")) {
+ size = size_create(attrs[a]->value);
+ if (!size) {
+ cho_log(LOG_ERR, "Invalid value in attribute 'h' in 'img' tag.");
+ return false;
+ }
+ if (size->type != ST_POINT) {
+ cho_log(LOG_ERR, "Invalid type of value in attribute 'h' in 'img' tag. Allowed type is: point");
+ return false;
+ }
+ image->h = size;
+ } else {
+ cho_log(LOG_ERR, "Invalid attribute '%s' in 'img' tag.", attrs[a]->name);
+ return NULL;
+ }
+ }
+ return image;
+}
static struct ChoText *
cho_text_new(void)
@@ -2307,6 +2523,9 @@ cho_text_new(void)
static void
cho_text_free(struct ChoText *text)
{
+ if (!text) {
+ return;
+ }
cho_style_free(text->style);
free(text->text);
free(text);
@@ -2333,6 +2552,9 @@ cho_text_above_count(struct ChoLineItemAbove **text_above)
static void
cho_text_above_free(struct ChoLineItemAbove *text_above)
{
+ if (!text_above) {
+ return;
+ }
if (text_above->is_chord) {
cho_chord_free(text_above->u.chord);
} else {
@@ -2367,10 +2589,15 @@ cho_line_item_new(void)
static void
cho_line_item_free(struct ChoLineItem *item)
{
+ if (!item) {
+ return;
+ }
if (item->is_text) {
cho_text_free(item->u.text);
} else {
- cho_image_free(item->u.image);
+ if (item->u.image) {
+ cho_image_free(item->u.image);
+ }
}
free(item);
}
@@ -2402,6 +2629,9 @@ cho_line_new(void)
static void
cho_line_free(struct ChoLine *line)
{
+ if (!line) {
+ return;
+ }
struct ChoLineItem **start_items = line->items;
while (*line->items) {
cho_line_item_free(*line->items);
@@ -2448,6 +2678,9 @@ cho_section_new(void)
static void
cho_section_free(struct ChoSection *section)
{
+ if (!section) {
+ return;
+ }
if (section->label) {
cho_text_free(section->label);
}
@@ -2515,6 +2748,9 @@ cho_song_count(struct ChoSong **songs)
static void
cho_song_free(struct ChoSong *song)
{
+ if (!song) {
+ return;
+ }
struct ChoMetadata **start_meta = song->metadata;
struct ChoSection **start_section = song->sections;
while (*song->metadata) {
@@ -2533,6 +2769,9 @@ cho_song_free(struct ChoSong *song)
void
cho_songs_free(struct ChoSong **songs)
{
+ if (!songs) {
+ return;
+ }
struct ChoSong **start_song = songs;
while (*songs) {
cho_song_free(*songs);
@@ -2570,6 +2809,9 @@ cho_directive_new(void)
static void
cho_directive_free(struct ChoDirective *directive)
{
+ if (!directive) {
+ return;
+ }
cho_style_free(directive->style);
free(directive);
}
@@ -3052,7 +3294,7 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config)
te--;
break;
}
- if (ta > -1 && !tags[ta]->is_closed) {
+ if (ta > -1 && !tags[ta]->is_closed && strcmp(tags[ta]->name, "img")) {
cho_log(LOG_ERR, "Tag has to be closed on same line.");
return NULL;
}
@@ -3769,6 +4011,10 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config)
if (buf == '>') {
tag_start[t] = 0;
t = 0;
+ if (!strcmp(tag_start, "img")) {
+ cho_log(LOG_ERR, "'img' tag has to have at least the 'src' attribute.");
+ return NULL;
+ }
tags[ta]->name = strdup(tag_start);
tag_style = cho_style_parse(tag_start, NULL, cho_tag_style_inherit(tags, ta-1));
if (!tag_style) {
@@ -3885,28 +4131,36 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config)
if (tags[ta]->attrs[at-1]->value) {
cho_tag_attr_free(tags[ta]->attrs[at]);
tags[ta]->attrs[at] = NULL;
- tag_style = cho_style_parse(tag_start, tags[ta]->attrs, cho_tag_style_inherit(tags, ta-1));
- if (!tag_style) {
- LOG_DEBUG("cho_style_parse failed.");
- return NULL;
- }
- tags[ta]->style = tag_style;
- switch (prev_state) {
- case STATE_LYRICS:
- cho_style_free(songs[so]->sections[se]->lines[li]->items[ly]->u.text->style);
- songs[so]->sections[se]->lines[li]->items[ly]->u.text->style = cho_style_copy(tag_style);
- break;
- case STATE_CHORD:
- cho_style_free(songs[so]->sections[se]->lines[li]->text_above[c]->u.chord->style);
- songs[so]->sections[se]->lines[li]->text_above[c]->u.chord->style = cho_style_copy(tag_style);
- break;
- case STATE_ANNOTATION:
- cho_style_free(songs[so]->sections[se]->lines[li]->text_above[c]->u.annot->style);
- songs[so]->sections[se]->lines[li]->text_above[c]->u.annot->style = cho_style_copy(tag_style);
- break;
- default:
- cho_log(LOG_ERR, "Invalid prev_state '%s'.", state_enums[prev_state]);
- return NULL;
+ if (!strcmp(tags[ta]->name, "img")) {
+ cho_text_free(songs[so]->sections[se]->lines[li]->items[ly]->u.text);
+ songs[so]->sections[se]->lines[li]->items[ly]->is_text = false;
+ image = cho_image_tag_parse(tags[ta]->attrs);
+ songs[so]->sections[se]->lines[li]->items[ly]->u.image = image;
+ printf("img tag with attr.\n");
+ } else {
+ tag_style = cho_style_parse(tag_start, tags[ta]->attrs, cho_tag_style_inherit(tags, ta-1));
+ if (!tag_style) {
+ LOG_DEBUG("cho_style_parse failed.");
+ return NULL;
+ }
+ tags[ta]->style = tag_style;
+ switch (prev_state) {
+ case STATE_LYRICS:
+ cho_style_free(songs[so]->sections[se]->lines[li]->items[ly]->u.text->style);
+ songs[so]->sections[se]->lines[li]->items[ly]->u.text->style = cho_style_copy(tag_style);
+ break;
+ case STATE_CHORD:
+ cho_style_free(songs[so]->sections[se]->lines[li]->text_above[c]->u.chord->style);
+ songs[so]->sections[se]->lines[li]->text_above[c]->u.chord->style = cho_style_copy(tag_style);
+ break;
+ case STATE_ANNOTATION:
+ cho_style_free(songs[so]->sections[se]->lines[li]->text_above[c]->u.annot->style);
+ songs[so]->sections[se]->lines[li]->text_above[c]->u.annot->style = cho_style_copy(tag_style);
+ break;
+ default:
+ cho_log(LOG_ERR, "Invalid prev_state '%s'.", state_enums[prev_state]);
+ return NULL;
+ }
}
at = 0;
memset(tag_start, 0, strlen(tag_start));
@@ -3961,28 +4215,36 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config)
at++;
tags[ta]->attrs = realloc(tags[ta]->attrs, (at+1) * sizeof(struct Attr *));
tags[ta]->attrs[at] = NULL;
- tag_style = cho_style_parse(tag_start, tags[ta]->attrs, cho_tag_style_inherit(tags, ta-1));
- if (!tag_style) {
- LOG_DEBUG("cho_style_parse failed.");
- return NULL;
- }
- tags[ta]->style = tag_style;
- switch (prev_state) {
- case STATE_LYRICS:
- cho_style_free(songs[so]->sections[se]->lines[li]->items[ly]->u.text->style);
- songs[so]->sections[se]->lines[li]->items[ly]->u.text->style = cho_style_copy(tag_style);
- break;
- case STATE_CHORD:
- cho_style_free(songs[so]->sections[se]->lines[li]->text_above[c]->u.chord->style);
- songs[so]->sections[se]->lines[li]->text_above[c]->u.chord->style = cho_style_copy(tag_style);
- break;
- case STATE_ANNOTATION:
- cho_style_free(songs[so]->sections[se]->lines[li]->text_above[c]->u.annot->style);
- songs[so]->sections[se]->lines[li]->text_above[c]->u.annot->style = cho_style_copy(tag_style);
- break;
- default:
- cho_log(LOG_ERR, "Invalid prev_state '%s'.", state_enums[prev_state]);
- return NULL;
+ if (!strcmp(tags[ta]->name, "img")) {
+ cho_text_free(songs[so]->sections[se]->lines[li]->items[ly]->u.text);
+ songs[so]->sections[se]->lines[li]->items[ly]->is_text = false;
+ image = cho_image_tag_parse(tags[ta]->attrs);
+ songs[so]->sections[se]->lines[li]->items[ly]->u.image = image;
+ printf("img tag with attr.\n");
+ } else {
+ tag_style = cho_style_parse(tag_start, tags[ta]->attrs, cho_tag_style_inherit(tags, ta-1));
+ if (!tag_style) {
+ LOG_DEBUG("cho_style_parse failed.");
+ return NULL;
+ }
+ tags[ta]->style = tag_style;
+ switch (prev_state) {
+ case STATE_LYRICS:
+ cho_style_free(songs[so]->sections[se]->lines[li]->items[ly]->u.text->style);
+ songs[so]->sections[se]->lines[li]->items[ly]->u.text->style = cho_style_copy(tag_style);
+ break;
+ case STATE_CHORD:
+ cho_style_free(songs[so]->sections[se]->lines[li]->text_above[c]->u.chord->style);
+ songs[so]->sections[se]->lines[li]->text_above[c]->u.chord->style = cho_style_copy(tag_style);
+ break;
+ case STATE_ANNOTATION:
+ cho_style_free(songs[so]->sections[se]->lines[li]->text_above[c]->u.annot->style);
+ songs[so]->sections[se]->lines[li]->text_above[c]->u.annot->style = cho_style_copy(tag_style);
+ break;
+ default:
+ cho_log(LOG_ERR, "Invalid prev_state '%s'.", state_enums[prev_state]);
+ return NULL;
+ }
}
at = 0;
avs = AVS_NO;
diff --git a/chordpro.h b/chordpro.h
@@ -146,20 +146,21 @@ struct ChoImage {
bool is_asset;
char *id;
char *src;
- struct DoubleOrPercent *width;
- struct DoubleOrPercent *height;
- struct DoubleOrPercent *scale;
+ struct Size *width;
+ struct Size *height;
+ struct Size *scale;
enum Alignment align;
double border;
- struct DoubleOrPercent *spread_space;
+ struct Size *spread_space;
char *href;
- struct DoubleOrPercent *x;
- struct DoubleOrPercent *y;
+ struct Size *x;
+ struct Size *y;
enum Anchor anchor;
- double dx;
- double dy;
- double w;
- double h;
+ struct Size *dx;
+ struct Size *dy;
+ struct Size *w;
+ struct Size *h;
+ bool bbox;
};
enum AttrValueSyntax {
diff --git a/out_pdf.c b/out_pdf.c
@@ -1055,7 +1055,7 @@ text_create(struct ChoSong **songs, struct Config *config)
text[t]->lines[tl]->items = NULL;
for (ly = 0; lines[li]->items[ly]; ly++) {
if (!lines[li]->items[ly]->is_text) {
- printf("src: %s\n", lines[li]->items[ly]->u.image->src);
+ // printf("src: %s\n", lines[li]->items[ly]->u.image->src);
continue;
}
// out_pdf_text_find_fitting_length(lines[li]->lyrics[ly]);
diff --git a/util.c b/util.c
@@ -276,59 +276,68 @@ filepath_dirname(const char *path)
return dirname;
}
-const char *
-double_or_percent_to_string(struct DoubleOrPercent *dop)
+static const char *
+size_type_to_string(enum SizeType type)
{
- static char str[8+1];
- if (dop->is_percent) {
- sprintf((char *)&str, "%d%%", dop->u.p);
- } else {
- if (dop->u.d > 999999) {
- sprintf((char *)&str, ">999.999");
- } else {
- sprintf((char *)&str, "%.1f", dop->u.d);
- }
+ switch (type) {
+ case ST_PERCENT:
+ return "%";
+ case ST_EM:
+ return "em";
+ case ST_EX:
+ return "ex";
+ default:
+ return "";
}
- return str;
}
-struct DoubleOrPercent *
-double_or_percent_copy(struct DoubleOrPercent *dop)
+struct Size *
+size_create(const char *str)
{
- struct DoubleOrPercent *copy = malloc(sizeof(struct DoubleOrPercent));
- if (dop->is_percent) {
- copy->is_percent = true;
- copy->u.p = dop->u.p;
- } else {
- copy->is_percent = false;
- copy->u.d = dop->u.d;
+ size_t len = strlen(str);
+ struct Size *size = malloc(sizeof(struct Size));
+ char *endptr;
+ double d;
+ d = strtod(str, &endptr);
+ if (str == endptr || errno == ERANGE) {
+ LOG_DEBUG("strtod failed.");
+ return NULL;
+ }
+ size->d = d;
+ size->type = ST_POINT;
+ if (len > 1 && str[len-1] == '%') {
+ if (size->d < 1.0 || size->d > 100.0) {
+ util_log(LOG_ERR, "invalid percentage.");
+ return NULL;
+ }
+ size->type = ST_PERCENT;
+ } else
+ if (len > 2 && str[len-2] == 'e' && str[len-1] == 'm') {
+ size->type = ST_EM;
+ } else
+ if (len > 2 && str[len-2] == 'e' && str[len-1] == 'x') {
+ size->type = ST_EX;
}
+ return size;
+}
+
+struct Size *
+size_copy(struct Size *size)
+{
+ struct Size *copy = malloc(sizeof(struct Size));
+ copy->type = size->type;
+ copy->d = size->d;
return copy;
}
-struct DoubleOrPercent *
-double_or_percent_create(const char *str)
+const char *
+size_to_string(struct Size *size)
{
- struct DoubleOrPercent *dop = malloc(sizeof(struct DoubleOrPercent));
- size_t len = strlen(str);
- if (str[len-1] == '%') {
- short p = str_parse_as_percent(str);
- if (p == -1) {
- LOG_DEBUG("str_parse_as_percent failed.");
- return NULL;
- }
- dop->u.p = p;
- dop->is_percent = true;
+ static char str[10+1];
+ if (size->d > 999999) {
+ sprintf((char *)&str, ">999.999");
} else {
- char *endptr;
- double d;
- d = strtod(str, &endptr);
- if (str == endptr || errno == ERANGE) {
- LOG_DEBUG("strtod failed.");
- return NULL;
- }
- dop->u.d = d;
- dop->is_percent = false;
+ sprintf((char *)&str, "%.1f%s", size->d, size_type_to_string(size->type));
}
- return dop;
+ return str;
}
diff --git a/util.h b/util.h
@@ -17,20 +17,16 @@ enum FileType {
F_OTHER
};
-/*
- INFO: Typically I would directly calculate the percent
- and store it as a double but I can't do that here because
- the percent refers to something in the pdf that will be
- generated. At parsing stage there is no information about
- the pdf.
-*/
-
-struct DoubleOrPercent {
- bool is_percent;
- union {
- double d;
- short p;
- } u;
+enum SizeType {
+ ST_POINT,
+ ST_PERCENT,
+ ST_EM,
+ ST_EX
+};
+
+struct Size {
+ enum SizeType type;
+ double d;
};
void util_log(enum LogLevel level, const char *msg, ...);
@@ -48,6 +44,6 @@ char *filepath_add_ending_slash_if_missing(const char *path);
char *filepath_basename(const char *path);
char *filepath_dirname(const char *path);
-const char *double_or_percent_to_string(struct DoubleOrPercent *dop);
-struct DoubleOrPercent *double_or_percent_copy(struct DoubleOrPercent *dop);
-struct DoubleOrPercent *double_or_percent_create(const char *str);
+struct Size *size_create(const char *str);
+struct Size *size_copy(struct Size *size);
+const char *size_to_string(struct Size *size);