Storage

Because Paths are such a crucial part of MuPDF, and are used so widely in document content, we take particular care to allow them to be expressed and accessed efficiently.

This means that at path construction time, we spot simple cases where we can optimise the path representation. For example, a move immediately following a move can cause the first move to be dropped. Similarly, a curve with both control points coincident with the endpoints can be expressed as a line.

This means that if you read a path out after construction (see PathWalking PathWalking) you cannot rely on the exact representation being the same.

In addition, after constructing a path, there are some simple things that can be done to minimise the memory used.

As paths are constructed, the data buffers within them grow. For efficiency, these grow with some slack in them, so at the end of construction there can be a non-trivial amount of space wasted.

If you intend to simply use the path, and then discard it, this does not matter. If instead you intend to keep the path around for a while, it may be worth calling fz_trim_path to shrink the storage buffers as much as possible.


\begin{lstlisting}
/*
fz_trim_path: Minimise the internal storage
used by a pa...
...ceptions.
*/
void fz_trim_path(fz_context *ctx, fz_path *path);
\end{lstlisting}

MuPDF automatically calls this function when fz_keep_path is called for the first time as having more than one reference to a path is considered a good indication of it being kept around for a while.

For cases where large numbers of paths are kept around for a long period of time, for example in a fz_display_list (see DisplayLists DisplayLists), it can be advantageous to `pack' paths to further minimise the space they use.

To pack a path, first call fz_packed_path_size to obtain the number of bytes required to pack a path:


\begin{lstlisting}
/*
fz_packed_path_size: Return the number of
bytes required...
...ws exceptions.
*/
int fz_packed_path_size(const fz_path *path);
\end{lstlisting}

Then, call fz_pack_path with some (suitably aligned) memory of the appropriate size to actually pack the path:


\begin{lstlisting}
/*
fz_pack_path: Pack a path into the given block.
\par
To m...
...(fz_context *ctx, uint8_t *pack, int max, const fz_path *path);
\end{lstlisting}

After a successful call to fz_pack_path, the pointer to the block of memory can be cast to an fz_path * and used as normal.

All the path routines recognise packed paths and will use them interchangeably. Packed paths may not be modified once created, however.