[cairo] API Shakeup: cairo_current_path -> cairo_copy_path_data

Carl Worth cworth at cworth.org
Tue Feb 22 13:32:55 PST 2005


On Mon, 24 Jan 2005 10:14:08 -0800, Keith Packard wrote:
> Perhaps:
> 
> typedef union {
> 	struct {
> 		enum { Move, Draw, Curve } Type;
> 		uint16_t	len;
> 	} head;
> 	double value;
> } cairo_path_elt_t;

After debating the various options at some length, we decided on a
slightly simpler to use (and slightly less packed) variant of the
above.

Here's the version I have in my notes, though I don't think we talked
about the specific names of some things (eg. "header") nor the types
of some (eg. int length), so suggestions in those areas would be
welcome:

	typedef union {
	    struct {
	        enum {
	            CAIRO_PATH_MOVE_TO,
	            CAIRO_PATH_LINE_TO,
	            CAIRO_PATH_CURVE_TO,
	            CAIRO_PATH_CLOSE_PATH,
	            CAIRO_PATH_END
	        } type;
	        int length;
	    } header;
	    struct {
	        double x, y;
	    } point;
	} cairo_path_data_t;

The advantage of this approach is that it allows direct access to the
data, (as opposed to requiring lots of function calls like the opaque
schemes do). Though we may still want to create macros to simplify
access. Additionally, this exposed data type allows the user to
construct a path and pass it to the library.

The proposed new functions for getting at the path data are:

	/* Get a copy of the current path.

	   Caller is responsible for the returned memory and should
	   free() it when finished.
	*/
	cairo_path_data_t *
	cairo_copy_path_data (cairo_t *cr);

	/* Get a flattened copy of the current path.
	   This is like cairo_copy_path_data except that all curves in
	   the path will first be converted to piecewise-linear
	   approximations, (within the current tolerance value). That
	   is, the result is guaranteed not to have any elements of
	   type CAIRO_PATH_CURVE_TO.

	   Caller is responsible for the returned memory and should
	   free() it when finished.
	*/
	cairo_path_data_t *
	cairo_copy_path_data_flat (cairo_t *cr);

The rationale for the word "copy" in the name rather than "current" is
to indicate that there is memory to be freed here. The convention
being that the words "create" and "copy" are signals to the user that
memory will have to be destroyed.

And we can add one new function for appending path data onto the
current path:

	void
	cairo_append_path_data (cairo_t *cr,
				cairo_path_data_t *path_data);

The usage of the cairo_path_data_t datatype may not be 100% obvious,
so sample usage will feature prominently in the documentation,
something like:

    cairo_path_data_t *path, *p;

    path = cairo_copy_path_data (cr);

    for (p = path; p->header.type != CAIRO_PATH_END; p += p->header.length) {
        switch (p->header.type) {
        case CAIRO_PATH_MOVE_TO:
            do_move_to_stuff (p[1].point.x, p[1].point.y);
            break;
        case CAIRO_PATH_LINE_TO:
            do_line_to_stuff (p[1].point.x, p[1].point.y);
            break;
        case CAIRO_PATH_CURVE_TO:
            do_curve_to_stuff (p[1].point.x, p[1].point.y,
                               p[2].point.x, p[2].point.y,
                               p[3].point.x, p[3].point.y);
            break;
        case CAIRO_PATH_CLOSE_PATH:
            do_close_path_stuff ();
            break;
        }
    }

    free (path);

As I said, that's perhaps not as obvious as I would like. (The tricky
bits are the increment by p->header.length and the initial index of 1
not 0 for the point data.) But it should be easy enough for
copy-and-paste.

I didn't feel comfortable proposing this until I had actually tried it
out. So, I've got a working implementation of this already, and I
ported kapow to use it. I was quite happy with how much simpler kapow
is now. The manipulation of the path was simple enough to fit nicely
inline within the switch statement, so four gratuitous functions
disappeared. Of course, the closure structure was also no longer
necessary. And, finally, it was very easy to simply call
cairo_new_path immediately after cairo_copy_path_data_flat rather than
doing state-saving contortions within the callbacks.

So, overall, I'm happy with the direction this change is headed.

-Carl

[*] I would have liked it if functions with "copy" or "create" in
their names were the only ones to allocate memory for the user to
free. But, alas, the cairo_begin_group/cairo_end_group calls are also
proposed to allocate memory for the user. And, try as I might, I
haven't found a clean way to get the words "copy" or "create" into
their names. So getting memory management right with those two will
require the user to learn a tiny bit more than the copy/create
convention.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 189 bytes
Desc: not available
Url : http://lists.freedesktop.org/archives/cairo/attachments/20050222/fe6e8286/attachment.pgp


More information about the cairo mailing list