From 85031ef40d6c22b795146ecc3eb8ad9c7bc5ba89 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Tue, 29 Sep 2026 15:54:19 -0400 Subject: [PATCH] gfxbuf: Adds wrappers to load SVGs from file or buffer. --- include/libbase/gfxbuf_rsvg.h | 15 +++++++- src/gfxbuf_rsvg.c | 72 +++++++++++++++++++++++++++++++---- tests/CMakeLists.txt | 4 ++ tests/libbase_rsvg_test.c | 6 ++- 4 files changed, 88 insertions(+), 9 deletions(-) diff --git a/include/libbase/gfxbuf_rsvg.h b/include/libbase/gfxbuf_rsvg.h index a3f05cd..7b5b4ca 100644 --- a/include/libbase/gfxbuf_rsvg.h +++ b/include/libbase/gfxbuf_rsvg.h @@ -22,7 +22,9 @@ #define __GFXBUF_RSVG_H__ #include -#include + +/** Forward declaration, so we don't need to include librsvg. */ +typedef struct _RsvgHandle RsvgHandle; #ifdef __cplusplus extern "C" { @@ -40,6 +42,17 @@ bool bs_gfxbuf_render_rsvg( bs_gfxbuf_t *gfxbuf_ptr, RsvgHandle *rsvg_handle_ptr); +/** Loads the SVG from an in-memory buffer with given size. */ +bool bs_gfxbuf_render_rsvg_data( + bs_gfxbuf_t *gfxbuf_ptr, + const void *data_ptr, + size_t data_size); + +/** Loads the SVG from a file. */ +bool bs_gfxbuf_render_rsvg_file( + bs_gfxbuf_t *gfxbuf_ptr, + const char *fname_ptr); + /** Unite test set. */ extern const bs_test_set_t bs_gfxbuf_rsvg_test_set; diff --git a/src/gfxbuf_rsvg.c b/src/gfxbuf_rsvg.c index 6a0e4c9..fca4066 100644 --- a/src/gfxbuf_rsvg.c +++ b/src/gfxbuf_rsvg.c @@ -58,13 +58,61 @@ bool bs_gfxbuf_render_rsvg( return rv; } +/* ------------------------------------------------------------------------- */ +bool bs_gfxbuf_render_rsvg_data( + bs_gfxbuf_t *gfxbuf_ptr, + const void *data_ptr, + size_t data_size) +{ + GError *error_ptr = NULL; + RsvgHandle *svg_handle_ptr = rsvg_handle_new_from_data( + data_ptr, data_size, &error_ptr); + if (NULL == svg_handle_ptr) { + bs_log(BS_ERROR, "Failed rsvg_handle_new_from_data(%p, %zu, %p)%s%s", + data_ptr, data_size, &error_ptr, + error_ptr ? ": " : "", + error_ptr ? error_ptr->message : ""); + if (NULL != error_ptr) free(error_ptr); + return false; + } + + bool rv = bs_gfxbuf_render_rsvg(gfxbuf_ptr, svg_handle_ptr); + g_object_unref(svg_handle_ptr); + return rv; +} + +/* ------------------------------------------------------------------------- */ +bool bs_gfxbuf_render_rsvg_file( + bs_gfxbuf_t *gfxbuf_ptr, + const char *fname_ptr) +{ + GError *error_ptr = NULL; + RsvgHandle *svg_handle_ptr = rsvg_handle_new_from_file( + fname_ptr, &error_ptr); + if (NULL == svg_handle_ptr) { + bs_log(BS_ERROR, "Failed rsvg_handle_new_from_data(\"%s\", %p)%s%s", + fname_ptr, + &error_ptr, + error_ptr ? ": " : "", + error_ptr ? error_ptr->message : ""); + if (NULL != error_ptr) free(error_ptr); + return false; + } + + bool rv = bs_gfxbuf_render_rsvg(gfxbuf_ptr, svg_handle_ptr); + g_object_unref(svg_handle_ptr); + return rv; +} + /* == Unit tests =========================================================== */ /** @cond TEST */ static void _bs_gfxbuf_rsvg_test_embedded(bs_test_t *test_ptr); +static void _bs_gfxbuf_rsvg_test_file(bs_test_t *test_ptr); static const bs_test_case_t _bs_gfxbuf_rsvg_test_cases[] = { { true, "embedded", _bs_gfxbuf_rsvg_test_embedded }, + { true, "file", _bs_gfxbuf_rsvg_test_file }, { false, NULL, NULL }, }; @@ -74,23 +122,33 @@ const bs_test_set_t bs_gfxbuf_rsvg_test_set = BS_TEST_SET( /* ------------------------------------------------------------------------- */ void _bs_gfxbuf_rsvg_test_embedded(bs_test_t *test_ptr) { - static const char *svg_ptr = ( + static const char *s = ( "" "" ""); bs_gfxbuf_t *g = bs_gfxbuf_create(1, 1); BS_TEST_VERIFY_NEQ_OR_RETURN(test_ptr, NULL, g); - - GError *e = NULL; - RsvgHandle *h = rsvg_handle_new_from_data((const void*)svg_ptr, strlen(svg_ptr), &e); - BS_TEST_VERIFY_NEQ_OR_RETURN(test_ptr, NULL, h); - BS_TEST_VERIFY_TRUE(test_ptr, bs_gfxbuf_render_rsvg(g, h)); - g_object_unref(h); + BS_TEST_VERIFY_TRUE(test_ptr, bs_gfxbuf_render_rsvg_data(g, s, strlen(s))); BS_TEST_VERIFY_EQ(test_ptr, 0xff4080c0, *bs_gfxbuf_pixel_at(g, 0, 0)); bs_gfxbuf_destroy(g); } +/* ------------------------------------------------------------------------- */ +void _bs_gfxbuf_rsvg_test_file(bs_test_t *test_ptr) +{ + bs_gfxbuf_t *g = bs_gfxbuf_create(1, 1); + BS_TEST_VERIFY_NEQ_OR_RETURN(test_ptr, NULL, g); + BS_TEST_VERIFY_TRUE( + test_ptr, + bs_gfxbuf_render_rsvg_file( + g, + bs_test_data_path(test_ptr, "data/example.svg"))); + + BS_TEST_VERIFY_EQ(test_ptr, 0xffc0b0a0, *bs_gfxbuf_pixel_at(g, 0, 0)); + bs_gfxbuf_destroy(g); +} + /** @endcond */ /* == End of gfxbuf_rsvg.c ================================================= */ diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index ef424b9..4fa7729 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -36,6 +36,10 @@ target_link_libraries( libbase libbase_compiler_flags libbase_rsvg) +target_compile_definitions( + libbase_rsvg_test + PUBLIC + BS_TEST_DATA_DIR="${CMAKE_CURRENT_SOURCE_DIR}") add_executable( libbase_benchmark diff --git a/tests/libbase_rsvg_test.c b/tests/libbase_rsvg_test.c index e104909..2b1f618 100644 --- a/tests/libbase_rsvg_test.c +++ b/tests/libbase_rsvg_test.c @@ -12,12 +12,16 @@ /** Main program, runs all unit tests. */ int main(int argc, const char **argv) { + const bs_test_param_t params = { + .test_data_dir_ptr = BS_TEST_DATA_DIR + }; + const bs_test_set_t *sets[] = { &bs_gfxbuf_rsvg_test_set, NULL }; - return bs_test_sets(sets, argc, argv, NULL); + return bs_test_sets(sets, argc, argv, ¶ms); } /* == End of libbase_rsvg_test.c =========================================== */