23.6 Stroking

Where filling a path simply requires details of the fill to be used, stroking a path requires far more information; varying the thickness of the line, or the dash pattern, or linecaps/joins used can can radically alter its appearance. The details of these stroke attributes are passed in a fz_stroke_state structure.

Stroke states are created and managed with reference counting using the functions described below, but unlike other structures, the definition of the structure itself is public. Callers are expected to alter the different fields in the structure themselves. The sole exception to this is the refs field, that should only be altered using the usual fz_keep_stroke_state and fz_drop_stroke_state mechanisms.

typedef struct fz_stroke_state_s fz_stroke_state; 
 
typedef enum fz_linecap_e 
{ 
   FZ_LINECAP_BUTT = 0, 
   FZ_LINECAP_ROUND = 1, 
   FZ_LINECAP_SQUARE = 2, 
   FZ_LINECAP_TRIANGLE = 3 
} fz_linecap; 
 
typedef enum fz_linejoin_e 
{ 
   FZ_LINEJOIN_MITER = 0, 
   FZ_LINEJOIN_ROUND = 1, 
   FZ_LINEJOIN_BEVEL = 2, 
   FZ_LINEJOIN_MITER_XPS = 3 
} fz_linejoin; 
 
struct fz_stroke_state_s 
{ 
   int refs; 
   fz_linecap start_cap, dash_cap, end_cap; 
   fz_linejoin linejoin; 
   float linewidth; 
   float miterlimit; 
   float dash_phase; 
   int dash_len; 
   float dash_list[32]; 
};

It is hoped that the meaning of the individual fields within a fz_stroke_state structure are self evident to anyone working in this field. If you are unfamiliar with any of the concepts here, see “The PDF Reference Manual” or “The Postscript Language Reference Manual” for more details.

Most simply a reference to a stroke state structure can be obtained by calling fz_new_stroke_state:

/* 
   fz_new_stroke_state: Create a new (empty) stroke state 
   structure (with no dash data) and return a reference to it. 
 
   Throws exception on failure to allocate. 
*/ 
fz_stroke_state *fz_new_stroke_state(fz_context *ctx);

For stroke states that include dash information, call:

/* 
   fz_new_stroke_state_with_dash_len: Create a new (empty) 
   stroke state structure, with room for dash data of the 
   given length, and return a reference to it. 
 
   len: The number of dash elements to allow room for. 
 
   Throws exception on failure to allocate. 
*/ 
fz_stroke_state *fz_new_stroke_state_with_dash_len(fz_context *ctx, int len);

Once obtained, references can be kept or dropped in the usual fashion:

/* 
   fz_keep_stroke_state: Take an additional reference to 
   a stroke state structure. 
 
   No modifications should be carried out on a stroke 
   state to which more than one reference is held, as 
   this can cause race conditions. 
 
   Never throws exceptions. 
*/ 
fz_stroke_state *fz_keep_stroke_state(fz_context *ctx, const fz_stroke_state *stroke); 
 
/* 
   fz_drop_stroke_state: Drop a reference to a stroke 
   state structure, destroying the structure if it is 
   the last reference. 
 
   Never throws exceptions. 
*/ 
void fz_drop_stroke_state(fz_context *ctx, const fz_stroke_state *stroke);

Once more than one reference is held to a stroke state, it should be considered ‘frozen’ or ‘immutable’ as other reference holders may be confused by changes to it. Accordingly, we provide functions to ensure that we are holding a reference to an ‘unshared’ stroke state:

/* 
   fz_unshare_stroke_state: Given a reference to a 
   (possibly) shared stroke_state structure, return 
   a reference to an equivalent stroke_state structure 
   that is guaranteed to be unshared (i.e. one that can 
   safely be modified). 
 
   shared: The reference to a (possibly) shared structure 
   to unshare. Ownership of this reference is passed in 
   to this function, even in the case of exceptions being 
   thrown. 
 
   Exceptions may be thrown in the event of failure to 
   allocate if required. 
*/ 
fz_stroke_state *fz_unshare_stroke_state(fz_context *ctx, fz_stroke_state *shared); 
 
/* 
   fz_unshare_stroke_state_with_dash_len: Given a reference to a 
   (possibly) shared stroke_state structure, return a reference 
   to a stroke_state structure (with room for a given amount of 
   dash data) that is guaranteed to be unshared (i.e. one that 
   can safely be modified). 
 
   shared: The reference to a (possibly) shared structure 
   to unshare. Ownership of this reference is passed in 
   to this function, even in the case of exceptions being 
   thrown. 
 
   Exceptions may be thrown in the event of failure to 
   allocate if required. 
*/ 
fz_stroke_state *fz_unshare_stroke_state_with_dash_len(fz_context *ctx, fz_stroke_state *shared, int len);

Finally, we have a simple function to clone a stroke state and return a new reference to it:

/* 
   fz_clone_stroke_state: Create an identical stroke_state 
   structure and return a reference to it. 
 
   stroke: The stroke state reference to clone. 
 
   Exceptions may be thrown in the event of a failure to 
   allocate. 
*/ 
fz_stroke_state *fz_clone_stroke_state(fz_context *ctx, fz_stroke_state *stroke);