Age | Commit message (Collapse) | Author |
|
This is a significant change to the use of locks in MuPDF.
Previously, the user had the option of passing us lock/unlock
functions for a single mutex as part of the allocation struct.
Now we remove these entries from the allocation struct, and
make a separate 'locks' struct. This enables people to use
fz_alloc_default with locking.
If multithreaded operation is required, then the user is
required to create FZ_LOCK_MAX mutexes, which will be locked
or unlocked by MuPDF calling the lock/unlock functions within
the new fz_locks_context structure passed in at context creation.
These mutexes are not required to be recursive (they may be, but
MuPDF should never call them in this way). MuPDF avoids deadlocks
by imposing a locking ordering on itself; a thread will never take
lock n, if it already holds any lock i for which 0 <= i <= n.
Currently, there are 4 locks used within MuPDF.
Lock 0: The alloc lock; taken around all calls to user supplied
(or default) allocation functions. Also taken around all accesses
to the refs field of storable items.
Lock 1: The store lock; taken whenever the store data structures
(specifically the linked list pointers) are accessed.
Lock 2: The file lock; taken whenever a thread is accessing the raw
file. We use the debugging macros to insist that this is held
whenever we do a file based seek or read. We also insist that this
is never held when we resolve an indirect reference, as this can
have the effect of moving the file pointer.
Lock 3: The glyphcache lock; taken whenever a thread calls freetype,
or accesses the glyphcache data structures. This introduces some
complexities w.r.t type3 fonts.
Locking can be hugely problematic, so to ease our minds as to
the correctness of this code, we introduce some debugging macros.
These compile away to nothing unless FITZ_DEBUG_LOCKING is defined.
fz_assert_lock_held(ctx, lock) checks that we hold lock.
fz_assert_lock_not_held(ctx, lock) checks that we do not hold lock.
In addition fz_lock_debug_lock and fz_lock_debug_unlock are used
on every fz_lock/fz_unlock to check the validity of the operation
we are performing - in particular it checks that we do/do not already
hold the lock we are trying to take/drop, and that by taking this
lock we are not violating our defined locking order.
The RESOLVE macro (used throughout the code to check whether we need
to resolve an indirect reference) calls fz_assert_lock_not_held to
ensure that we aren't about to resolve an indirect reference (and
hence move the stream pointer) when the file is locked.
In order to implement the file locking properly, pdf_open_stream
(and friends) now lock the file as a side effect (because they
fz_seek to the start of the stream). The lock is automatically
dropped on an fz_close of such streams.
Previously, the glyph cache was created in a context when it was first
required; this presents problems as it can be shared between several
contexts or not, depending on whether it is created before the
contexts are cloned. We now always create it at startup, so it is
always shared.
This means that we need reference counting for the glyph caches.
Added here.
In fz_render_glyph, we take the glyph cache lock, and check to see
whether the glyph is in the cache. If it is, we bump the refcount,
drop the lock and returned the cached character. If it is not, we
need to render the character.
For freetype based fonts we keep the lock throughout the rendering
process, thus ensuring that freetype is only called in a single
threaded manner.
For type3 fonts, however, we need to invoke the interpreter again
to render the glyph streams. This can require reentrance to this
routine. We therefore drop the glyph cache lock, call the
interpreter to render us our pixmap, and take the lock again.
This dropping and retaking of the lock introduces a possible race
condition; 2 threads may try to render the same character at the
same time. We therefore modify our hash table insert routines to
behave differently if it comes to insert an entry only to find
that an entry with the same key is already there.
We spot this case; if we have just rendered a type3 glyph and when
we try to insert it into the cache discover that someone has beaten
us to it, we just discard our entry and use the cached one.
Hopefully this will seldom be a problem in practise; to solve it
properly would require greater complexity (probably involving
spotting that another thread is already working on the desired
rendering, and sleeping on a semaphore until it completes).
|
|
|
|
|
|
|
|
More aesthetically pleasing version.
|
|
Word space should only be applied when the codepoint is 32, and
is read from a single byte encoding region. Ghostscript gets
this wrong too.
|
|
|
|
This way both pixmaps for rendering and image data are top-down.
|
|
|
|
When we moved over to a context based system, we laid the foundation
for a thread-safe mupdf. This commit should complete that process.
Firstly, fz_clone_context is properly implemented so that it
makes a new context, but shares certain sections (currently
just the allocator, and the store).
Secondly, we add locking (to parts of the code that have
previously just had placeholder LOCK/UNLOCK comments). Functions
to lock and unlock a mutex are added to the allocator structure;
omit these (as is the case today) and no multithreading is
(safely) possible. The context will refuse to clone if these are
not provided.
Finally we flesh out the LOCK/UNLOCK comments to be real calls of
the functions - unfortunately this requires us to plumb fz_context
into the fz_keep_storable function (and all the fz_keep_xxx
functions that call it). This is the largest section of the patch.
No changes expected to any test files.
|
|
Some Type 3 fonts contain glyphs that rely on inheriting various
aspects of the graphics state from their calling code. (i.e. a
glyph might use d0, then fill an area without setting a color
first).
While the spec is vague on this point, we believe that technically
it is invalid. Previously mupdf defaulted all elements of the graphic
state back when beginning to draw the glyph. This does not match
what Acrobat does though, so we change the approach taken.
We now watch (by use of bits in the device flags word) for the use
of parts of the graphics state before it is set. If such use is
detected, then we note that the glyph is 'uncacheable' and render
it direct.
This seems to match Acrobats behaviour.
|
|
Every xobject keeps a reference to the object from whence
it came. This is marked/unmarked as it is executed.
Thanks to Zeniko for spotting the potential problem.
|
|
Copes with files with many many gstates in; such as 'tikz-gtree'
documents, according to Sumatra.
Thanks to Zeniko for this.
|
|
XPS differs from PS/PDF/etc in the way it handles miters; rather than
simply converting a miter that's overly long to a bevel, it truncates
it at the miter limit. As such it needs to be handled correctly.
For clarity, expose new enumerated types for linejoins and linecaps,
and use these throughout code.
When we upgrade our freetype, we can move to using proper xps mitering
in that too.
Add new fz_matrix_max_expansion function to return a safer expansion
value that works in the case where we scale up in one direction and
down in another.
In the xps path drawing code, avoid generating unnecessary linetos.
Thanks to Zeniko for spotting these and providing implementations.
|
|
Move coordinate space tweaks into pdf_ and xps_run_page, and provide
neutral pdf_ and xps_bound_page functions to return the page size as
a zero-origined bounding box.
|
|
|
|
Fix 2 places where we were filling a stroked pattern rather than
stroking it.
Cope with being asked to run a NULL buffer.
If running a stream fails, warn and return what we have, rather than
giving up entirely. Should really set a return code for each render.
Only look at the Print flag bit for Print renders. Only look at the
View flag bit for view renders.
If we find an unexpected ) or > during object parsing, warn and continue
rather than giving up entirely.
If optional content groups are broken, render the rest of the page
anyway.
Previously indirect objects that point to another indirection would
cause a failure; now attempt to resolve these. We set an arbitrary
limit of 10 such redirections to avoid infinite loops.
|
|
A new 'cookie' parameter is added to page rendering/interpretation
functions. Supply this as NULL to get existing behaviour.
If you supply a non-NULL cookie, then this is taken as a pointer to
a struct that can be used for simple, non-thread locked communication
between caller and library.
The entire struct should be memset to zero before entry, except for
specific flags (thus coping with future extensions to this struct).
The abort flag should be zero on entry. It will be checked periodically
by the library - if the caller sets it non-zero (via another thread)
then the current operation will be aborted. No guarantees are given as
to how often this will be checked, or how fast it will be responded to.
The progress_max field will be set to an integer (-1 for unknown)
representing the number of 'things' to do. The progress field will
count up from 0 to this number as time goes by. No guarantees are
made as to the accuracy of this information, but it should be
useful for offering some sort of progress bar etc. Note that
progress_max may increase during the job.
In general, callers should be careful to accept out of range or
invalid data in this structure as this is deliberately
accessed 'unlocked'.
|
|
|
|
Rather than passing a stream to a close function, just pass context
and state - that's all that is required. This enables us to
call close to cleanup neatly if the stream fails to allocate.
|
|
|
|
|
|
|
|
The new fz_malloc_struct(A,B) macro allocates sizeof(B) bytes using
fz_malloc, and then passes the resultant pointer to Memento_label
to label it with "B".
This costs nothing in non-memento builds, but gives much nicer
listings of leaked blocks when memento is enabled.
|
|
Also: use 'cannot' instead of 'failed to' in error messages.
|
|
When using exceptions (which are implemented using setjmp/longjmp), we
need to be careful to ensure that variable values get written back
before any exception happens.
Previously we've done that using volatile, but that produces nasty
warnings (and unduly limits the compilers freedom to optimise). Here
we introduce a new macro fz_var that passes the address of the variable
out of scope. This means that the compiler has to ensure that any
changes to its value are written back to memory before calling any
out of scope function.
|
|
The code attempts to spot cases where a pattern tile is so large that
only 1 repeat is visible. Due to rounding errors, this test could
sometimes fail, and (on badly formed files) we'd attempt to allocate
huge pixmaps.
The fix is to allow for rounding errors.
|
|
|
|
When opening a file, create a pdf_ocg_descriptor that lists the OCGs
in a file. Add a new function to allow us to set the configuration
in use (currently just the default one).
This sets the states of the OCGs as appropriate. When decoding the
file respect the states of the OCGs.
This results in Invite.pdf rendering correctly.
There is more to be done in this area (with automatic setting of
OCGs by language/zoom level etc), but this is a good start.
|
|
Once we've applied the clipping path, don't clip again on every
subsequent path.
|
|
When reverting the clip path handling, I made a mistake. We need to
set up the clip before starting any local group to ensure correct
nesting.
|
|
When reverting the clip path handling, I made a mistake. We need to
set up the clip before starting any local group to ensure correct
nesting.
|
|
Mostly redoing the xps_context to xps_document change and adding
contexts to newly written code.
Conflicts:
apps/pdfapp.c
apps/pdfapp.h
apps/x11_main.c
apps/xpsdraw.c
draw/draw_device.c
draw/draw_scale.c
fitz/base_object.c
fitz/fitz.h
pdf/mupdf.h
pdf/pdf_interpret.c
pdf/pdf_outline.c
pdf/pdf_page.c
xps/muxps.h
xps/xps_doc.c
xps/xps_xml.c
|
|
In commit 2f8acb0, we tweaked mupdf's clip path handling so that
clip paths were resolved as soon as the operator for them was
called; this protected against subsequent changes to the path
happening before something else was drawn ready for clipping.
Unfortunately, various PDF files out there seem to rely on the
fact that they can call the 'W' operator before fully defining
the path, and that the region that will be clipped is given by
the final path, not the one that was in place when the operator
was called.
We therefore revert back to the old behaviour.
|
|
This frees us from passing errors back everywhere, and hence enables us
to pass results back as return values.
Rather than having to explicitly check for errors everywhere and bubble
them, we now allow exception handling to do the work for us; the
downside to this is that we no longer emit as much debugging information
as we did before (though this could be put back in). For now, the
debugging information we have lost has been retained in comments
with 'RJW:' at the start.
This code needs fuller testing, but is being committed as a work in
progress.
|
|
|
|
|
|
Huge pervasive change to lots of files, adding a context for exception
handling and allocation.
In time we'll move more statics into there.
Also fix some for(i = 0; i < function(...); i++) calls.
|
|
Import exception handling code from WSS, modified to fit into the
fitz world.
With this code we have 'real' fz_try/fz_catch/fz_rethrow functions,
handling a fz_except type. We therefore rename the existing fz_throw/
fz_catch/fz_rethrow to be fz_error_make/fz_error_handle/fz_error_note.
We don't actually use fz_try/fz_catch/fz_rethrow yet...
|
|
|
|
|
|
|
|
|
|
Make sure the CSI works from a clean slate in pdf_run_stream, since it
may be called to draw a softmask form pdf_flush_text in the middle of
parsing a TJ text array.
Also guard against xobject failures by catching instead of rethrowing
xobject parse errors so that the begin and end group draw calls are
balanced.
|
|
|
|
Fix bug 692282.
|
|
Detect the d0 or d1 operators by writing a bit to the new device
flags word. This can then be checked by the Type3 code to create
the appropriate backing pixmap.
In order to know what the appropriate backing pixmap is, we pass
an additional colorspace into the glyph rendering code.
|
|
Firstly, this takes on some of Zenikos patch to correct the clip
stack handling that was broken by the fix to bug 692287 (in commit
2c3bbbf). This bug should now be solved.
We add a new 'shape' field to the draw device structure (and clip
stack). When we are inside non-isolated groups, this is set to be
a pixmap where we accumulate the 'shape' of the objects drawn.
When we come to blend back, if we are blending a non-isolated group
back, we have to use a different blending function that takes account
of the shape.
Various internal groups (the page group, and groups used to force
blending) are set to be isolated to avoid carrying shape planes
around when this is not required.
All our rendering code now has to know how to maintain the shape
plane as well as doing the basic rendering.
|
|
First, we add clipping rects to clipping functions. Various functions
(the ones that handle clipping) are now additionally passed a rectangle
that represents an additional bound for this clip in device space
(i.e. it has already been mapped through the current ctm).
Next, when constructing the displaylist, keep track of the bounding box
for the contents of each clip.
While writing the list, on every node we add, we add the bbox for that
node to the enclosing clips content bbox (if there is an enclosing clip).
When we pop a clip, write back to the corresponding push to update
the bbox.
This means if we get large clip regions, with only small areas used within
them, we will only do the slow blending for those small areas.
Finally, we fix a calculation in fz_bound_path which was incorrectly
accounting for mitrelimits. This was showing up in testing on page 630
of the PDF reference v1.7.
|
|
In the existing mupdf clip path code, it would be possible for us to
render incorrectly; consider the following fragment of a content
stream:
0 0 100 100 re
W
50 50 100 100 re
f
That should set the clip path to the (0, 0) -> (100, 100) rectangle,
and then attempt to fill both the (0,0) -> (100,100) rectangle and the
(50,50) -> (150,150) rectangle, resulting in just the (0,0) -> (100,100)
rectangle being filled.
In the existing mupdf code, it would actually fill both rectangles as
the path after the W operation (the addition of the second rectangle)
would also affect the stored clip path.
We solve this by doing the clip operation on the W operator, rather than
deferred to when the path is actually disposed of.
|