1 | #include "fitz-imp.h" |
2 | |
3 | #include <assert.h> |
4 | #include <string.h> |
5 | #include <stdio.h> |
6 | #include <time.h> |
7 | |
8 | struct fz_style_context_s |
9 | { |
10 | int refs; |
11 | char *user_css; |
12 | int use_document_css; |
13 | }; |
14 | |
15 | static 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 | |
26 | static 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 | |
33 | static 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 | */ |
47 | void 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 | */ |
55 | int 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 | */ |
63 | void 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 | */ |
72 | const char *fz_user_css(fz_context *ctx) |
73 | { |
74 | return ctx->style->user_css; |
75 | } |
76 | |
77 | static 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 | |
88 | static 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 | |
95 | static 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 | */ |
113 | void 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 | */ |
127 | void 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 | |
133 | static 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 | */ |
156 | void |
157 | fz_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 | |
179 | static void |
180 | fz_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 | */ |
218 | fz_context * |
219 | fz_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 | */ |
289 | fz_context * |
290 | fz_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 | */ |
327 | void 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 | */ |
336 | void *fz_user_context(fz_context *ctx) |
337 | { |
338 | if (ctx == NULL) |
339 | return NULL; |
340 | |
341 | return ctx->user; |
342 | } |
343 | |