343 lines
8.0 KiB
C
343 lines
8.0 KiB
C
|
#include "fitz-imp.h"
|
||
|
|
||
|
#include <assert.h>
|
||
|
#include <string.h>
|
||
|
#include <stdio.h>
|
||
|
#include <time.h>
|
||
|
|
||
|
struct fz_style_context_s
|
||
|
{
|
||
|
int refs;
|
||
|
char *user_css;
|
||
|
int use_document_css;
|
||
|
};
|
||
|
|
||
|
static void fz_new_style_context(fz_context *ctx)
|
||
|
{
|
||
|
if (ctx)
|
||
|
{
|
||
|
ctx->style = fz_malloc_struct(ctx, fz_style_context);
|
||
|
ctx->style->refs = 1;
|
||
|
ctx->style->user_css = NULL;
|
||
|
ctx->style->use_document_css = 1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static fz_style_context *fz_keep_style_context(fz_context *ctx)
|
||
|
{
|
||
|
if (!ctx)
|
||
|
return NULL;
|
||
|
return fz_keep_imp(ctx, ctx->style, &ctx->style->refs);
|
||
|
}
|
||
|
|
||
|
static void fz_drop_style_context(fz_context *ctx)
|
||
|
{
|
||
|
if (!ctx)
|
||
|
return;
|
||
|
if (fz_drop_imp(ctx, ctx->style, &ctx->style->refs))
|
||
|
{
|
||
|
fz_free(ctx, ctx->style->user_css);
|
||
|
fz_free(ctx, ctx->style);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
Toggle whether to respect document styles in HTML and EPUB.
|
||
|
*/
|
||
|
void fz_set_use_document_css(fz_context *ctx, int use)
|
||
|
{
|
||
|
ctx->style->use_document_css = use;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
Return whether to respect document styles in HTML and EPUB.
|
||
|
*/
|
||
|
int fz_use_document_css(fz_context *ctx)
|
||
|
{
|
||
|
return ctx->style->use_document_css;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
Set the user stylesheet source text for use with HTML and EPUB.
|
||
|
*/
|
||
|
void fz_set_user_css(fz_context *ctx, const char *user_css)
|
||
|
{
|
||
|
fz_free(ctx, ctx->style->user_css);
|
||
|
ctx->style->user_css = user_css ? fz_strdup(ctx, user_css) : NULL;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
Get the user stylesheet source text.
|
||
|
*/
|
||
|
const char *fz_user_css(fz_context *ctx)
|
||
|
{
|
||
|
return ctx->style->user_css;
|
||
|
}
|
||
|
|
||
|
static void fz_new_tuning_context(fz_context *ctx)
|
||
|
{
|
||
|
if (ctx)
|
||
|
{
|
||
|
ctx->tuning = fz_malloc_struct(ctx, fz_tuning_context);
|
||
|
ctx->tuning->refs = 1;
|
||
|
ctx->tuning->image_decode = fz_default_image_decode;
|
||
|
ctx->tuning->image_scale = fz_default_image_scale;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static fz_tuning_context *fz_keep_tuning_context(fz_context *ctx)
|
||
|
{
|
||
|
if (!ctx)
|
||
|
return NULL;
|
||
|
return fz_keep_imp(ctx, ctx->tuning, &ctx->tuning->refs);
|
||
|
}
|
||
|
|
||
|
static void fz_drop_tuning_context(fz_context *ctx)
|
||
|
{
|
||
|
if (!ctx)
|
||
|
return;
|
||
|
if (fz_drop_imp(ctx, ctx->tuning, &ctx->tuning->refs))
|
||
|
{
|
||
|
fz_free(ctx, ctx->tuning);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
Set the tuning function to use for
|
||
|
image decode.
|
||
|
|
||
|
image_decode: Function to use.
|
||
|
|
||
|
arg: Opaque argument to be passed to tuning function.
|
||
|
*/
|
||
|
void fz_tune_image_decode(fz_context *ctx, fz_tune_image_decode_fn *image_decode, void *arg)
|
||
|
{
|
||
|
ctx->tuning->image_decode = image_decode ? image_decode : fz_default_image_decode;
|
||
|
ctx->tuning->image_decode_arg = arg;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
Set the tuning function to use for
|
||
|
image scaling.
|
||
|
|
||
|
image_scale: Function to use.
|
||
|
|
||
|
arg: Opaque argument to be passed to tuning function.
|
||
|
*/
|
||
|
void fz_tune_image_scale(fz_context *ctx, fz_tune_image_scale_fn *image_scale, void *arg)
|
||
|
{
|
||
|
ctx->tuning->image_scale = image_scale ? image_scale : fz_default_image_scale;
|
||
|
ctx->tuning->image_scale_arg = arg;
|
||
|
}
|
||
|
|
||
|
static void fz_init_random_context(fz_context *ctx)
|
||
|
{
|
||
|
if (!ctx)
|
||
|
return;
|
||
|
|
||
|
ctx->seed48[0] = 0;
|
||
|
ctx->seed48[1] = 0;
|
||
|
ctx->seed48[2] = 0;
|
||
|
ctx->seed48[3] = 0xe66d;
|
||
|
ctx->seed48[4] = 0xdeec;
|
||
|
ctx->seed48[5] = 0x5;
|
||
|
ctx->seed48[6] = 0xb;
|
||
|
|
||
|
fz_srand48(ctx, (uint32_t)time(NULL));
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
Free a context and its global state.
|
||
|
|
||
|
The context and all of its global state is freed, and any
|
||
|
buffered warnings are flushed (see fz_flush_warnings). If NULL
|
||
|
is passed in nothing will happen.
|
||
|
*/
|
||
|
void
|
||
|
fz_drop_context(fz_context *ctx)
|
||
|
{
|
||
|
if (!ctx)
|
||
|
return;
|
||
|
|
||
|
/* Other finalisation calls go here (in reverse order) */
|
||
|
fz_drop_document_handler_context(ctx);
|
||
|
fz_drop_glyph_cache_context(ctx);
|
||
|
fz_drop_store_context(ctx);
|
||
|
fz_drop_style_context(ctx);
|
||
|
fz_drop_tuning_context(ctx);
|
||
|
fz_drop_colorspace_context(ctx);
|
||
|
fz_drop_font_context(ctx);
|
||
|
|
||
|
fz_flush_warnings(ctx);
|
||
|
|
||
|
assert(ctx->error.top == ctx->error.stack);
|
||
|
|
||
|
/* Free the context itself */
|
||
|
ctx->alloc.free(ctx->alloc.user, ctx);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
fz_init_error_context(fz_context *ctx)
|
||
|
{
|
||
|
ctx->error.top = ctx->error.stack;
|
||
|
ctx->error.errcode = FZ_ERROR_NONE;
|
||
|
ctx->error.message[0] = 0;
|
||
|
|
||
|
ctx->warn.message[0] = 0;
|
||
|
ctx->warn.count = 0;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
Allocate context containing global state.
|
||
|
|
||
|
The global state contains an exception stack, resource store,
|
||
|
etc. Most functions in MuPDF take a context argument to be
|
||
|
able to reference the global state. See fz_drop_context for
|
||
|
freeing an allocated context.
|
||
|
|
||
|
alloc: Supply a custom memory allocator through a set of
|
||
|
function pointers. Set to NULL for the standard library
|
||
|
allocator. The context will keep the allocator pointer, so the
|
||
|
data it points to must not be modified or freed during the
|
||
|
lifetime of the context.
|
||
|
|
||
|
locks: Supply a set of locks and functions to lock/unlock
|
||
|
them, intended for multi-threaded applications. Set to NULL
|
||
|
when using MuPDF in a single-threaded applications. The
|
||
|
context will keep the locks pointer, so the data it points to
|
||
|
must not be modified or freed during the lifetime of the
|
||
|
context.
|
||
|
|
||
|
max_store: Maximum size in bytes of the resource store, before
|
||
|
it will start evicting cached resources such as fonts and
|
||
|
images. FZ_STORE_UNLIMITED can be used if a hard limit is not
|
||
|
desired. Use FZ_STORE_DEFAULT to get a reasonable size.
|
||
|
|
||
|
May return NULL.
|
||
|
*/
|
||
|
fz_context *
|
||
|
fz_new_context_imp(const fz_alloc_context *alloc, const fz_locks_context *locks, size_t max_store, const char *version)
|
||
|
{
|
||
|
fz_context *ctx;
|
||
|
|
||
|
if (strcmp(version, FZ_VERSION))
|
||
|
{
|
||
|
fprintf(stderr, "cannot create context: incompatible header (%s) and library (%s) versions\n", version, FZ_VERSION);
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
if (!alloc)
|
||
|
alloc = &fz_alloc_default;
|
||
|
|
||
|
if (!locks)
|
||
|
locks = &fz_locks_default;
|
||
|
|
||
|
ctx = Memento_label(alloc->malloc(alloc->user, sizeof(fz_context)), "fz_context");
|
||
|
if (!ctx)
|
||
|
{
|
||
|
fprintf(stderr, "cannot create context (phase 1)\n");
|
||
|
return NULL;
|
||
|
}
|
||
|
memset(ctx, 0, sizeof *ctx);
|
||
|
|
||
|
ctx->user = NULL;
|
||
|
ctx->alloc = *alloc;
|
||
|
ctx->locks = *locks;
|
||
|
|
||
|
ctx->error.print = fz_default_error_callback;
|
||
|
ctx->warn.print = fz_default_warning_callback;
|
||
|
|
||
|
fz_init_error_context(ctx);
|
||
|
fz_init_aa_context(ctx);
|
||
|
fz_init_random_context(ctx);
|
||
|
|
||
|
/* Now initialise sections that are shared */
|
||
|
fz_try(ctx)
|
||
|
{
|
||
|
fz_new_store_context(ctx, max_store);
|
||
|
fz_new_glyph_cache_context(ctx);
|
||
|
fz_new_colorspace_context(ctx);
|
||
|
fz_new_font_context(ctx);
|
||
|
fz_new_document_handler_context(ctx);
|
||
|
fz_new_style_context(ctx);
|
||
|
fz_new_tuning_context(ctx);
|
||
|
}
|
||
|
fz_catch(ctx)
|
||
|
{
|
||
|
fprintf(stderr, "cannot create context (phase 2)\n");
|
||
|
fz_drop_context(ctx);
|
||
|
return NULL;
|
||
|
}
|
||
|
return ctx;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
Make a clone of an existing context.
|
||
|
|
||
|
This function is meant to be used in multi-threaded
|
||
|
applications where each thread requires its own context, yet
|
||
|
parts of the global state, for example caching, are shared.
|
||
|
|
||
|
ctx: Context obtained from fz_new_context to make a copy of.
|
||
|
ctx must have had locks and lock/functions setup when created.
|
||
|
The two contexts will share the memory allocator, resource
|
||
|
store, locks and lock/unlock functions. They will each have
|
||
|
their own exception stacks though.
|
||
|
|
||
|
May return NULL.
|
||
|
*/
|
||
|
fz_context *
|
||
|
fz_clone_context(fz_context *ctx)
|
||
|
{
|
||
|
fz_context *new_ctx;
|
||
|
|
||
|
/* We cannot safely clone the context without having locking/
|
||
|
* unlocking functions. */
|
||
|
if (ctx == NULL || (ctx->locks.lock == fz_locks_default.lock && ctx->locks.unlock == fz_locks_default.unlock))
|
||
|
return NULL;
|
||
|
|
||
|
new_ctx = ctx->alloc.malloc(ctx->alloc.user, sizeof(fz_context));
|
||
|
if (!new_ctx)
|
||
|
return NULL;
|
||
|
|
||
|
/* First copy old context, including pointers to shared contexts */
|
||
|
memcpy(new_ctx, ctx, sizeof (fz_context));
|
||
|
|
||
|
/* Reset error context to initial state. */
|
||
|
fz_init_error_context(new_ctx);
|
||
|
|
||
|
/* Then keep lock checking happy by keeping shared contexts with new context */
|
||
|
fz_keep_document_handler_context(new_ctx);
|
||
|
fz_keep_style_context(new_ctx);
|
||
|
fz_keep_tuning_context(new_ctx);
|
||
|
fz_keep_font_context(new_ctx);
|
||
|
fz_keep_colorspace_context(new_ctx);
|
||
|
fz_keep_store_context(new_ctx);
|
||
|
fz_keep_glyph_cache(new_ctx);
|
||
|
|
||
|
return new_ctx;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
Set the user field in the context.
|
||
|
|
||
|
NULL initially, this field can be set to any opaque value
|
||
|
required by the user. It is copied on clones.
|
||
|
*/
|
||
|
void fz_set_user_context(fz_context *ctx, void *user)
|
||
|
{
|
||
|
if (ctx != NULL)
|
||
|
ctx->user = user;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
Read the user field from the context.
|
||
|
*/
|
||
|
void *fz_user_context(fz_context *ctx)
|
||
|
{
|
||
|
if (ctx == NULL)
|
||
|
return NULL;
|
||
|
|
||
|
return ctx->user;
|
||
|
}
|