libwmf-0.2.0 Tutorial 2: The IPA



This is a combination of tutorial and reference guide for writing new device layers for libwmf.

Since no two graphics interfaces are identical, the task of the IPA (the interface between the interpreter and the device layer) is to simplify the task of translating the metafile drawing commands. (It cannot be denied that there is still considerable room for improvement.)

When writing a new device layer you will need to include the following headers:

#include <libwmf/ipa.h>
#include <libwmf/defs.h>

The former includes the API declarations as well as the IPA declarations, while the latter defines metafile constants.


wmfRGB | wmfBMP | wmfBrush | wmfPen | wmfFont | wmfDC | wmfFlood_t | wmfDrawPixel_t | wmfDrawArc_t | wmfDrawLine_t | wmfPolyLine_t | wmfDrawRectangle_t | wmfPolyRectangle_t | wmfBMP_Read_t | wmfBMP_Draw_t | wmfROP_Draw_t | wmfDrawText_t | wmfUserData_t | wmfCharDrawer

IPA Function Reference

Let us assume that you are writing a device layer called mydev, then the first requirement is an initialization function:

#include <libwmf/ipa.h>
#include <libwmf/defs.h>
#include <libwmf/mydev.h>

void wmf_mydev_function (wmfAPI* API)
{	wmfFunctionReference* FR = (wmfFunctionReference*) API->function_reference;

	/* */
The function reference has the following definition:
typedef struct _wmfFunctionReference wmfFunctionReference;

struct _wmfFunctionReference
{	void (*device_open) (wmfAPI*);
	void (*device_close) (wmfAPI*);
	void (*device_begin) (wmfAPI*);
	void (*device_end) (wmfAPI*);

	void (*flood_interior) (wmfAPI*,wmfFlood_t*);
	void (*flood_exterior) (wmfAPI*,wmfFlood_t*);

	void (*draw_pixel) (wmfAPI*,wmfDrawPixel_t*);
	void (*draw_pie) (wmfAPI*,wmfDrawArc_t*);
	void (*draw_chord) (wmfAPI*,wmfDrawArc_t*);
	void (*draw_arc) (wmfAPI*,wmfDrawArc_t*);
	void (*draw_ellipse) (wmfAPI*,wmfDrawArc_t*);
	void (*draw_line) (wmfAPI*,wmfDrawLine_t*);
	void (*poly_line) (wmfAPI*,wmfPolyLine_t*);
	void (*draw_polygon) (wmfAPI*,wmfPolyLine_t*);
	void (*draw_rectangle) (wmfAPI*,wmfDrawRectangle_t*);

	void (*rop_draw) (wmfAPI*,wmfROP_Draw_t*);
	void (*bmp_draw) (wmfAPI*,wmfBMP_Draw_t*);
	void (*bmp_read) (wmfAPI*,wmfBMP_Read_t*);
	void (*bmp_free) (wmfAPI*,wmfBMP*);

	void (*draw_text) (wmfAPI*,wmfDrawText_t*);

	void (*udata_init) (wmfAPI*,wmfUserData_t*);
	void (*udata_copy) (wmfAPI*,wmfUserData_t*);
	void (*udata_set) (wmfAPI*,wmfUserData_t*);
	void (*udata_free) (wmfAPI*,wmfUserData_t*);

	void (*region_frame) (wmfAPI*,wmfPolyRectangle_t*);
	void (*region_paint) (wmfAPI*,wmfPolyRectangle_t*);
	void (*region_clip) (wmfAPI*,wmfPolyRectangle_t*);

The initialization function has two purposes, the first being to establish the links that create the IPA by pointing the function reference variables to your own drawing functions:

#include <libwmf/ipa.h>
#include <libwmf/defs.h>
#include <libwmf/mydev.h>

void wmf_mydev_function (wmfAPI* API)
{	wmfFunctionReference* FR = (wmfFunctionReference*) API->function_reference;

	FR->device_open  = wmf_mydev_device_open;
	FR->device_close = wmf_mydev_device_close;
	FR->device_begin = wmf_mydev_device_begin;
	FR->device_end   = wmf_mydev_device_end;
	/* etc. */

	/* */

void wmf_mydev_device_open (wmfAPI* API)
{	/* */

/* etc. */

The second purpose of the initialization function is to allocate the device's data structure, set the device parameters to default values if necessary, and then to attach the data to the API->device_data hook.

/* */

typedef struct _wmf_mydev_t wmf_mydev_t;

struct _wmf_mydev_t
{	/* */

	unsigned long flags;

void wmf_mydev_function (wmfAPI* API)
{	wmfFunctionReference* FR = (wmfFunctionReference*) API->function_reference;

	wmf_mydev_t* ddata = 0;

	FR->device_open  = wmf_mydev_device_open;
	/* etc. */

	API->device_data = wmf_malloc (API,sizeof (wmf_mydev_t));

	if (API->err != wmf_E_None) return; /* insufficient memory? */

	ddata = (wmf_mydev_t*) API->device_data;

	/* */

	ddata->flags = 0;

/* */

IPA Functions

The IPA functions are called by wmf_play (), the only exception being device_close which is called by wmf_api_destroy () - and then only if device_open has been called by wmf_play ().

device_open is called the first time (and only the first time) wmf_play () is called, and is the very first IPA function to be called, just as device_close will be the very last.

At the beginning of each play cycle (i.e., each call to wmf_play ()) device_begin is called (after device_open if it is the first cycle), and at the end of each cycle device_end is called. The metafile graphics use other IPA functions.

device_open, device_begin, device_end and device_close should be written so that wmf_play () can be called repeatedly.

The names of the functions are not important. The generic names are used below:

device_open | device_close | device_begin | device_end | flood_interior | flood_exterior | draw_pixel | draw_pie | draw_chord | draw_arc | draw_ellipse | draw_line | poly_line | draw_polygon | draw_rectangle | rop_draw | bmp_draw | bmp_read | bmp_free | draw_text | udata_init | udata_copy | udata_set | udata_free | region_frame | region_paint | region_clip

Bitmap Functions

Other Functions


Compiling - The Distribution

The section applies only if you are working on the libwmf sources.

The build system uses automake and autoconf. If any changes are made to any of the various files, or to or libwmf.m4, then the build system will need to be updated. Change to the top source directory (containing and libwmf.m4) and:

# aclocal
# automake
# autoheader
# autoconf
# date >

When adding a new device layer, include/libwmf/ and src/ipa/ will need to be modifiled. Source files (src/ipa/new.c) and installing header files (include/libwmf/new.h) do not need to be added to the distribution, but other headers (src/ipa/new.h & src/ipa/new/*.h) will.

Copyright 2001 wvWare/libwmf