summaryrefslogtreecommitdiff
path: root/docs/coding-overview.html
diff options
context:
space:
mode:
Diffstat (limited to 'docs/coding-overview.html')
-rw-r--r--docs/coding-overview.html381
1 files changed, 381 insertions, 0 deletions
diff --git a/docs/coding-overview.html b/docs/coding-overview.html
new file mode 100644
index 00000000..3ab1fff1
--- /dev/null
+++ b/docs/coding-overview.html
@@ -0,0 +1,381 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>MuPDF Overview</title>
+<link rel="stylesheet" href="style.css" type="text/css">
+<meta name="viewport" content="width=device-width, initial-scale=1">
+</head>
+
+<body>
+
+<header>
+<h1>MuPDF Overview</h1>
+</header>
+
+<nav>
+<a href="http://mupdf.com/index.html">ABOUT</a>
+<a href="http://mupdf.com/news.html">NEWS</a>
+<a href="index.html">DOCUMENTATION</a>
+<a href="http://mupdf.com/downloads/">DOWNLOAD</a>
+<a href="http://git.ghostscript.com/?p=mupdf.git;a=summary">SOURCE</a>
+<a href="https://bugs.ghostscript.com/">BUGS</a>
+</nav>
+
+<article>
+
+<h2>Contents</h2>
+
+<ul>
+<li><a href="#basic-mupdf-usage-example">Basic MuPDF usage example</a>
+<li><a href="#common-function-arguments">Common function arguments</a>
+<li><a href="#error-handling">Error Handling</a>
+<li><a href="#multi-threading">Multi-threading</a>
+<li><a href="#cloning-the-context">Cloning the context</a>
+</ul>
+
+<h2><a id="basic-mupdf-usage-example">
+Basic MuPDF usage example
+</a></h2>
+
+<p>
+For an example of how to use MuPDF in the most basic way, see
+<a href="examples/example.c">docs/examples/example.c</a>.
+To limit the complexity and give an easier introduction
+this code has no error handling at all, but any serious piece of code
+using MuPDF should use the error handling strategies described below.
+
+<h2><a id="common-function-arguments">
+Common function arguments
+</a></h2>
+
+<p>
+Most functions in MuPDF's interface take a context argument.
+
+<p>
+A context contains global state used by MuPDF inside functions when
+parsing or rendering pages of the document. It contains for example:
+
+<ul>
+<li> an exception stack (see error handling below),
+<li> a memory allocator (allowing for custom allocators)
+<li> a resource store (for caching of images, fonts, etc.)
+<li> a set of locks and (un-)locking functions (for multi-threading)
+</ul>
+
+<p>
+Without the set of locks and accompanying functions the context and
+its proxies may only be used in a single-threaded application.
+
+<h2><a id="error-handling">
+Error handling
+</a></h2>
+
+<p>
+MuPDF uses a set of exception handling macros to simplify error return
+and cleanup. Conceptually, they work a lot like C++'s try/catch
+system, but do not require any special compiler support.
+
+<p>
+The basic formulation is as follows:
+
+<pre>
+fz_try(ctx)
+{
+ // Try to perform a task. Never 'return', 'goto' or
+ // 'longjmp' out of here. 'break' may be used to
+ // safely exit (just) the try block scope.
+}
+fz_always(ctx)
+{
+ // Any code here is always executed, regardless of
+ // whether an exception was thrown within the try or
+ // not. Never 'return', 'goto' or longjmp out from
+ // here. 'break' may be used to safely exit (just) the
+ // always block scope.
+}
+fz_catch(ctx)
+{
+ // This code is called (after any always block) only
+ // if something within the fz_try block (including any
+ // functions it called) threw an exception. The code
+ // here is expected to handle the exception (maybe
+ // record/report the error, cleanup any stray state
+ // etc) and can then either exit the block, or pass on
+ // the exception to a higher level (enclosing) fz_try
+ // block (using fz_throw, or fz_rethrow).
+}
+</pre>
+
+<p>
+The fz_always block is optional, and can safely be omitted.
+
+<p>
+The macro based nature of this system has 3 main limitations:
+
+<ol>
+<li> <p>
+ Never return from within try (or 'goto' or longjmp out of it).
+ This upsets the internal housekeeping of the macros and will
+ cause problems later on. The code will detect such things
+ happening, but by then it is too late to give a helpful error
+ report as to where the original infraction occurred.
+
+<li> <p>
+ The fz_try(ctx) { ... } fz_always(ctx) { ... } fz_catch(ctx) { ... }
+ is not one atomic C statement. That is to say, if you do:
+<pre>
+if (condition)
+ fz_try(ctx) { ... }
+ fz_catch(ctx) { ... }
+</pre>
+ then you will not get what you want. Use the following instead:
+<pre>
+if (condition) {
+ fz_try(ctx) { ... }
+ fz_catch(ctx) { ... }
+}
+</pre>
+
+<li> <p>
+ The macros are implemented using setjmp and longjmp, and so
+ the standard C restrictions on the use of those functions
+ apply to fz_try/fz_catch too. In particular, any "truly local"
+ variable that is set between the start of fz_try and something
+ in fz_try throwing an exception may become undefined as part
+ of the process of throwing that exception.
+
+ <p>
+ As a way of mitigating this problem, we provide a fz_var()
+ macro that tells the compiler to ensure that that variable is
+ not unset by the act of throwing the exception.
+</ol>
+
+<p>
+A model piece of code using these macros then might be:
+
+<pre>
+house build_house(plans *p)
+{
+ material m = NULL;
+ walls w = NULL;
+ roof r = NULL;
+ house h = NULL;
+ tiles t = make_tiles();
+
+ fz_var(w);
+ fz_var(r);
+ fz_var(h);
+
+ fz_try(ctx)
+ {
+ fz_try(ctx)
+ {
+ m = make_bricks();
+ }
+ fz_catch(ctx)
+ {
+ // No bricks available, make do with straw?
+ m = make_straw();
+ }
+ w = make_walls(m, p);
+ r = make_roof(m, t);
+ // Note, NOT: return combine(w,r);
+ h = combine(w, r);
+ }
+ fz_always(ctx)
+ {
+ drop_walls(w);
+ drop_roof(r);
+ drop_material(m);
+ drop_tiles(t);
+ }
+ fz_catch(ctx)
+ {
+ fz_throw(ctx, "build_house failed");
+ }
+ return h;
+}
+</pre>
+
+<p>
+Things to note about this:
+
+<ol>
+<li> If make_tiles throws an exception, this will immediately be
+ handled by some higher level exception handler. If it
+ succeeds, t will be set before fz_try starts, so there is no
+ need to fz_var(t);
+
+<li> We try first off to make some bricks as our building material.
+ If this fails, we fall back to straw. If this fails, we'll end
+ up in the fz_catch, and the process will fail neatly.
+
+<li> We assume in this code that combine takes new reference to
+ both the walls and the roof it uses, and therefore that w and
+ r need to be cleaned up in all cases.
+
+<li> We assume the standard C convention that it is safe to destroy
+ NULL things.
+</ol>
+
+<h2><a id="multi-threading">
+Multi-threading
+</a></h2>
+
+<p>
+First off, study the basic usage example in
+<a href="examples/example.c">docs/examples/example.c</a>
+and make sure you understand how it works as the data structures manipulated
+there will be referred to in this section too.
+
+<p>
+MuPDF can usefully be built into a multi-threaded application without
+the library needing to know anything threading at all. If the library
+opens a document in one thread, and then sits there as a 'server'
+requesting pages and rendering them for other threads that need them,
+then the library is only ever being called from this one thread.
+
+<p>
+Other threads can still be used to handle UI requests etc, but as far
+as MuPDF is concerned it is only being used in a single threaded way.
+In this instance, there are no threading issues with MuPDF at all,
+and it can safely be used without any locking, as described in the
+previous sections.
+
+<p>
+This section will attempt to explain how to use MuPDF in the more
+complex case; where we genuinely want to call the MuPDF library
+concurrently from multiple threads within a single application.
+
+<p>
+MuPDF can be invoked with a user supplied set of locking functions.
+It uses these to take mutexes around operations that would conflict
+if performed concurrently in multiple threads. By leaving the
+exact implementation of locks to the caller MuPDF remains threading
+library agnostic.
+
+<p>
+The following simple rules should be followed to ensure that
+multi-threaded operations run smoothly:
+
+<ol>
+<li> <p>
+ "No simultaneous calls to MuPDF in different threads are
+ allowed to use the same context."
+
+ <p>
+ Most of the time it is simplest to just use a different
+ context for every thread; just create a new context at the
+ same time as you create the thread. For more details see
+ "Cloning the context" below.
+
+<li> <p>
+ "No simultaneous calls to MuPDF in different threads are
+ allowed to use the same document."
+
+ <p>
+ Only one thread can be accessing a document at a time, but
+ once display lists are created from that document, multiple
+ threads at a time can operate on them.
+
+ <p>
+ The document can be used from several different threads as
+ long as there are safeguards in place to prevent the usages
+ being simultaneous.
+
+<li> <p>
+ "No simultaneous calls to MuPDF in different threads are
+ allowed to use the same device."
+
+ <p>
+ Calling a device simultaneously from different threads will
+ cause it to get confused and may crash. Calling a device from
+ several different threads is perfectly acceptable as long as
+ there are safeguards in place to prevent the calls being
+ simultaneous.
+</ol>
+
+<p>
+So, how does a multi-threaded example differ from a non-multithreaded
+one?
+
+<p>
+Firstly, when we create the first context, we call fz_new_context
+as before, but the second argument should be a pointer to a set
+of locking functions.
+
+<p>
+The calling code should provide FZ_LOCK_MAX mutexes, which will be
+locked/unlocked by MuPDF calling the lock/unlock function pointers
+in the supplied structure with the user pointer from the structure
+and the lock number, i (0 &lt;= i &lt; FZ_LOCK_MAX). These mutexes can
+safely be recursive or non-recursive as MuPDF only calls in a non-
+recursive style.
+
+<p>
+To make subsequent contexts, the user should NOT call fz_new_context
+again (as this will fail to share important resources such as the
+store and glyphcache), but should rather call fz_clone_context.
+Each of these cloned contexts can be freed by fz_free_context as
+usual. They will share the important data structures (like store,
+glyph cache etc) with the original context, but will have their
+own exception stacks.
+
+<p>
+To open a document, call fz_open_document as usual, passing a context
+and a filename. It is important to realise that only one thread at a
+time can be accessing the documents itself.
+
+<p>
+This means that only one thread at a time can perform operations such
+as fetching a page, or rendering that page to a display list. Once a
+display list has been obtained however, it can be rendered from any
+other thread (or even from several threads simultaneously, giving
+banded rendering).
+
+<p>
+This means that an implementer has 2 basic choices when constructing
+an application to use MuPDF in multi-threaded mode. Either he can
+construct it so that a single nominated thread opens the document
+and then acts as a 'server' creating display lists for other threads
+to render, or he can add his own mutex around calls to mupdf that
+use the document. The former is likely to be far more efficient in
+the long run.
+
+<p>
+For an example of how to do multi-threading see
+<a href="examples/multi-threaded.c">docs/examples/multi-threaded.c</a>
+which has a main thread and one rendering thread per page.
+
+<h2><a id="cloning-the-context">
+Cloning the context
+</a></h2>
+
+<p>
+As described above, every context contains an exception stack which is
+manipulated during the course of nested fz_try/fz_catches. For obvious
+reasons the same exception stack cannot be used from more than one
+thread at a time.
+
+<p>
+If, however, we simply created a new context (using fz_new_context) for
+every thread, we would end up with separate stores/glyph caches etc,
+which is not (generally) what is desired. MuPDF therefore provides a
+mechanism for "cloning" a context. This creates a new context that
+shares everything with the given context, except for the exception
+stack.
+
+<p>
+A commonly used general scheme is therefore to create a 'base' context
+at program start up, and to clone this repeatedly to get new contexts
+that can be used on new threads.
+
+</article>
+
+<footer>
+<a href="http://artifex.com"><img src="artifex-logo.png" align="right"></a>
+Copyright &copy; 2006-2017 Artifex Software Inc.
+</footer>
+
+</body>
+</html>