summaryrefslogtreecommitdiff
path: root/doc/public/language-bindings.xml
diff options
context:
space:
mode:
Diffstat (limited to 'doc/public/language-bindings.xml')
-rw-r--r--doc/public/language-bindings.xml745
1 files changed, 745 insertions, 0 deletions
diff --git a/doc/public/language-bindings.xml b/doc/public/language-bindings.xml
new file mode 100644
index 000000000..ce437ef53
--- /dev/null
+++ b/doc/public/language-bindings.xml
@@ -0,0 +1,745 @@
+<appendix id="language-bindings">
+ <title>Creating a language binding for cairo</title>
+ <para>
+ While cairo is implemented and C, and has a C API, it is expected
+ that many users of cairo will be using it from languages other
+ than C. The glue that connects the core cairo library to another
+ language is known as a <firstterm>language
+ binding</firstterm>. This appendix attempts to collect together
+ issues that come up when creating a language bindings for cairo
+ and present standardized solutions to promote consistency among
+ the different language bindings.
+ </para>
+ <sect1 id="bindings-general">
+ <title>General considerations</title>
+ <para>
+ The naming of the central <link
+ linkend="cairo-t"><type>cairo_t</type></link> type is a
+ special exception. The object is “a cairo context” not “a
+ cairo”, and names such as <type>cairo_t</type> rather than
+ <type>cairo_context_t</type> and
+ <function>cairo_set_source()</function> rather than
+ <function>cairo_context_set_source()</function> are simply
+ abbreviations to make the C API more palatable. In languages
+ which have object-oriented syntax, this abbreviation is much
+ less useful. In fact, if ‘Cairo’ is used as a namespace, then
+ in many languages, you'd end up with a ridiculous type name
+ like ‘Cairo.Cairo’. For this reason, and for inter-language
+ consistency all object-oriented languages should name this
+ type as if it were <type>cairo_context_t</type>.
+ </para>
+ <para>
+ The punctuation and casing of the type names and
+ method names of cairo should be changed to match the general
+ convention of the language. In Java, where type names are written
+ in StudlyCaps and method names in javaCaps, cairo_font_extents_t
+ will become FontExtents and
+ <literal>cairo_set_source(cr,source)</literal>,
+ <literal>cr.setSource(source)</literal>.
+ As compared to changing the punctuation, and casing, much
+ more reluctance should be used in changing the method names
+ themselves. Even if get is usually omitted from getters in
+ your language, you shouldn't bind cairo_get_source() as
+ cr.source().
+ </para>
+ </sect1>
+ <sect1 id="bindings-memory">
+ <title>Memory management</title>
+ <para>
+ The objects in cairo can roughly be divided into two types:
+ reference-counted, opaque types like
+ <link
+ linkend="cairo-surface-t"><type>cairo_surface_t</type></link>
+ and plain structures like
+ <link
+ linkend="cairo-glyph-t"><type>cairo_glyph_t</type></link>.
+ <link
+ linkend="cairo-path-t"><type>cairo_path_t</type></link>
+ and
+ <link
+ linkend="cairo-path-data-t"><type>cairo_path_data_t</type></link>
+ are special cases and are treated separately in this appendix.
+ </para>
+ <para>
+ Refcounted opaque types all have a
+ <function>..._reference()</function>
+ function to increase the refcount by one and a
+ <function>..._destroy()</function> to decrease the refcount
+ by one. These should not be exposed to the user of the language
+ binding, but rather used to implement memory management within
+ the language binding. The simplest way to do memory management
+ for a language binding is to treat the language binding object
+ as a simple handle to the cairo object. The language binding
+ object references the cairo object, and unreferences it when
+ finalized. This is the recommended method, though there are
+ a couple of caveats to be noted:
+ </para>
+ <itemizedlist>
+ <listitem>
+ <para>
+ Equality won't work as expected. You can have two language
+ objects for the same cairo and they won't necessarily
+ compare equal. If the language allows customizing the
+ equality operation, then this is fixable by comparing
+ the underlying pointers. It also can be fixed by creating
+ at most one language object per cairo object, and
+ uniquifying via a <firstterm>pin table</firstterm> (a hash
+ table that goes from cairo object to language object).
+ For <type>cairo_surface_t</type> you can use also
+ <link
+ linkend="cairo-surface-set-user-data"><function>cairo_surface_set_user_data()</function></link>
+ instead of a separate pin table.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Derivation from the language object doesn't work because
+ you can lose the language object while keeping the Cairo
+ object. Code like:
+ </para>
+<programlisting>
+public class MySurface (ImageSurface) {
+ public MySurface (width, height) {
+ super (Format.ARGB32, width, height);
+ }
+ public int get42 () {
+ return 42;
+ }
+}
+
+ cr = Cairo(MySurface(width, height));
+ surface = cr.getTarget();
+</programlisting>
+ <para>
+ Can result in <varname>surface</varname> containing an
+ <classname>ImageSurface</classname> not a <classname>MySurface</classname>.
+ This is not easily fixable without creating memory leaks,
+ and it's probably best to simply forbid deriving from the
+ language objects.
+ </para>
+ </listitem>
+ </itemizedlist>
+ <para>
+ When a plain structure is used as a return value from cairo,
+ this is done by passing it as a “out parameter”.
+ </para>
+<programlisting>
+cairo_font_extents_t extents;
+
+cairo_font_extents (cr, &amp;extents);</programlisting>
+ <para>
+ In a language binding, this should typically be treated
+ as a return value:
+ </para>
+<programlisting>
+FontExtents extents = cr.fontExtents ();</programlisting>
+ <para>
+ A language binding has a choice in how it implements the
+ language objects for plain structures. It can use a pure
+ language object with fields corresponding to those of the C
+ structure, and convert from and to the C structure when calling
+ cairo functions or converting cairo return values. Or it
+ can keep a pointer to the C structure internally and wrap
+ it inside a language object much like occurs for refcounted
+ objects. The choice should be invisible to the user: they should
+ be able to imagine that it is implemented as a pure language
+ object.
+ </para>
+ </sect1>
+ <sect1 id="bindings-return-values">
+ <title>Multiple return values</title>
+ <para>
+ There are a number of functions in the cairo API that have
+ multiple <firstterm>out parameters</firstterm> or
+ <firstterm>in-out parameters</firstterm>. In some languages
+ these can be translated into multiple return values. In Python,
+ what is:
+ </para>
+ <programlisting>
+cairo_user_to_device (cr, &amp;x, &amp;y);</programlisting>
+ <para>
+ can by mapped to:
+ </para>
+ <programlisting>
+(x, y) = cr.user_to_device (cr, x, y);</programlisting>
+ <para>
+ but many languages don't have provisions for multiple return
+ values, so it is necessary to introduce auxiliary types.
+ Most of the functions that require the auxiliary types
+ require a type that would, in C, look like
+ </para>
+ <programlisting>
+typedef struct _cairo_point cairo_point_t;
+struct _cairo_point {
+ double x;
+ double y;
+}</programlisting>
+ <para>
+ The same type should be used both for functions that use a pair
+ of coordinates as an absolute position, and functions that use
+ a pair of coordinates as a displacement. While an argument could
+ be made that having a separate “distance” type is more correct,
+ it is more likely just to confuse users.
+ </para>
+ <programlisting>
+void
+cairo_user_to_device (cairo_t *cr, double *x, double *y);
+
+void
+cairo_user_to_device_distance (cairo_t *cr, double *dx, double *dy);
+
+void
+cairo_device_to_user (cairo_t *cr, double *x, double *y);
+
+void
+cairo_device_to_user_distance (cairo_t *cr, double *dx, double *dy);
+
+void
+cairo_matrix_transform_distance (cairo_matrix_t *matrix, double *dx, double *dy);
+
+void
+cairo_matrix_transform_point (cairo_matrix_t *matrix, double *x, double *y);
+
+void
+cairo_get_current_point (cairo_t *cr, double *x, double *y);
+ </programlisting>
+ <para>
+ There are also a couple of functions that return four values
+ representing a rectangle. These should be mapped to a
+ “rectangle” type that looks like:
+ </para>
+ <programlisting>
+typedef struct _cairo_rectangle cairo_rectangle_t;
+struct _cairo_rectangle {
+ double x;
+ double y;
+ double width;
+ double height;
+}</programlisting>
+ <para>
+ The C function returns the rectangle as a set of two points to
+ facilitate rounding to integral extents, but this isn't worth
+ adding a “box” type to go along with the more obvious
+ “rectangle” representation.
+ </para>
+ <remark>
+ Q: Would it make sense here to define a standard
+ <function>cairo_rectangle_round()</function> method
+ that language bindings should map?
+ </remark>
+ <programlisting>
+void
+cairo_stroke_extents (cairo_t *cr,
+ double *x1, double *y1,
+ double *x2, double *y2);
+
+void
+cairo_fill_extents (cairo_t *cr,
+ double *x1, double *y1,
+ double *x2, double *y2);
+ </programlisting>
+ </sect1>
+ <sect1 id="bindings-overloading">
+ <title>Overloading and optional arguments</title>
+ <para>
+ Function overloading (having a several variants of a function
+ with the same name and different arguments) is a language
+ feature available in many languages but not in C.
+ </para>
+ <para>
+ In general, language binding authors should use restraint in
+ combining functions in the cairo API via function
+ overloading. What may seem like an obvious overload now may
+ turn out to be strange with future additions to cairo.
+ It might seem logical to make
+ <link
+ linkend="cairo-set-source-rgb"><function>cairo_set_source_rgb()</function></link>
+ an overload of <function>cairo_set_source()</function>, but future plans to add
+ <function>cairo_set_source_rgb_premultiplied()</function>,
+ which will also take three doubles make this a bad idea. For
+ this reason, only the following pairs of functions should
+ be combined via overloading
+ </para>
+ <programlisting>
+void
+cairo_set_source (cairo_t *cr, cairo_pattern_t *source);
+
+void
+cairo_set_source_surface (cairo_t *cr,
+ cairo_surface_t *source,
+ double surface_x,
+ double surface_y);
+
+void
+cairo_mask (cairo_t *cr,
+ cairo_pattern_t *pattern);
+
+void
+cairo_mask_surface (cairo_t *cr,
+ cairo_surface_t *surface,
+ double surface_x,
+ double surface_y);
+
+cairo_surface_t *
+cairo_image_surface_create (cairo_format_t format,
+ int width,
+ int height);
+cairo_surface_t *
+cairo_image_surface_create_for_data (unsigned char *data,
+ cairo_format_t format,
+ int width,
+ int height,
+ int stride);
+
+cairo_status_t
+cairo_surface_write_to_png (cairo_surface_t *surface,
+ const char *filename);
+
+cairo_status_t
+cairo_surface_write_to_png_stream (cairo_surface_t *surface,
+ cairo_write_func_t write_func,
+ void *closure);
+
+cairo_surface_t *
+cairo_image_surface_create_from_png (const char *filename);
+
+cairo_surface_t *
+cairo_image_surface_create_from_png_stream (cairo_read_func_t read_func,
+ void *closure);
+ </programlisting>
+ <para>
+ Note that there are cases where all constructors for a type
+ aren't overloaded together. For example
+ <link
+ linkend="cairo-image-surface-create-from-png"><function>cairo_image_surface_create_from_png()</function></link>
+ should <emphasis>not</emphasis> be overloaded together with
+ <link
+ linkend="cairo-image-surface-create"><function>cairo_image_surface_create()</function></link>.
+ In such cases, the remaining constructors will typically need to
+ be bound as static methods. In Java, for example, we might have:
+ </para>
+<programlisting>
+Surface surface1 = ImageSurface(Format.RGB24, 100, 100);
+Surface surface2 = ImageSurface.createFromPNG("camera.png");</programlisting>
+ <para>
+ Some other overloads that add combinations not found in C may be
+ convenient for users for language bindings that provide
+ <type>cairo_point_t</type> and <type>cairo_rectangle_t</type>
+ types, for example:
+ </para>
+ <programlisting>
+void
+cairo_move_to (cairo_t *cr,
+ cairo_point_t *point);
+void
+cairo_rectangle (cairo_t *cr,
+ cairo_rectangle_t *rectangle);
+ </programlisting>
+ </sect1>
+ <sect1 id="bindings-streams">
+ <title>Streams and File I/O</title>
+ <para>
+ Various places in the cairo API deal with reading and writing
+ data, whether from and to files, or to other sources and
+ destinations. In these cases, what is typically provided in the
+ C API is a simple version that just takes a filename, and a
+ complex version that takes a callback function.
+ An example is the PNG handling functions:
+ </para>
+<programlisting>
+cairo_surface_t *
+cairo_image_surface_create_from_png (const char *filename);
+
+cairo_surface_t *
+cairo_image_surface_create_from_png_stream (cairo_read_func_t read_func,
+ void *closure);
+
+cairo_status_t
+cairo_surface_write_to_png (cairo_surface_t *surface,
+ const char *filename);
+
+cairo_status_t
+cairo_surface_write_to_png_stream (cairo_surface_t *surface,
+ cairo_write_func_t write_func,
+ void *closure);</programlisting>
+ <para>
+ The expectation is that the filename version will be mapped
+ literally in the language binding, but the callback version
+ will be mapped to a version that takes a language stream
+ object. For example, in Java, the four functions above
+ might be mapped to:
+ </para>
+<programlisting>
+static public ImageSurface createFromPNG (String filename) throws IOException;
+static public ImageSurface createFromPNG (InputStream stream) throws IOException;
+public void writeToPNG (String filename) throws IOException;
+public void writeToPNG (OutputStream stream) throws IOException;
+</programlisting>
+ <para>
+ In many cases, it will be better to
+ implement the filename version internally
+ using the stream version, rather than building it on top of the
+ filename version in C. The reason for this is that will
+ naturally give a more standard handling of file errors for
+ the language, as seen in the above Java example, where
+ <methodname>createFromPNG()</methodname> is marked as raising
+ an exception. Propagating exceptions from inside the callback
+ function to the caller will pose a challenge to the language
+ binding implementor, since an exception must not propagate
+ through the Cairo code. A technique that will be useful in
+ some cases is to catch the exception in the callback,
+ store the exception object inside a structure pointed to by
+ <parameter>closure</parameter>, and then rethrow it once
+ the function returns.
+ </para>
+ <remark>
+ I'm not sure how to handle this for
+ <link
+ linkend="cairo-pdf-surface-create-for-stream"><function>cairo_pdf_surface_create_for_stream()</function></link>.
+ Other than keep a “exception to rethrow” thread-specific
+ variable
+ that is checked after <emphasis>every</emphasis> call to a Cairo
+ function.
+ </remark>
+ </sect1>
+ <sect1 id="bindings-errors">
+ <title>Error handling</title>
+ <para>
+ The error handling approach in C for Cairo has multiple
+ elements:
+ </para>
+ <itemizedlist>
+ <listitem><para>
+ When a method on an object fails, the object is put into
+ an error state. Subsequent operations on the object do
+ nothing. The status of the object can be queried with
+ a function like <link
+ linkend="cairo-status"><function>status()</function></link>.
+ </para></listitem>
+ <listitem><para>
+ Constructors, rather than
+ returning <constant>NULL</constant> on out-of-memory failure,
+ return a special singleton object on which all
+ operations do nothing. Retrieving the status of the
+ singleton object returns <constant>CAIRO_STATUS_NO_MEMORY</constant>
+ </para>
+ <remark>
+ Is this going to apply to
+ <type>cairo_surface_t</type> as well?
+ </remark>
+ <remark>
+ What about cairo_copy_path_data()? It's probably going to
+ have to return <constant>NULL</constant>.
+ </remark>
+ </listitem>
+ <listitem><para>
+ Errors propagate from object to object. Setting a pattern
+ in an out-of-memory state as the source of a
+ <type>cairo_t</type> puts the type into an error state.
+ </para></listitem>
+ </itemizedlist>
+ <remark>Much of the above is not yet implemented at the time of
+ this writing</remark>
+ <para>
+ A language binding could copy the C approach, and for a
+ language without exceptions, this is likely the right thing
+ to do. However, for a language with exceptions, exposing
+ a completely different style of error handling for cairo
+ would be strange. So, instead, status should be checked
+ after every call to cairo, and exceptions thrown as necessary.
+ </para>
+ <para>
+ One problem that can arise with this, in languages
+ where handling exceptions is mandatory (like Java), is that almost
+ every cairo function can result in a status being set,
+ usually because of an out-of-memory condition. This could make
+ cairo hard to use. To resolve this problem, let's classify then
+ cairo status codes:
+ </para>
+<programlisting>
+/* Memory */
+CAIRO_STATUS_NO_MEMORY,
+
+/* Programmer error */
+CAIRO_STATUS_INVALID_RESTORE
+CAIRO_STATUS_INVALID_POP_GROUP
+CAIRO_STATUS_NO_CURRENT_POINT
+CAIRO_STATUS_INVALID_MATRIX
+CAIRO_STATUS_NO_TARGET_SURFACE
+CAIRO_STATUS_INVALID_STRING
+CAIRO_STATUS_SURFACE_FINISHED
+CAIRO_STATUS_BAD_NESTING
+
+/* Language binding implementation */
+CAIRO_STATUS_NULL_POINTER
+CAIRO_STATUS_INVALID_PATH_DATA
+CAIRO_STATUS_SURFACE_TYPE_MISMATCH
+
+/* Other */
+CAIRO_STATUS_READ_ERROR
+CAIRO_STATUS_WRITE_ERROR
+</programlisting>
+ <para>
+ If we look at these, the
+ <constant>CAIRO_STATUS_NO_MEMORY</constant>
+ should map to the native out-of-memory exception, which could
+ happen at any point in any case. Most of the others indicate
+ programmer error, and handling them in user code would be
+ silly. These should be mapped into whatever the language uses
+ for assertion failures, rather than errors that are normally
+ handled. (In Java, a subclass of Error rather than Exception,
+ perhaps.) And <constant>CAIRO_STATUS_READ_ERROR</constant>,
+ and <constant>CAIRO_STATUS_WRITE_ERROR</constant> can occur
+ only in very specific places. (In fact, as described
+ in <xref linkend="bindings-streams"/>, these errors may be
+ mapped into the language's native I/O error types.)
+ So, there really aren't exceptions that the programmer must
+ handle at most points in the Cairo API.
+ </para>
+ </sect1>
+ <sect1 id="bindings-patterns">
+ <title>Patterns</title>
+ <para>
+ The cairo C API allows for creating a number of different types
+ of patterns. All of these different types of patterns map to
+ <link
+ linkend="cairo-pattern-t"><type>cairo_pattern_t</type></link>
+ in C, but in an object oriented language, there should instead
+ be a hierarchy of types. (The functions that should map to
+ constructors or static methods for the various types are listed
+ after the type, methods on that type are listed below. Note that
+ cairo_pattern_create_rgb() and cairo_pattern_create_rgba()
+ should not be overloaded with each other as a SolidPattern()
+ constructor, but should appear as static methods instead. This
+ is to maintain code clarity by making it clear how the arguments
+ relate to color components.)
+ </para>
+ <programlisting>
+cairo_pattern_t
+ <link linkend="cairo-pattern-set-matrix"><function>cairo_pattern_set_matrix()</function></link>
+ <link linkend="cairo-pattern-get-matrix"><function>cairo_pattern_get_matrix()</function></link>
+ cairo_solid_pattern_t (<link linkend="cairo-pattern-create-rgb"><function>cairo_pattern_create_rgb()</function></link> and <link linkend="cairo-pattern-create-rgba"><function>cairo_pattern_create_rgba()</function></link>)
+ cairo_surface_pattern_t (<link linkend="cairo-pattern-create-for-surface"><function>cairo_pattern_create_for_surface()</function></link>)
+ <link linkend="cairo-pattern-set-extend"><function>cairo_pattern_set_extend()</function></link>
+ <link linkend="cairo-pattern-get-extend"><function>cairo_pattern_get_extend()</function></link>
+ <link linkend="cairo-pattern-set-filter"><function>cairo_pattern_set_filter()</function></link>
+ <link linkend="cairo-pattern-get-filter"><function>cairo_pattern_get_filter()</function></link>
+ cairo_gradient_t
+ <link linkend="cairo-pattern-add-color-stop-rgb"><function>cairo_pattern_add_color_stop_rgb()</function></link>
+ <link linkend="cairo-pattern-add-color-stop-rgba"><function>cairo_pattern_add_color_stop_rgba()</function></link>
+ cairo_linear_gradient_t (<link linkend="cairo-pattern-create-linear"><function>cairo_pattern_create_linear()</function></link>)
+ cairo_radial_gradient_t (<link linkend="cairo-pattern-create-radial"><function>cairo_pattern_create_radial()</function></link>)
+ cairo_mesh_t (<link linkend="cairo-pattern-create-mesh"><function>cairo_pattern_create_mesh()</function></link>)
+ <link linkend="cairo-mesh-pattern-begin-patch"><function>cairo_mesh_pattern_begin_patch()</function></link>
+ <link linkend="cairo-mesh-pattern-end-patch"><function>cairo_mesh_pattern_end_patch()</function></link>
+ <link linkend="cairo-mesh-pattern-move-to"><function>cairo_mesh_pattern_move_to()</function></link>
+ <link linkend="cairo-mesh-pattern-line-to"><function>cairo_mesh_pattern_line_to()</function></link>
+ <link linkend="cairo-mesh-pattern-curve-to"><function>cairo_mesh_pattern_curve_to()</function></link>
+ <link linkend="cairo-mesh-pattern-set-control-point"><function>cairo_mesh_pattern_set_control_point()</function></link>
+ <link linkend="cairo-mesh-pattern-set-corner-color-rgb"><function>cairo_mesh_pattern_set_corner_color_rgb()</function></link>
+ <link linkend="cairo-mesh-pattern-set-corner-color-rgba"><function>cairo_mesh_pattern_set_corner_color_rgba()</function></link>
+ <link linkend="cairo-mesh-pattern-get-patch-count"><function>cairo_mesh_pattern_get_patch_count()</function></link>
+ <link linkend="cairo-mesh-pattern-get-path"><function>cairo_mesh_pattern_get_path()</function></link>
+ <link linkend="cairo-mesh-pattern-get-control-point"><function>cairo_mesh_pattern_get_control_point()</function></link>
+ <link linkend="cairo-mesh-pattern-get-corner-color-rgba"><function>cairo_mesh_pattern_get_corner_color_rgba()</function></link>
+ </programlisting>
+ <para>
+ </para>
+ </sect1>
+ <sect1 id="bindings-surfaces">
+ <title>Surfaces</title>
+ <para>
+ Like patterns, surfaces, which use only the
+ <link
+ linkend="cairo-surface-t"><type>cairo_surface_t</type></link>
+ type in the C API should be broken up into a hierarchy of types
+ in a language binding.
+ </para>
+ <programlisting>
+cairo_surface_t
+ cairo_image_surface_t
+ cairo_atsui_surface_t
+ cairo_win32_surface_t
+ cairo_xlib_surface_t
+ cairo_beos_surface_t
+ </programlisting>
+ <para>
+ Unlike patterns, the constructors and methods on these types are
+ clearly named, and can be trivially associated with the
+ appropriate subtype. Many language bindings will want to avoid
+ binding the platform-specific subtypes at all, since the
+ methods on these types are not useful without passing in native
+ C types. Unless there is a language binding for Xlib available,
+ there is no way to represent a XLib <type>Display</type> * in
+ that language.
+ </para>
+ <para>
+ This doesn't mean that platform-specific surface types can't
+ be used in a language binding that doesn't bind the constructor.
+ A very common situation is to use a cairo language binding in
+ combination with a binding for a higher level system like
+ the <ulink url="http://www.gtk.org/">GTK+</ulink> widget
+ toolkit. In such a situation, the higher level toolkit provides
+ ways to get references to platform specific surfaces.
+ </para>
+ <para>
+ The <link
+ linkend="cairo-surface-set-user-data"><function>cairo_surface_set_user_data()</function></link>,
+ and <link
+ linkend="cairo-surface-get-user-data"><function>cairo_surface_get_user_data()</function></link>
+ methods are provided for use in language bindings, and should
+ not be directly exposed to applications. One example of the use
+ of these functions in a language binding is creating a binding for:
+ </para>
+<programlisting>
+cairo_surface_t *
+<link linkend="cairo-image-surface-create-for-data"><function>cairo_image_surface_create_for_data</function></link> (unsigned char *data,
+ cairo_format_t format,
+ int width,
+ int height,
+ int stride);
+</programlisting>
+ <para>
+ The memory block passed in for <parameter>data</parameter> must be
+ kept around until the surface is destroyed, so the language
+ binding must have some way of determining when that happens. The
+ way to do this is to use the <parameter>destroy</parameter>
+ argument to <function>cairo_surface_set_user_data()</function>.
+ </para>
+ <remark>
+ Some languages may not have a suitable “pointer to a block of
+ data” type to pass in for <parameter>data</parameter>. And even
+ where a language does have such a type, the user will be
+ frequently able to cause the backing store to be reallocated
+ to a different location or truncated. Should we recommend a
+ standard type name and binding for a buffer object here?
+ </remark>
+ </sect1>
+ <sect1 id="bindings-fonts">
+ <title>Fonts</title>
+ <para>
+ Fonts are once more an area where there is a hierarchy of types:
+ </para>
+<programlisting>
+cairo_font_face_t
+ cairo_ft_font_face_t
+ cairo_win32_font_face_t
+cairo_scaled_font_t
+ cairo_ft_scaled_font_t
+ cairo_win32_scaled_font_t
+</programlisting>
+ <para>
+ The methods on the subtypes are, however, not useful without
+ bindings for fontconfig and FreeType or for the Win32 GDI,
+ so most language bindings will choose not to bind these
+ types.
+ </para>
+ <para>
+ The <link
+ linkend="cairo-font-face-set-user-data"><function>cairo_font_face_set_user_data()</function></link>,
+ and <link
+ linkend="cairo-font-face-get-user-data"><function>cairo_font_face_get_user_data()</function></link>
+ methods are provided for use in language bindings, and should
+ not be directly exposed to applications.
+ </para>
+ </sect1>
+ <sect1 id="bindings-path">
+ <title>cairo_path_t</title>
+ <para>
+ The <link linkend="cairo-path-t"><type>cairo_path_t</type></link> type is one
+ area in which most language bindings will differ significantly
+ from the C API. The C API for <type>cairo_path_t</type> is
+ designed for efficiency and to avoid auxiliary objects that
+ would be have to be manually memory managed by the
+ application. However,
+ a language binding should not present <type>cairo_path_t</type> as an
+ array, but rather as an opaque that can be iterated
+ over. Different languages have quite different conventions for
+ how iterators work, so it is impossible to give an exact
+ specification for how this API should work, but the type names
+ and methods should be similar to the language's mapping of the following:
+ </para>
+ <programlisting>
+typedef struct cairo_path_iterator cairo_path_iterator_t;
+typedef struct cairo_path_element cairo_path_element_t;
+
+cairo_path_iterator_t *
+cairo_path_get_iterator (cairo_path_t *path);
+
+cairo_bool_t
+cairo_path_iterator_has_next (cairo_path_iterator_t *iterator);
+
+cairo_path_element_t *
+cairo_path_iterator_next (cairo_path_iterator_t *iterator);
+
+cairo_path_element_type_t
+cairo_path_element_get_type (cairo_path_element_t *element);
+
+void
+cairo_path_element_get_point (cairo_path_element_t *element,
+ int index,
+ double *x,
+ double *y);
+ </programlisting>
+ <para>
+ The above is written using the Java conventions for
+ iterators. To illustrate how the API for PathIterator might
+ depend on the native iteration conventions of the API, examine
+ three versions of the loop, first written in a hypothetical Java
+ binding:
+ </para>
+ <programlisting>
+PathIterator iter = cr.copyPath().iterator();
+while (cr.hasNext()) {
+ PathElement element = iter.next();
+ if (element.getType() == PathElementType.MOVE_TO) {
+ Point p = element.getPoint(0);
+ doMoveTo (p.x, p.y);
+ }
+}</programlisting>
+ <para>
+ And then in a hypothetical C++ binding:
+ </para>
+ <programlisting>
+Path path = cr.copyPath();
+for (PathIterator iter = path.begin(); iter != path.end(); iter++) {
+ PathElement element = *iter;
+ if (element.getType() == PathElementType.MOVE_TO) {
+ Point p = element.getPoint(0);
+ doMoveTo (p.x, p.y);
+ }
+}</programlisting>
+ <para>
+ And then finally in a Python binding:
+ </para>
+<programlisting>
+for element in cr.copy_path():
+ if element.getType == cairo.PATH_ELEMENT_MOVE_TO:
+ (x, y) = element.getPoint(0)
+ doMoveTo (x, y);</programlisting>
+ <para>
+ While many of the API elements stay the same in the three
+ examples, the exact iteration mechanism is quite different, to
+ match how users of the language would expect to iterate over
+ a container.
+ </para>
+ <para>
+ You should not present an API for mutating or for creating new
+ <type>cairo_path_t</type> objects. In the future, these
+ guidelines may be extended to present an API for creating a
+ <type>cairo_path_t</type> from scratch for use with
+ <link
+ linkend="cairo-append-path"><function>cairo_append_path()</function></link>
+ but the current expectation is that <function>cairo_append_path()</function> will
+ mostly be used with paths from
+ <link
+ linkend="cairo-append-path"><function>cairo_copy_path()</function></link>.
+ </para>
+ </sect1>
+</appendix>
+<!--
+Local variables:
+mode: sgml
+sgml-parent-document: ("cairo-docs.xml" "book" "book" "appendix")
+End:
+-->