1#include "fitz-imp.h"
2
3#include <assert.h>
4#include <string.h>
5#include <stdio.h>
6#include <time.h>
7
8struct fz_style_context_s
9{
10 int refs;
11 char *user_css;
12 int use_document_css;
13};
14
15static void fz_new_style_context(fz_context *ctx)
16{
17 if (ctx)
18 {
19 ctx->style = fz_malloc_struct(ctx, fz_style_context);
20 ctx->style->refs = 1;
21 ctx->style->user_css = NULL;
22 ctx->style->use_document_css = 1;
23 }
24}
25
26static fz_style_context *fz_keep_style_context(fz_context *ctx)
27{
28 if (!ctx)
29 return NULL;
30 return fz_keep_imp(ctx, ctx->style, &ctx->style->refs);
31}
32
33static void fz_drop_style_context(fz_context *ctx)
34{
35 if (!ctx)
36 return;
37 if (fz_drop_imp(ctx, ctx->style, &ctx->style->refs))
38 {
39 fz_free(ctx, ctx->style->user_css);
40 fz_free(ctx, ctx->style);
41 }
42}
43
44/*
45 Toggle whether to respect document styles in HTML and EPUB.
46*/
47void fz_set_use_document_css(fz_context *ctx, int use)
48{
49 ctx->style->use_document_css = use;
50}
51
52/*
53 Return whether to respect document styles in HTML and EPUB.
54*/
55int fz_use_document_css(fz_context *ctx)
56{
57 return ctx->style->use_document_css;
58}
59
60/*
61 Set the user stylesheet source text for use with HTML and EPUB.
62*/
63void fz_set_user_css(fz_context *ctx, const char *user_css)
64{
65 fz_free(ctx, ctx->style->user_css);
66 ctx->style->user_css = user_css ? fz_strdup(ctx, user_css) : NULL;
67}
68
69/*
70 Get the user stylesheet source text.
71*/
72const char *fz_user_css(fz_context *ctx)
73{
74 return ctx->style->user_css;
75}
76
77static void fz_new_tuning_context(fz_context *ctx)
78{
79 if (ctx)
80 {
81 ctx->tuning = fz_malloc_struct(ctx, fz_tuning_context);
82 ctx->tuning->refs = 1;
83 ctx->tuning->image_decode = fz_default_image_decode;
84 ctx->tuning->image_scale = fz_default_image_scale;
85 }
86}
87
88static fz_tuning_context *fz_keep_tuning_context(fz_context *ctx)
89{
90 if (!ctx)
91 return NULL;
92 return fz_keep_imp(ctx, ctx->tuning, &ctx->tuning->refs);
93}
94
95static void fz_drop_tuning_context(fz_context *ctx)
96{
97 if (!ctx)
98 return;
99 if (fz_drop_imp(ctx, ctx->tuning, &ctx->tuning->refs))
100 {
101 fz_free(ctx, ctx->tuning);
102 }
103}
104
105/*
106 Set the tuning function to use for
107 image decode.
108
109 image_decode: Function to use.
110
111 arg: Opaque argument to be passed to tuning function.
112*/
113void fz_tune_image_decode(fz_context *ctx, fz_tune_image_decode_fn *image_decode, void *arg)
114{
115 ctx->tuning->image_decode = image_decode ? image_decode : fz_default_image_decode;
116 ctx->tuning->image_decode_arg = arg;
117}
118
119/*
120 Set the tuning function to use for
121 image scaling.
122
123 image_scale: Function to use.
124
125 arg: Opaque argument to be passed to tuning function.
126*/
127void fz_tune_image_scale(fz_context *ctx, fz_tune_image_scale_fn *image_scale, void *arg)
128{
129 ctx->tuning->image_scale = image_scale ? image_scale : fz_default_image_scale;
130 ctx->tuning->image_scale_arg = arg;
131}
132
133static void fz_init_random_context(fz_context *ctx)
134{
135 if (!ctx)
136 return;
137
138 ctx->seed48[0] = 0;
139 ctx->seed48[1] = 0;
140 ctx->seed48[2] = 0;
141 ctx->seed48[3] = 0xe66d;
142 ctx->seed48[4] = 0xdeec;
143 ctx->seed48[5] = 0x5;
144 ctx->seed48[6] = 0xb;
145
146 fz_srand48(ctx, (uint32_t)time(NULL));
147}
148
149/*
150 Free a context and its global state.
151
152 The context and all of its global state is freed, and any
153 buffered warnings are flushed (see fz_flush_warnings). If NULL
154 is passed in nothing will happen.
155*/
156void
157fz_drop_context(fz_context *ctx)
158{
159 if (!ctx)
160 return;
161
162 /* Other finalisation calls go here (in reverse order) */
163 fz_drop_document_handler_context(ctx);
164 fz_drop_glyph_cache_context(ctx);
165 fz_drop_store_context(ctx);
166 fz_drop_style_context(ctx);
167 fz_drop_tuning_context(ctx);
168 fz_drop_colorspace_context(ctx);
169 fz_drop_font_context(ctx);
170
171 fz_flush_warnings(ctx);
172
173 assert(ctx->error.top == ctx->error.stack);
174
175 /* Free the context itself */
176 ctx->alloc.free(ctx->alloc.user, ctx);
177}
178
179static void
180fz_init_error_context(fz_context *ctx)
181{
182 ctx->error.top = ctx->error.stack;
183 ctx->error.errcode = FZ_ERROR_NONE;
184 ctx->error.message[0] = 0;
185
186 ctx->warn.message[0] = 0;
187 ctx->warn.count = 0;
188}
189
190/*
191 Allocate context containing global state.
192
193 The global state contains an exception stack, resource store,
194 etc. Most functions in MuPDF take a context argument to be
195 able to reference the global state. See fz_drop_context for
196 freeing an allocated context.
197
198 alloc: Supply a custom memory allocator through a set of
199 function pointers. Set to NULL for the standard library
200 allocator. The context will keep the allocator pointer, so the
201 data it points to must not be modified or freed during the
202 lifetime of the context.
203
204 locks: Supply a set of locks and functions to lock/unlock
205 them, intended for multi-threaded applications. Set to NULL
206 when using MuPDF in a single-threaded applications. The
207 context will keep the locks pointer, so the data it points to
208 must not be modified or freed during the lifetime of the
209 context.
210
211 max_store: Maximum size in bytes of the resource store, before
212 it will start evicting cached resources such as fonts and
213 images. FZ_STORE_UNLIMITED can be used if a hard limit is not
214 desired. Use FZ_STORE_DEFAULT to get a reasonable size.
215
216 May return NULL.
217*/
218fz_context *
219fz_new_context_imp(const fz_alloc_context *alloc, const fz_locks_context *locks, size_t max_store, const char *version)
220{
221 fz_context *ctx;
222
223 if (strcmp(version, FZ_VERSION))
224 {
225 fprintf(stderr, "cannot create context: incompatible header (%s) and library (%s) versions\n", version, FZ_VERSION);
226 return NULL;
227 }
228
229 if (!alloc)
230 alloc = &fz_alloc_default;
231
232 if (!locks)
233 locks = &fz_locks_default;
234
235 ctx = alloc->malloc(alloc->user, sizeof(fz_context));
236 if (!ctx)
237 {
238 fprintf(stderr, "cannot create context (phase 1)\n");
239 return NULL;
240 }
241 memset(ctx, 0, sizeof *ctx);
242
243 ctx->user = NULL;
244 ctx->alloc = *alloc;
245 ctx->locks = *locks;
246
247 ctx->error.print = fz_default_error_callback;
248 ctx->warn.print = fz_default_warning_callback;
249
250 fz_init_error_context(ctx);
251 fz_init_aa_context(ctx);
252 fz_init_random_context(ctx);
253
254 /* Now initialise sections that are shared */
255 fz_try(ctx)
256 {
257 fz_new_store_context(ctx, max_store);
258 fz_new_glyph_cache_context(ctx);
259 fz_new_colorspace_context(ctx);
260 fz_new_font_context(ctx);
261 fz_new_document_handler_context(ctx);
262 fz_new_style_context(ctx);
263 fz_new_tuning_context(ctx);
264 }
265 fz_catch(ctx)
266 {
267 fprintf(stderr, "cannot create context (phase 2)\n");
268 fz_drop_context(ctx);
269 return NULL;
270 }
271 return ctx;
272}
273
274/*
275 Make a clone of an existing context.
276
277 This function is meant to be used in multi-threaded
278 applications where each thread requires its own context, yet
279 parts of the global state, for example caching, are shared.
280
281 ctx: Context obtained from fz_new_context to make a copy of.
282 ctx must have had locks and lock/functions setup when created.
283 The two contexts will share the memory allocator, resource
284 store, locks and lock/unlock functions. They will each have
285 their own exception stacks though.
286
287 May return NULL.
288*/
289fz_context *
290fz_clone_context(fz_context *ctx)
291{
292 fz_context *new_ctx;
293
294 /* We cannot safely clone the context without having locking/
295 * unlocking functions. */
296 if (ctx == NULL || (ctx->locks.lock == fz_locks_default.lock && ctx->locks.unlock == fz_locks_default.unlock))
297 return NULL;
298
299 new_ctx = ctx->alloc.malloc(ctx->alloc.user, sizeof(fz_context));
300 if (!new_ctx)
301 return NULL;
302
303 /* First copy old context, including pointers to shared contexts */
304 memcpy(new_ctx, ctx, sizeof (fz_context));
305
306 /* Reset error context to initial state. */
307 fz_init_error_context(new_ctx);
308
309 /* Then keep lock checking happy by keeping shared contexts with new context */
310 fz_keep_document_handler_context(new_ctx);
311 fz_keep_style_context(new_ctx);
312 fz_keep_tuning_context(new_ctx);
313 fz_keep_font_context(new_ctx);
314 fz_keep_colorspace_context(new_ctx);
315 fz_keep_store_context(new_ctx);
316 fz_keep_glyph_cache(new_ctx);
317
318 return new_ctx;
319}
320
321/*
322 Set the user field in the context.
323
324 NULL initially, this field can be set to any opaque value
325 required by the user. It is copied on clones.
326*/
327void fz_set_user_context(fz_context *ctx, void *user)
328{
329 if (ctx != NULL)
330 ctx->user = user;
331}
332
333/*
334 Read the user field from the context.
335*/
336void *fz_user_context(fz_context *ctx)
337{
338 if (ctx == NULL)
339 return NULL;
340
341 return ctx->user;
342}
343