File: plugins.tex

package info (click to toggle)
graphviz 14.1.1-1
  • links: PTS
  • area: main
  • in suites: forky, sid
  • size: 139,440 kB
  • sloc: ansic: 142,129; cpp: 11,960; python: 7,770; makefile: 4,043; yacc: 3,030; xml: 2,972; tcl: 2,495; sh: 1,388; objc: 1,159; java: 560; lex: 423; perl: 243; awk: 156; pascal: 139; php: 58; ruby: 49; cs: 31; sed: 1
file content (378 lines) | stat: -rw-r--r-- 15,714 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
\section{Adding Plug-ins}
\label{sec:pluginmain}

The \gviz\ framework allows the programmer to use plug-ins to
extend the system in several ways. For example, the programmer can add new
graph layout engines along with new renderers and their related
functions. Table~\ref{table:apis} describes the plug-in APIs
supported by \gviz.
\begin{table*}[htbp]\footnotesize
\centering
\begin{tabular}[t]{|l|l|c|p{2.0in}|} \hline
\multicolumn{1}{|c|}{Kind} & \multicolumn{1}{|c|}{Functions} & \multicolumn{1}{|c|}{Features} & \multicolumn{1}{c|}{Description} \\ \hline
{\tt API\_render} & {\tt gvrender\_engine\_t} & {\tt gvrender\_features\_t} & Functions for rendering a graph \\
{\tt API\_device} & {\tt gvdevice\_engine\_t} & - & Functions for initializing and terminating a device \\
{\tt API\_loadimage} & {\tt gvloadimage\_engine\_t} & - & Functions for converting from one image format to another \\
{\tt API\_layout} & {\tt gvlayout\_engine\_t} & {\tt gvlayout\_features\_t} & Functions for laying out a graph \\
{\tt API\_textlayout} & {\tt gvtextlayout\_engine\_t} & - & Functions for resolving font names and text size \\
\hline
\end{tabular}
\caption{Plug-in API types}
\label{table:apis}
\end{table*}
Each plug-in is defined by an engine structure containing its function
entry points, and a features structure specifying features supported
by the plug-in. Thus, a renderer is defined by values of type
{\tt gvrender\_engine\_t} and {\tt gvrender\_features\_t}.

Once all of the plug-ins of a given kind are defined, they should be
gathered into a 0-terminated array of element type {\tt gvplugin\_installed\_t},
whose fields are shown in Figure~\ref{fig:installed}.
\begin{figure*}[htb]
\centering
\begin{tabular}{|l|} \hline
int id; \\
char *type; \\
int quality; \\
void *engine; \\
void *features; \\
\hline
\end{tabular}
\caption{Plug-in fields}
\label{fig:installed}
\end{figure*}
The fields have the following meanings.
\begin{description}
\item[{\tt id}]
Identifier for a given plug-in within a given package and with
a given API kind. Note that the {\tt id} need only be unique within
its plug-in package, as these packages are assumed to be independent.
\item[{\tt type}]
Name for a given plug-in, used during plug-in lookup.
\item[{\tt quality}]
An arbitrary integer used for ordering plug-ins with the same {\tt type}.
Plug-ins with larger values will be chosen before plug-ins with smaller
values.
\item[{\tt engine}]
Points to the related engine structure.
\item[{\tt features}]
Points to the related features structure.
\end{description}

As an example, suppose we wish to add various renderers for
bitmap output. A collection of these might be combined as follows.
\begin{verbatim}
gvplugin_installed_t render_bitmap_types[] = {
    {0, "jpg", 1, &jpg_engine, &jpg_features},
    {0, "jpeg", 1, &jpg_engine, &jpg_features},
    {1, "png", 1, &png_engine, &png_features},
    {2, "gif", 1, &gif_engine, &gif_features},
    {0, NULL, 0, NULL, NULL}
};
\end{verbatim}
Note that this allows {\tt "jpg"} and {\tt "jpeg"} to refer to the
same renderers.
For the plug-in kinds without a features structure, the feature pointer in its
{\tt gvplugin\_installed\_t} should be NULL.

All of the plug-ins of all API kinds should then be
gathered into a 0-terminated array of element type {\tt gvplugin\_api\_t}.
For each element, 
the first field indicates the kind of API, and the second points to the
array of plug-ins described above ({\tt gvplugin\_installed\_t}).
  
Continuing our example, if we have supplied, in addition
to the bitmap rendering plug-ins, plug-ins to render VRML, and
plug-ins to load images, we would define
\begin{verbatim}
gvplugin_api_t apis[] = {
    {API_render, &render_bitmap_types},
    {API_render, &render_vrml_types},
    {API_loadimage, &loadimage_bitmap_types},
    {0, 0},
};
\end{verbatim}
Here {\tt render\_vrml\_types} and  {\tt render\_vrml\_types}
are also 0-terminated arrays of element type {\tt gvplugin\_installed\_t}.
Note that there can be multiple items of the same API kind.

A final definition is used to attach a name to the package of
all the plug-ins. This is done using a {\tt gvplugin\_library\_t}
structure. Its first field is a {\tt char*} giving the name of the
package. The second field is a {\tt gvplugin\_api\_t*} pointing to
the array described above. The structure itself must be named
{\tt gvplugin\_{\em name}\_LTX\_library}, where {\em name} is the
name of the package as defined in the first field. 

For example, if we have decided to call our package {\tt "bitmap"},
we could use the following definition:
\begin{verbatim}
gvplugin_library_t gvplugin_bitmap_LTX_library = { "bitmap", apis };
\end{verbatim}

To finish the installation of the package, it is necessary to create
a dynamic library containing the {\tt gvplugin\_library\_t} value and
all of the functions and data referred by it, either directly or
indirectly. The library must be named {\tt gvplugin\_{\em name}},
where again {\em name} is the name of the package. The actual filename
of the library will be system-dependent. For example, on Linux systems,
our library {\tt gvplugin\_bitmap} would have filename 
{\tt libgvplugin\_bitmap.so.3}. 

In most cases, \gviz\ is built with
a plug-in version number. This number must be included in the library's
filename, following any system-dependent conventions. 
The number is given as the value of {\tt plugins} in the file
{\tt libgvc.pc}, which can be found in the directory {\tt lib/pkgconfig}
where \gviz\ was installed.
In our example, the ``3'' in the library's filename gives the version number. 

Finally, the library must be installed in the \gviz\ library directory,
and {\tt dot -c} must be run to add the package to the \gviz\ configuration.
Note that both of these steps typically assume that one has installer
privileges.\footnote{
Normally, for builds intended for local installation {\tt dot -c} is run 
during {\tt make install}.
It may be necessary to run this manually if cross-compiling or otherwise 
manually moving binaries to a different system. 
}

In the remainder of this section, we shall look at the first 
three types of plug-in APIs in more detail.

\subsection{Writing a renderer plug-in}
\label{sec:plugin}
A renderer plug-in has two parts.
The first consists of a structure of type {\tt gvrender\_engine\_t}
defining the renderer's actions, as described in Section~\ref{sec:renderers}.
Recall that any field may contain a NULL pointer. 

For the second part, the programmer must provide a structure of type 
{\tt gvrender\_features\_t}. This record provides \gviz\ with
information about the renderer. 
Figure~\ref{fig:features} list the fields involved.
\begin{figure*}[htbp]
\centering
\begin{tabular}{|l|} \hline
int flags; \\
double default\_margin; \\
double default\_pad; \\
pointf default\_pagesize; \\
pointf default\_dpi; \\
char **knowncolors; \\
int sz\_knowncolors; \\
color\_type\_t color\_type; \\
char *device; \\
char *loadimage\_target; \\
\hline
\end{tabular}
\caption{Features of a renderer}
\label{fig:features}
\end{figure*}
Some of the default values may be overridden by the input graph.

We now describe the fields in detail.
\begin{description}
\item[{\tt flags}]
Bit-wise of {\tt or} flags indicating properties of the renderer.
These flags are described in Table~\ref{table:renderflags}.
\item[{\tt default\_margin}]
Default margin size in points. This is the amount
of space left around the drawing.
\item[{\tt default\_pad}]
Default pad size in points. This is the amount
by which the graph is inset within the drawing region. Note that the
drawing region may be filled with a background color.
\item[{\tt default\_pagesize}]
Default page size size in points. For example, an 8.5 by 11 inch letter-sized
page would have a {\tt default\_pagesize} of 612 by 792.
\item[{\tt default\_dpi}]
Default resolution, in pixels per inch. Note that the x and y values
may be different to support non-square pixels.
\item[{\tt knowncolors}]
An array of character pointers giving a lexicographically ordered
\footnote{The ordering must be done byte-wise using 
the {\tt LANG=C} locale for
byte comparison.} list of the color names supported by the renderer.
\item[{\tt sz\_knowncolors}]
The number of items in the {\tt knowncolors} array.
\item[{\tt color\_type}]
The preferred representation for colors. See Section~\ref{sec:color}.
\item[{\tt device}]
The name of a device, if any, associated with the renderer. For example,
a renderer using GTK for output might specify {\tt "gtk"} as its device.
If a name is given, the library will look for a plug-in of type API\_device
with that name, and use the associated functions to initialize and terminate
the device. See Section~\ref{sec:device}. 
\item[{\tt loadimage\_target}]
The name of the preferred type of image format for the renderer.
When a user-supplied image is given, the library will attempt to find
a function that will convert the image from its original format to
the renderer's preferred one. A user-defined renderer may need to
provide, as additional plug-ins, its own functions for handling the conversion.
\end{description}

\begin{table*}[htbp]\footnotesize
\centering
\begin{tabular}[t]{|l|p{3.5in}|} \hline
\multicolumn{1}{|c|}{Flag} & \multicolumn{1}{c|}{Description} \\ \hline
{\tt GVRENDER\_DOES\_ARROWS} & Built-in arrowheads on splines \\
{\tt GVRENDER\_DOES\_LAYERS} & Supports graph layers \\
{\tt GVRENDER\_Y\_GOES\_DOWN} & Output coordinate system has the origin in
the upper left corner \\
{\tt GVRENDER\_DOES\_TRANSFORM} & Can handle transformation (scaling,
translation, rotation) from universal
to device coordinates. If false, the library will do the transformation
before passing any coordinates to the renderer \\
{\tt GVRENDER\_DOES\_LABELS} & Wants an object's label, if any, provided 
as text during rendering \\
{\tt GVRENDER\_DOES\_MAPS} & Supports regions to which URLs can be attached.
If true, URLs are provided to the renderer, 
either as part of the {\tt job->obj} or via the renderer's {\tt begin\_anchor}
function \\
{\tt GVRENDER\_DOES\_MAP\_RECTANGLE} & Rectangular regions can be mapped \\
{\tt GVRENDER\_DOES\_MAP\_CIRCLE} & Circular regions can be mapped \\
{\tt GVRENDER\_DOES\_MAP\_POLYGON} & Polygons can be mapped \\
{\tt GVRENDER\_DOES\_MAP\_ELLIPSE} & Ellipses can be mapped \\
{\tt GVRENDER\_DOES\_MAP\_BSPLINE} & B-splines can be mapped \\
{\tt GVRENDER\_DOES\_TOOLTIPS} & If true, tooltips are provided to the renderer,
either as part of the {\tt job->obj} or via the renderer's {\tt begin\_anchor}
function \\
{\tt GVRENDER\_DOES\_TARGETS} & If true, targets are provided to the renderer, 
either as part of the {\tt job->obj} or via the renderer's {\tt begin\_anchor}
function \\
{\tt GVRENDER\_DOES\_Z} & Uses a 3D output model \\
{\tt GVRENDER\_NO\_WHITE\_BG} & Does not paint white background, assumes white
paper -Tps \\
\hline
\end{tabular}
\caption{Renderer properties}
\label{table:renderflags}
\end{table*}

\subsection{Writing a device plug-in}
\label{sec:device}

A device plug-in provides hooks for \gviz\ to handle any
device-specific operations needed before and after rendering.
The related engine of type {\tt gvdevice\_engine\_t} has 2 entry points:
\begin{verbatim}
    void (*initialize) (GVJ_t*);
    void (*finalize) (GVJ_t*);
\end{verbatim}
which are called at the beginning and end of rendering each job.
The initialize routine might open a canvas on window system, or
set up a new page for printing;
the finalize routine might go into an event loop after which it could close
the output device.

\subsection{Writing an image loading plug-in}
\label{sec:imageload}

A image loading plug-in has engine type
{\tt gvimageload\_engine\_t} and provides a single entry point which can be
used to read in an image,
convert the image from one format to another, and write the result.
Since the function actually does rendering, it is usually closely tied
to a specific renderer plug-in.
\begin{verbatim}
    void (*loadimage) (GVJ_t *job, usershape_t *us, boxf b, bool filled);
\end{verbatim}
When called, {\tt loadimage} is given the current job, a pointer to the
input image {\tt us}, and the bounding box {\tt b} in device coordinates
where the image should be written. The boolean {\tt filled} value indicates
whether the bounding box should first be filled.

The {\tt type} value for an image loading plug-in's 
{\tt gvplugin\_installed\_t} entry should specify the input and output
formats it handles. Thus, a plug-in converting JPEG to GIF would be
called {\tt "jpeg2gif"}. Since an image loader may well want to read in
an image in some format, and then render the image using the same format,
it is quite reasonable for the input and output formats to be identical,
e.g. {\tt "gif2gif"}.

Concerning the type {\tt usershape\_t}, its most important fields
are shown in Figure~\ref{fig:usershape}.
\begin{figure*}[htbp]
\centering
\begin{tabular}{|l|} \hline
char *name; \\
FILE *f; \\
imagetype\_t type; \\
unsigned int x, y; \\
unsigned int w, h; \\
unsigned int dpi; \\
void *data; \\
size\_t datasize; \\
void (*datafree)(usershape\_t *us); \\
\hline
\end{tabular}
\caption{Fields in {\tt usershape\_t}}
\label{fig:usershape}
\end{figure*}
These fields have the following meanings:
\begin{description}
\item[{\tt name}]
The name of the image.
\item[{\tt f}]
An open input stream to the image's data. Since the image might
be processed multiple times, the application should use a function
such as {\tt fseek} to make sure the file pointer points to the
beginning of the file.
\item[{\tt type}]
The format of the image. The formats supported in \gviz\ are
{\tt FT\_BMP}, {\tt FT\_GIF}, {\tt FT\_PNG}, {\tt FT\_JPEG}, {\tt FT\_PDF}, 
{\tt FT\_PS} and {\tt FT\_EPS}. The value {\tt FT\_NULL} indicates an
unknown image type. 
\item[{\tt x} and {\tt y}]
The coordinates of the lower-left corner of image in image units.
This is usually the origin but some images such as those in PostScript
format may be translated away from the origin.
\item[{\tt w} and {\tt h}]
The width and height of image in image units
\item[{\tt dpi}]
The number of image units per inch
\item[{\tt data}, {\tt datasize}, {\tt datafree}]
These fields can be used to cache the converted image data so
that the file I/O and conversion need only be done once. The
data can be stored via {\tt data}, with {\tt datasize} giving the
number of bytes used. In this case, the image loading code should
store a clean-up handler in {\tt datafree}, which can be called
to release any memory allocated. 

If {\tt loadimage} does caching, it can check if {\tt us->data}
is NULL. If so, it can read and cache the image. If not, it should
check that the {\tt us->datafree} value points to its own {\tt datafree}
routing. If not, then some other image loader has cached data there.
The {\tt loadimage} function must them call the current {\tt us->datafree}
function before caching its own version of the image. 

The code template in Figure~\ref{fig:caching}
indicates how caching should be handled.
\end{description}
\begin{figure}[hbt]
\begin{verbatim}
    if (us->data) {
        if (us->datafree != my_datafree) {
            us->datafree(us);  /* free incompatible cache data */
            us->data = NULL;
            us->datafree = NULL;
            us->datasize = 0;
        }
    }

    if (!us->data) { 
       /* read image data from us->f and convert it;
        * store the image data into memory pointed to by us->data;
        * set us->datasize and us->datafree to the appropriate values.
        */
    }

    if (us->data) {
       /* emit the image data in us->data */
    }
\end{verbatim}
\caption{Caching converted images}
\label{fig:caching}
\end{figure}