summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastian Rasmussen <sebras@gmail.com>2012-02-06 02:36:43 +0100
committerRobin Watts <robin@ghostscript.com>2012-02-26 19:33:20 +0000
commitc3aace6725d08238273caef5d3606f52b2dd597f (patch)
tree4a2664a02cd1c9159c36205413c02d6851d18319
parentc8dc1547226920f64f14d6aa4ad5d40563dc6845 (diff)
downloadmupdf-c3aace6725d08238273caef5d3606f52b2dd597f.tar.xz
Add introductory MuPDF documentation.
-rw-r--r--doc/overview.txt159
-rw-r--r--fitz/fitz.h128
2 files changed, 159 insertions, 128 deletions
diff --git a/doc/overview.txt b/doc/overview.txt
new file mode 100644
index 00000000..82c6b17e
--- /dev/null
+++ b/doc/overview.txt
@@ -0,0 +1,159 @@
+Basic MuPDF usage example
+=========================
+
+For an example of how to use MuPDF in the most basic way, see
+doc/example.c. 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.
+
+Common function arguments
+=========================
+
+Most functions in the MuPDF interface take an argument which is one of
+context, document, stream or device.
+
+A context contains global state used by MuPDF inside functions when
+parsing or rendering pages of the document. It contains e.g.:
+
+ an exception stack (see error handling below),
+
+ a memory allocator (allowing for custom allocators)
+
+ a resource store (for caching of images, fonts, etc.)
+
+The other arguments -- document, stream and device -- all contain a
+reference to the context, in order to not require context to be passed
+to sets of functions that need to take a common argument for parsing
+or rendering reasons.
+
+Error handling
+==============
+
+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.
+
+The basic formulation is as follows:
+
+ 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).
+ }
+
+The fz_always block is optional, and can safely be omitted.
+
+The macro based nature of this system has 3 main limitations:
+
+1) 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.
+
+2) The fz_try(ctx) { ... } fz_always(ctx) { ... } fz_catch(ctx) { ... }
+ is not one atomic C statement. That is to say, if you do:
+
+ if (condition)
+ fz_try(ctx) { ... }
+ fz_catch(ctx) { ... }
+
+ then you will not get what you want. Use the following instead:
+
+ if (condition) {
+ fz_try(ctx) { ... }
+ fz_catch(ctx) { ... }
+ }
+
+3) 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.
+
+ As a way of mitigating this problem, we provide an fz_var()
+ macro that tells the compiler to ensure that that variable is
+ not unset by the act of throwing the exception.
+
+A model piece of code using these macros then might be:
+
+ 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;
+ }
+
+Things to note about this:
+
+a) 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);
+
+b) 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.
+
+c) 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.
+
+d) We assume the standard C convention that it is safe to destroy
+ NULL things.
diff --git a/fitz/fitz.h b/fitz/fitz.h
index ddffa181..7a13ef75 100644
--- a/fitz/fitz.h
+++ b/fitz/fitz.h
@@ -139,134 +139,6 @@ struct fz_error_context_s
void fz_var_imp(void *);
#define fz_var(var) fz_var_imp((void *)&(var))
-/*
-
-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.
-
-The basic formulation is as follows:
-
- 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).
- }
-
-The fz_always block is optional, and can safely be omitted.
-
-The macro based nature of this system has 3 main limitations:
-
-1) 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.
-
-2) The fz_try(ctx) { ... } fz_always(ctx) { ... } fz_catch(ctx) { ... }
- is not one atomic C statement. That is to say, if you do:
-
- if (condition)
- fz_try(ctx) { ... }
- fz_catch(ctx) { ... }
-
- then you will not get what you want. Use the following instead:
-
- if (condition) {
- fz_try(ctx) { ... }
- fz_catch(ctx) { ... }
- }
-
-3) 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.
-
- As a way of mitigating this problem, we provide an fz_var() macro that
- tells the compiler to ensure that that variable is not unset by the
- act of throwing the exception.
-
-A model piece of code using these macros then might be:
-
- 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);
- h = combine(w, r); // Note, NOT: return 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;
- }
-
-Things to note about this:
-
-a) 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);
-
-b) 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.
-
-c) 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.
-
-d) We assume the standard C convention that it is safe to destroy
- NULL things.
-
-*/
-
/* Exception macro definitions. Just treat these as a black box - pay no
* attention to the man behind the curtain. */