Michael Orlitzky [Sun, 20 Oct 2024 15:22:25 +0000 (11:22 -0400)]
src/svgtiny.c: cleanup immediately if sheet append fails
If we fail to append to current sheet to the css_select_ctx in
svgtiny_parse_style_element(), we should destroy that sheet right
away, before returning an error.
Michael Orlitzky [Sat, 19 Oct 2024 23:24:15 +0000 (19:24 -0400)]
src/svgtiny.c: clean up "styles" in svgtiny_parse_svg()
We allocate "styles" at the beginning of svgtiny_parse_svg(), but only
clean it up at the very end, and not along any of the error paths. This
commit adds a bunch of css_select_results_destroy() calls along those
paths to ensure that we don't leak resources.
Michael Orlitzky [Sat, 19 Oct 2024 23:16:20 +0000 (19:16 -0400)]
src/svgtiny.c: cleanup dom nodes and select ctx after svgtiny_parse()
The svgtiny_parse() function has a "cleanup:" label at the end
that... cleans up, and then returns whatever result is set. Looking
back through this function, though, we see that none of "svg",
"document", or "state.select_ctx" are cleaned up separately in the two
places where we jump to the "cleanup:" label. Thus those resources may
be leaked.
To prevent that, we just have to move the "cleanup:" label up a bit,
so that it includes the clean-up for "svg", "document", and
"state.select_ctx". We also add a new guard that prevents us from
clobbering a real error code with an error from the context destructor
in the cleanup routine.
Michael Orlitzky [Sat, 19 Oct 2024 21:53:53 +0000 (17:53 -0400)]
src/svgtiny.c: add missing svgtiny_cleanup_state_local() on error path
There's an error path in svgtiny_parse_svg() that leads to returning
svgtiny_LIBDOM_ERROR early. But unlike all of the other early returns
in that function, this one is missing svgtiny_cleanup_state_local().
We add it.
Michael Orlitzky [Sat, 19 Oct 2024 21:43:44 +0000 (17:43 -0400)]
src/svgtiny_css.c: handle DOM_NO_MEM_ERR when setting user data
In set_libcss_node_data(), the dom_node_set_user_data() function can
in fact return a "no memory" error. We now catch that and convert it
into a CSS_NOMEM.
Michael Orlitzky [Sat, 19 Oct 2024 21:23:39 +0000 (17:23 -0400)]
src/svgtiny_css.c: don't check "key" in the libdom user_data handler
The libdom user data get/set functions in the libcss select handler
API identify the libcss user data (among all potential user data) with
a key -- basically, a string. In theory, we should look for this key
in the callback function before delegating to libcss (to make sure
it's libcss user data we're working with), but at the moment, libcss
is the only place the data could have come from.
We can therefore skip the key comparison entirely. This simplifies the
code a bit because it's currently awkward to access the same interned
key string from all three sites.
Michael Orlitzky [Sat, 19 Oct 2024 20:46:51 +0000 (16:46 -0400)]
src/svgtiny_css.c free dom_string in svgtiny_dom_user_data_handler()
This callback uses dom_string_create() for a comparison, but forgets
to call either dom_string_destroy() or dom_string_unref() after the
string has outlived its usefulness. The string is used one line after
it is created, so we find dom_string_destroy() to be more clear in
this case.
In the node_is_lang() callback, we're interning "lang" and later
destroying it. But "lang" is already interned at that point (in
libcss), so we are destroying a copy that doesn't belong to us. It
should be unref'd instead. Valgrind detected the error. Thanks to
Michael Drake for the pointer.
Michael Orlitzky [Fri, 26 Jan 2024 01:12:22 +0000 (20:12 -0500)]
src/svgtiny_css.c: fix lwc/dom string comparison in node_has_name()
The node_has_name() function was calling lwc_string_isequal() to test
the universal selector (a dom_string) against the given node name (an
lwc_string). Instead, it should be using dom_string_lwc_isequal(),
which is designed to do exactly that. Thanks to Michael Drake for the
suggestion.
Michael Orlitzky [Thu, 16 Nov 2023 15:55:11 +0000 (10:55 -0500)]
test/css: add some visually-verified test cases for our new features
It's helpful to have some test cases for our CSS handling, but
unfortunately, it's not all that easy to write them. How should we
compare the actual output to the expected output?
For now we settle for a visual comparison. You can render the test
diagrams using the example program examples/svgtiny_display_x11, and
also open them in another SVG viewer. Do they look the same? Great.
The test cases should be simple enough that _subtle_ visual mismatches
are not possible.
Automating this is not an impossible problem: for example, we could
render the parsed diagram to a bitmap image using cairo and then
compare it to what we get using librsvg which is also cairo-based. But
that has downsides too (like the portability of librsvg) that we don't
want to address right now.
Michael Orlitzky [Sun, 19 Nov 2023 16:39:13 +0000 (11:39 -0500)]
src/svgtiny.c: use case-sensitive comparisons for SVG element names
SVG is XML and its element names are therefore case-sensitive. We
switch to case-sensitive comparisons to avoid rendering elements
(e.g. <RECT />) that other SVG clients (e.g. Firefox) will not.
First, tell people to run "make" instead of giving them the full "gcc"
command-line. Then elaborate on how one can modify the build process
to use a development copy of libsvgtiny.
Michael Orlitzky [Sun, 19 Nov 2023 13:32:01 +0000 (08:32 -0500)]
examples/GNUmakefile: add a GNUmakefile for the example program
This should simplify building it a bit, both against the system copy
and against a development repo. We use the name GNUmakefile (as
opposed to Makefile) to avoid interacting with the netsurf build
system.
Michael Orlitzky [Sat, 18 Nov 2023 19:58:20 +0000 (14:58 -0500)]
src/svgtiny.c: remove parent == NULL hack
Now that we're providing some (unused!) default user-agent properties,
this code path is apparently no longer reached. Never look a gift
horse in the mouth, is an insane saying. But everything works great
without the NULL check, so let's remove it.
Michael Orlitzky [Sat, 18 Nov 2023 19:55:13 +0000 (14:55 -0500)]
src/svgtiny_css.c: add some default user-agent properties after all
We tried to avoid populating ua_default_for_property() with any
default properties, but it looks like some are "required." Without
them, the style-composition process gets crashy while trying to set
initial values. Thanks to the libcss example program for the idea.
Michael Orlitzky [Thu, 16 Nov 2023 14:52:59 +0000 (09:52 -0500)]
src/svgtiny.c: use separate function for style application
We've been doing CSS in svgtiny_parse_paint_attributes(), because we
only support CSS paint attributes at the moment. But ultimately that
won't be right. Let's separate it out now into its own function,
svgtiny_parse_styles().
Michael Orlitzky [Thu, 16 Nov 2023 01:37:57 +0000 (20:37 -0500)]
include/svgtiny.h: add fill_opacity and stroke_opacity to svgtiny_shape
We already have fields for the fill and stroke opacity in the parser
state, but we have no way to record those values in the shapes we're
creating as we parse. Here we make room to do that.
Michael Orlitzky [Wed, 18 Oct 2023 00:09:42 +0000 (20:09 -0400)]
src/svgtiny.c: parse styles in svgtiny_parse_paint_attributes()
Now that the scaffolding is in place, we do the work to parse our two
supported CSS paint attributes, fill-opacity and stroke-opacity. This
amounts to,
* Calling svgtiny_select_style(), which is just a wrapper around
css_select_style()
* Passing the result to css_computed_foo_opacity() to get the
computed styles
* Populating fill_opacity and stroke_opacity in the parser state
if the corresponding styles exist
There's also a temporary hack to avoid crashing on the root node that
later goes away when we implement parent/child style composition.
Michael Orlitzky [Wed, 15 Nov 2023 17:32:23 +0000 (12:32 -0500)]
test/decode_svg.c: handle svgtiny_LIBCSS_ERROR
This test program has a switch statement to handle errors, with one
case for each svgtiny_code. Now that svgtiny_LIBCSS_ERROR belongs to
that enum, we add it to the list of cases.
This example program has a switch statement to handle errors, with one
case for each svgtiny_code. Now that svgtiny_LIBCSS_ERROR belongs to
that enum, we add it to the list of cases.
Some boilerplate will be needed when we call css_select_style() during
parsing. In preparation for (avoiding) that, we factor it out into a
convenience function called svgtiny_select_style().
Michael Orlitzky [Tue, 17 Oct 2023 15:35:13 +0000 (11:35 -0400)]
src/svgtiny_css.c: add user handler function
This function needs to be passed to dom_node_set_user_data() in
set_libcss_node_data(), but we couldn't implement it before our
css_select_handler was defined, because it passes the address of
that select handler to css_libcss_node_data_handler().
Michael Orlitzky [Tue, 17 Oct 2023 20:55:03 +0000 (16:55 -0400)]
src/svgtiny_css.c: define a css_select_handler
We define a css_select_handler structure full of all of the select
handlers we've just implemented. This is the big piece of the puzzle
that we need before we can call css_select_style().
Michael Orlitzky [Tue, 17 Oct 2023 14:22:35 +0000 (10:22 -0400)]
src/svgtiny_strings.h: intern a "userdata" key string
To implement libcss's select handler API, we need to implement two
functions that get/set "userdata" on a node. The corresponding libdom
API allows you to set arbitrary data in the form of key->value pairs;
so to identify THIS particular data, we need to use the same string
each time. For that reason we intern "_libcss_user_data" and call it
the "userdata_key".
Michael Orlitzky [Tue, 17 Oct 2023 01:19:04 +0000 (21:19 -0400)]
src/svgtiny_css.c: case-insensitivity for node_has_attribute_substring()
All of the CSS attribute selectors take a flag to make the comparison
case-insensitive. Libcss doesn't support that yet, but in the case of
node_has_attribute_substring(), factoring out the implementation and
letting it take an "insensitive" flag will be of use to us when we
implement the node_is_lang() select handler.
Michael Orlitzky [Wed, 11 Oct 2023 19:17:08 +0000 (15:17 -0400)]
src/svgtiny.c: parse inline stylesheet in svgtiny_parse_paint_attributes()
...and do nothing with it, for the moment. We are able to parse the
inline style="..." attributes right now but more scaffolding is needed
before we can utilize css_select_style().
Michael Orlitzky [Wed, 11 Oct 2023 12:27:22 +0000 (08:27 -0400)]
src/svgtiny_css.c: new function svgtiny_create_stylesheet()
We add a function to handle the creation of a new stylesheet with the
default set of parameters. This is in preparation for parsing the
inline styles, which a priori would involve copy/pasting a lot of
params.foo = bar;
lines from svgtiny_parse_style_element(). The goal is to factor the
common bits out of both the <style> and style= implementations.
src/svgtiny_css.c: new file with new svgtiny_resolve_url() function
Define a stub relative-URL resolver that assumes all URLs are absolute
and returns them unmodified. Some method of doing this is required by
libcss. At the moment, libcss does not support any SVG properties that
take url() values, so not much is lost.
src/svgtiny.c: add impotent svgtiny_preparse_styles() function
We declare and add the svgtiny_preparse_styles() function that will be
used to make a first pass through the SVG document and parse all of
the <style> elements. At the moment it is only half implemented:
once we find a <style> element, we do nothing with it. A separate
function will be used to parse a <style> once we have it.
src/svgtiny.c: initialize the libcss context in svgtiny_parse()
Before we begin parsing, we have to initialize our new css_select_ctx
by calling css_select_ctx_create(). Later, when parsing is complete,
we css_select_ctx_destroy() it.
src/svgtiny_strings.h: add "media" to the list of strings
The "media" attribute is arguably the only meaningful attribute a
<style> element has within an SVG document. Here we intern the string
"media" in preparation for parsing <style>. Libcss can at least store
the media information even if we decide not to use it.
src/svgtiny_internal.h: add CSS context to parser state
Add a css_select_ctx pointer to the svgtiny_parse_state that is
threaded through each phase of SVG parsing. This will allow us to
populate the context with any <style> sheets we find; later, we can
consult those stylesheets while constructing our svgtiny_diagram (the
abstract representation into which we parse an SVG).
The first step towards adding libcss support is to build against
libcss. For now that means getting its "cflags" and "libs" from
pkg-config and putting them into CFLAGS and LDFLAGS.