Mercurial > hgrepos > Python2 > PyMuPDF
comparison mupdf-source/source/fitz/context.c @ 2:b50eed0cc0ef upstream
ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4.
The directory name has changed: no version number in the expanded directory now.
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Mon, 15 Sep 2025 11:43:07 +0200 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 1:1d09e1dec1d9 | 2:b50eed0cc0ef |
|---|---|
| 1 // Copyright (C) 2004-2025 Artifex Software, Inc. | |
| 2 // | |
| 3 // This file is part of MuPDF. | |
| 4 // | |
| 5 // MuPDF is free software: you can redistribute it and/or modify it under the | |
| 6 // terms of the GNU Affero General Public License as published by the Free | |
| 7 // Software Foundation, either version 3 of the License, or (at your option) | |
| 8 // any later version. | |
| 9 // | |
| 10 // MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY | |
| 11 // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | |
| 12 // FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more | |
| 13 // details. | |
| 14 // | |
| 15 // You should have received a copy of the GNU Affero General Public License | |
| 16 // along with MuPDF. If not, see <https://www.gnu.org/licenses/agpl-3.0.en.html> | |
| 17 // | |
| 18 // Alternative licensing terms are available from the licensor. | |
| 19 // For commercial licensing, see <https://www.artifex.com/> or contact | |
| 20 // Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, | |
| 21 // CA 94129, USA, for further information. | |
| 22 | |
| 23 #include "mupdf/fitz.h" | |
| 24 | |
| 25 #include "context-imp.h" | |
| 26 | |
| 27 #include <assert.h> | |
| 28 #include <string.h> | |
| 29 #include <stdio.h> | |
| 30 #include <time.h> | |
| 31 | |
| 32 struct fz_style_context | |
| 33 { | |
| 34 int refs; | |
| 35 char *user_css; | |
| 36 int use_document_css; | |
| 37 }; | |
| 38 | |
| 39 static void fz_new_style_context(fz_context *ctx) | |
| 40 { | |
| 41 if (ctx) | |
| 42 { | |
| 43 ctx->style = fz_malloc_struct(ctx, fz_style_context); | |
| 44 ctx->style->refs = 1; | |
| 45 ctx->style->user_css = NULL; | |
| 46 ctx->style->use_document_css = 1; | |
| 47 } | |
| 48 } | |
| 49 | |
| 50 static fz_style_context *fz_keep_style_context(fz_context *ctx) | |
| 51 { | |
| 52 if (!ctx) | |
| 53 return NULL; | |
| 54 return fz_keep_imp(ctx, ctx->style, &ctx->style->refs); | |
| 55 } | |
| 56 | |
| 57 static void fz_drop_style_context(fz_context *ctx) | |
| 58 { | |
| 59 if (!ctx) | |
| 60 return; | |
| 61 if (fz_drop_imp(ctx, ctx->style, &ctx->style->refs)) | |
| 62 { | |
| 63 fz_free(ctx, ctx->style->user_css); | |
| 64 fz_free(ctx, ctx->style); | |
| 65 } | |
| 66 } | |
| 67 | |
| 68 void fz_set_use_document_css(fz_context *ctx, int use) | |
| 69 { | |
| 70 ctx->style->use_document_css = use; | |
| 71 } | |
| 72 | |
| 73 int fz_use_document_css(fz_context *ctx) | |
| 74 { | |
| 75 return ctx->style->use_document_css; | |
| 76 } | |
| 77 | |
| 78 void fz_set_user_css(fz_context *ctx, const char *user_css) | |
| 79 { | |
| 80 fz_free(ctx, ctx->style->user_css); | |
| 81 ctx->style->user_css = user_css ? fz_strdup(ctx, user_css) : NULL; | |
| 82 } | |
| 83 | |
| 84 const char *fz_user_css(fz_context *ctx) | |
| 85 { | |
| 86 return ctx->style->user_css; | |
| 87 } | |
| 88 | |
| 89 void fz_load_user_css(fz_context *ctx, const char *filename) | |
| 90 { | |
| 91 fz_buffer *buf = NULL; | |
| 92 fz_var(buf); | |
| 93 fz_try(ctx) | |
| 94 { | |
| 95 buf = fz_read_file(ctx, filename); | |
| 96 fz_set_user_css(ctx, fz_string_from_buffer(ctx, buf)); | |
| 97 } | |
| 98 fz_always(ctx) | |
| 99 { | |
| 100 fz_drop_buffer(ctx, buf); | |
| 101 } | |
| 102 fz_catch(ctx) | |
| 103 { | |
| 104 fz_report_error(ctx); | |
| 105 fz_warn(ctx, "cannot read user css file"); | |
| 106 } | |
| 107 } | |
| 108 | |
| 109 static void fz_new_tuning_context(fz_context *ctx) | |
| 110 { | |
| 111 if (ctx) | |
| 112 { | |
| 113 ctx->tuning = fz_malloc_struct(ctx, fz_tuning_context); | |
| 114 ctx->tuning->refs = 1; | |
| 115 ctx->tuning->image_decode = fz_default_image_decode; | |
| 116 ctx->tuning->image_scale = fz_default_image_scale; | |
| 117 } | |
| 118 } | |
| 119 | |
| 120 static fz_tuning_context *fz_keep_tuning_context(fz_context *ctx) | |
| 121 { | |
| 122 if (!ctx) | |
| 123 return NULL; | |
| 124 return fz_keep_imp(ctx, ctx->tuning, &ctx->tuning->refs); | |
| 125 } | |
| 126 | |
| 127 static void fz_drop_tuning_context(fz_context *ctx) | |
| 128 { | |
| 129 if (!ctx) | |
| 130 return; | |
| 131 if (fz_drop_imp(ctx, ctx->tuning, &ctx->tuning->refs)) | |
| 132 { | |
| 133 fz_free(ctx, ctx->tuning); | |
| 134 } | |
| 135 } | |
| 136 | |
| 137 void fz_tune_image_decode(fz_context *ctx, fz_tune_image_decode_fn *image_decode, void *arg) | |
| 138 { | |
| 139 ctx->tuning->image_decode = image_decode ? image_decode : fz_default_image_decode; | |
| 140 ctx->tuning->image_decode_arg = arg; | |
| 141 } | |
| 142 | |
| 143 void fz_tune_image_scale(fz_context *ctx, fz_tune_image_scale_fn *image_scale, void *arg) | |
| 144 { | |
| 145 ctx->tuning->image_scale = image_scale ? image_scale : fz_default_image_scale; | |
| 146 ctx->tuning->image_scale_arg = arg; | |
| 147 } | |
| 148 | |
| 149 static void fz_init_random_context(fz_context *ctx) | |
| 150 { | |
| 151 if (!ctx) | |
| 152 return; | |
| 153 | |
| 154 ctx->seed48[0] = 0; | |
| 155 ctx->seed48[1] = 0; | |
| 156 ctx->seed48[2] = 0; | |
| 157 ctx->seed48[3] = 0xe66d; | |
| 158 ctx->seed48[4] = 0xdeec; | |
| 159 ctx->seed48[5] = 0x5; | |
| 160 ctx->seed48[6] = 0xb; | |
| 161 | |
| 162 fz_srand48(ctx, (uint32_t)time(NULL)); | |
| 163 } | |
| 164 | |
| 165 void | |
| 166 fz_drop_context(fz_context *ctx) | |
| 167 { | |
| 168 int free_master = 0; | |
| 169 int call_log = 0; | |
| 170 | |
| 171 if (!ctx) | |
| 172 return; | |
| 173 | |
| 174 if (ctx->error.errcode) | |
| 175 { | |
| 176 fz_flush_warnings(ctx); | |
| 177 fz_warn(ctx, "UNHANDLED EXCEPTION!"); | |
| 178 fz_report_error(ctx); | |
| 179 #ifdef CLUSTER | |
| 180 abort(); | |
| 181 #endif | |
| 182 } | |
| 183 | |
| 184 | |
| 185 assert(ctx->master); | |
| 186 fz_lock(ctx, FZ_LOCK_ALLOC); | |
| 187 ctx->master->context_count--; | |
| 188 if (ctx->master->context_count == 0) | |
| 189 { | |
| 190 call_log = 1; | |
| 191 if (ctx->master != ctx) | |
| 192 free_master = 1; | |
| 193 } | |
| 194 fz_unlock(ctx, FZ_LOCK_ALLOC); | |
| 195 | |
| 196 /* We call the log with ctx intact, apart from the master | |
| 197 * pointer having had the context_count reduced. The | |
| 198 * only possible problem here is if fz_log_activity | |
| 199 * clones the context, but it really shouldn't be doing | |
| 200 * that! */ | |
| 201 if (call_log) | |
| 202 fz_log_activity(ctx, FZ_ACTIVITY_SHUTDOWN, NULL); | |
| 203 if (free_master) | |
| 204 ctx->alloc.free(ctx->alloc.user, ctx->master); | |
| 205 | |
| 206 /* Other finalisation calls go here (in reverse order) */ | |
| 207 fz_drop_document_handler_context(ctx); | |
| 208 fz_drop_archive_handler_context(ctx); | |
| 209 fz_drop_glyph_cache_context(ctx); | |
| 210 fz_drop_store_context(ctx); | |
| 211 fz_drop_style_context(ctx); | |
| 212 fz_drop_tuning_context(ctx); | |
| 213 fz_drop_colorspace_context(ctx); | |
| 214 fz_drop_font_context(ctx); | |
| 215 | |
| 216 fz_flush_warnings(ctx); | |
| 217 | |
| 218 assert(ctx->error.top == ctx->error.stack_base); | |
| 219 | |
| 220 /* Free the context itself */ | |
| 221 if (ctx->master == ctx && ctx->context_count != 0) | |
| 222 { | |
| 223 /* Need to delay our freeing until all our children have died. */ | |
| 224 ctx->master = NULL; | |
| 225 } | |
| 226 else | |
| 227 { | |
| 228 ctx->alloc.free(ctx->alloc.user, ctx); | |
| 229 } | |
| 230 } | |
| 231 | |
| 232 static void | |
| 233 fz_init_error_context(fz_context *ctx) | |
| 234 { | |
| 235 #define ALIGN(addr, align) ((((intptr_t)(addr)) + (align-1)) & ~(align-1)) | |
| 236 ctx->error.stack_base = (fz_error_stack_slot *)ALIGN(ctx->error.stack, FZ_JMPBUF_ALIGN); | |
| 237 ctx->error.top = ctx->error.stack_base; | |
| 238 ctx->error.errcode = FZ_ERROR_NONE; | |
| 239 ctx->error.message[0] = 0; | |
| 240 | |
| 241 ctx->warn.message[0] = 0; | |
| 242 ctx->warn.count = 0; | |
| 243 } | |
| 244 | |
| 245 fz_context * | |
| 246 fz_new_context_imp(const fz_alloc_context *alloc, const fz_locks_context *locks, size_t max_store, const char *version) | |
| 247 { | |
| 248 fz_context *ctx; | |
| 249 | |
| 250 if (strcmp(version, FZ_VERSION)) | |
| 251 { | |
| 252 fprintf(stderr, "cannot create context: incompatible header (%s) and library (%s) versions\n", version, FZ_VERSION); | |
| 253 return NULL; | |
| 254 } | |
| 255 | |
| 256 if (!alloc) | |
| 257 alloc = &fz_alloc_default; | |
| 258 | |
| 259 if (!locks) | |
| 260 locks = &fz_locks_default; | |
| 261 | |
| 262 ctx = Memento_label(alloc->malloc(alloc->user, sizeof(fz_context)), "fz_context"); | |
| 263 if (!ctx) | |
| 264 { | |
| 265 fprintf(stderr, "cannot create context (phase 1)\n"); | |
| 266 return NULL; | |
| 267 } | |
| 268 memset(ctx, 0, sizeof *ctx); | |
| 269 | |
| 270 ctx->user = NULL; | |
| 271 ctx->alloc = *alloc; | |
| 272 ctx->locks = *locks; | |
| 273 | |
| 274 /* We are our own master! */ | |
| 275 ctx->master = ctx; | |
| 276 ctx->context_count = 1; | |
| 277 | |
| 278 ctx->error.print = fz_default_error_callback; | |
| 279 ctx->warn.print = fz_default_warning_callback; | |
| 280 | |
| 281 fz_init_error_context(ctx); | |
| 282 fz_init_aa_context(ctx); | |
| 283 fz_init_random_context(ctx); | |
| 284 | |
| 285 /* Now initialise sections that are shared */ | |
| 286 fz_try(ctx) | |
| 287 { | |
| 288 fz_new_store_context(ctx, max_store); | |
| 289 fz_new_glyph_cache_context(ctx); | |
| 290 fz_new_colorspace_context(ctx); | |
| 291 fz_new_font_context(ctx); | |
| 292 fz_new_document_handler_context(ctx); | |
| 293 fz_new_archive_handler_context(ctx); | |
| 294 fz_new_style_context(ctx); | |
| 295 fz_new_tuning_context(ctx); | |
| 296 } | |
| 297 fz_catch(ctx) | |
| 298 { | |
| 299 fz_report_error(ctx); | |
| 300 fprintf(stderr, "cannot create context (phase 2)\n"); | |
| 301 fz_drop_context(ctx); | |
| 302 return NULL; | |
| 303 } | |
| 304 return ctx; | |
| 305 } | |
| 306 | |
| 307 fz_context * | |
| 308 fz_clone_context(fz_context *ctx) | |
| 309 { | |
| 310 fz_context *new_ctx; | |
| 311 | |
| 312 /* We cannot safely clone the context without having locking/ | |
| 313 * unlocking functions. */ | |
| 314 if (ctx == NULL || (ctx->locks.lock == fz_locks_default.lock && ctx->locks.unlock == fz_locks_default.unlock)) | |
| 315 return NULL; | |
| 316 | |
| 317 new_ctx = ctx->alloc.malloc(ctx->alloc.user, sizeof(fz_context)); | |
| 318 if (!new_ctx) | |
| 319 return NULL; | |
| 320 | |
| 321 fz_lock(ctx, FZ_LOCK_ALLOC); | |
| 322 ctx->master->context_count++; | |
| 323 fz_unlock(ctx, FZ_LOCK_ALLOC); | |
| 324 new_ctx->master = ctx->master; | |
| 325 | |
| 326 /* First copy old context, including pointers to shared contexts */ | |
| 327 memcpy(new_ctx, ctx, sizeof (fz_context)); | |
| 328 | |
| 329 /* Reset error context to initial state. */ | |
| 330 fz_init_error_context(new_ctx); | |
| 331 | |
| 332 /* Then keep lock checking happy by keeping shared contexts with new context */ | |
| 333 fz_keep_document_handler_context(new_ctx); | |
| 334 fz_keep_archive_handler_context(new_ctx); | |
| 335 fz_keep_style_context(new_ctx); | |
| 336 fz_keep_tuning_context(new_ctx); | |
| 337 fz_keep_font_context(new_ctx); | |
| 338 fz_keep_colorspace_context(new_ctx); | |
| 339 fz_keep_store_context(new_ctx); | |
| 340 fz_keep_glyph_cache(new_ctx); | |
| 341 | |
| 342 return new_ctx; | |
| 343 } | |
| 344 | |
| 345 void fz_set_user_context(fz_context *ctx, void *user) | |
| 346 { | |
| 347 if (ctx != NULL) | |
| 348 ctx->user = user; | |
| 349 } | |
| 350 | |
| 351 void *fz_user_context(fz_context *ctx) | |
| 352 { | |
| 353 if (ctx == NULL) | |
| 354 return NULL; | |
| 355 | |
| 356 return ctx->user; | |
| 357 } | |
| 358 | |
| 359 void fz_register_activity_logger(fz_context *ctx, fz_activity_fn *activity, void *opaque) | |
| 360 { | |
| 361 if (ctx == NULL) | |
| 362 return; | |
| 363 | |
| 364 ctx->activity.activity = activity; | |
| 365 ctx->activity.opaque = opaque; | |
| 366 } | |
| 367 | |
| 368 void fz_log_activity(fz_context *ctx, fz_activity_reason reason, void *arg) | |
| 369 { | |
| 370 if (ctx == NULL || ctx->activity.activity == NULL) | |
| 371 return; | |
| 372 | |
| 373 ctx->activity.activity(ctx, ctx->activity.opaque, reason, arg); | |
| 374 } | |
| 375 | |
| 376 int fz_new_document_id(fz_context *ctx) | |
| 377 { | |
| 378 int id; | |
| 379 | |
| 380 fz_lock(ctx, FZ_LOCK_ALLOC); | |
| 381 while (ctx->master && ctx->master != ctx) | |
| 382 ctx = ctx->master; | |
| 383 id = ctx->next_document_id++; | |
| 384 fz_unlock(ctx, FZ_LOCK_ALLOC); | |
| 385 | |
| 386 return id; | |
| 387 } |
