diff options
Diffstat (limited to 'source/helpers/mu-office-lib')
-rw-r--r-- | source/helpers/mu-office-lib/mu-office-lib.c | 189 |
1 files changed, 184 insertions, 5 deletions
diff --git a/source/helpers/mu-office-lib/mu-office-lib.c b/source/helpers/mu-office-lib/mu-office-lib.c index 8c253e92..e2e5f6f5 100644 --- a/source/helpers/mu-office-lib/mu-office-lib.c +++ b/source/helpers/mu-office-lib/mu-office-lib.c @@ -107,10 +107,21 @@ static void muoffice_unlock(void *user, int lock); struct MuOfficeLib_s { fz_context *ctx; - mu_mutex mutexes[FZ_LOCK_MAX]; + mu_mutex mutexes[FZ_LOCK_MAX+1]; fz_locks_context locks; }; +/* + We add 1 extra lock which we use in this helper to protect + against accessing the fz_document from multiple threads + inadvertently when the caller is calling 'run' or + 'runBackground'. +*/ +enum +{ + DOCLOCK = FZ_LOCK_MAX +}; + static void muoffice_lock(void *user, int lock) { MuOfficeLib *mu = (MuOfficeLib *)user; @@ -129,7 +140,7 @@ static void fin_muoffice_locks(MuOfficeLib *mu) { int i; - for (i = 0; i < FZ_LOCK_MAX; i++) + for (i = 0; i < FZ_LOCK_MAX+1; i++) mu_destroy_mutex(&mu->mutexes[i]); } @@ -138,7 +149,7 @@ static fz_locks_context *init_muoffice_locks(MuOfficeLib *mu) int i; int failed = 0; - for (i = 0; i < FZ_LOCK_MAX; i++) + for (i = 0; i < FZ_LOCK_MAX+1; i++) failed |= mu_create_mutex(&mu->mutexes[i]); if (failed) @@ -209,6 +220,46 @@ void MuOfficeLib_destroy(MuOfficeLib *mu) Pal_Mem_free(mu); } + +/** + * Perform MuPDF native operations on a given MuOfficeLib + * instance. + * + * The function is called with an fz_context value that can + * be safely used (i.e. the context is cloned/dropped + * appropriately around the call). The function should signal + * errors by fz_throw-ing. + * + * @param mu the MuOfficeLib instance. + * @param fn the function to call to run the operations. + * @param arg Opaque data pointer. + * + * @return error indication - 0 for success + */ +MuError MuOfficeLib_run(MuOfficeLib *mu, void (*fn)(fz_context *ctx, void *arg), void *arg) +{ + fz_context *ctx; + MuError err = MuError_OK; + + if (mu == NULL) + return MuError_BadNull; + if (fn == NULL) + return err; + + ctx = fz_clone_context(mu->ctx); + if (ctx == NULL) + return MuError_OOM; + + fz_try(ctx) + fn(ctx, arg); + fz_catch(ctx) + err = MuError_Generic; + + fz_drop_context(ctx); + + return err; +} + /** * Find the type of a file given it's filename extension. * @@ -288,6 +339,8 @@ static void load_worker(void *arg) return; } + fz_lock(ctx, DOCLOCK); + fz_try(ctx) { doc->doc = fz_open_document(ctx, doc->path); @@ -324,6 +377,8 @@ static void load_worker(void *arg) err = MuOfficeDocErrorType_UnableToLoadDocument; fail: + fz_unlock(ctx, DOCLOCK); + if (err) doc->error(doc->cookie, err); @@ -608,6 +663,7 @@ MuError MuOfficeDoc_getPage( MuOfficeDoc *doc, { MuOfficePage *page; MuError err = MuError_OK; + fz_context *ctx; if (!doc) return MuError_BadNull; @@ -617,12 +673,15 @@ MuError MuOfficeDoc_getPage( MuOfficeDoc *doc, *pPage = NULL; ensure_doc_loaded(doc); + ctx = doc->ctx; page = Pal_Mem_calloc(1, sizeof(*page)); if (page == NULL) return MuError_OOM; - fz_try(doc->ctx) + fz_lock(ctx, DOCLOCK); + + fz_try(ctx) { page->doc = doc; page->pageNum = pageNumber; @@ -633,15 +692,73 @@ MuError MuOfficeDoc_getPage( MuOfficeDoc *doc, doc->pages = page; *pPage = page; } - fz_catch(doc->ctx) + fz_catch(ctx) { Pal_Mem_free(page); err = MuError_Generic; } + fz_unlock(ctx, DOCLOCK); + + return err; +} + + +/** + * Perform MuPDF native operations on a given document. + * + * The function is called with fz_context and fz_document + * values that can be safely used (i.e. the context is + * cloned/dropped appropriately around the function, and + * locking is used to ensure that no other threads are + * simultaneously using the document). Functions can + * signal errors by fz_throw-ing. + * + * Due to the locking, it is best to ensure that as little + * time is taken here as possible (i.e. if you fetch some + * data and then spend a long time processing it, it is + * probably best to fetch the data using MuOfficeDoc_run + * and then process it outside). This avoids potentially + * blocking the UI. + * + * @param doc the document object. + * @param fn the function to call with fz_context/fz_document + * values. + * @param arg Opaque data pointer. + * + * @return error indication - 0 for success + */ +MuError MuOfficeDoc_run(MuOfficeDoc *doc, void (*fn)(fz_context *ctx, fz_document *doc, void *arg), void *arg) +{ + fz_context *ctx; + MuError err = MuError_OK; + + if (doc == NULL) + return MuError_BadNull; + if (fn == NULL) + return err; + + ensure_doc_loaded(doc); + + ctx = fz_clone_context(doc->mu->ctx); + if (ctx == NULL) + return MuError_OOM; + + fz_lock(ctx, DOCLOCK); + + fz_try(ctx) + fn(ctx, doc->doc, arg); + fz_catch(ctx) + err = MuError_Generic; + + fz_unlock(ctx, DOCLOCK); + + fz_drop_context(ctx); + return err; } + /** * Destroy a page object * @@ -803,6 +920,58 @@ MuError MuOfficePage_getSizeForZoom( MuOfficePage *page, return MuError_OK; } +/** + * Perform MuPDF native operations on a given page. + * + * The function is called with fz_context and fz_page + * values that can be safely used (i.e. the context is + * cloned/dropped appropriately around the function, and + * locking is used to ensure that no other threads are + * simultaneously using the document). Functions can + * signal errors by fz_throw-ing. + * + * Due to the locking, it is best to ensure that as little + * time is taken here as possible (i.e. if you fetch some + * data and then spend a long time processing it, it is + * probably best to fetch the data using MuOfficePage_run + * and then process it outside). This avoids potentially + * blocking the UI. + * + * @param page the page object. + * @param fn the function to call with fz_context/fz_document + * values. + * @param arg Opaque data pointer. + * + * @return error indication - 0 for success + */ +MuError MuOfficePage_run(MuOfficePage *page, void (*fn)(fz_context *ctx, fz_page *page, void *arg), void *arg) +{ + fz_context *ctx; + MuError err = MuError_OK; + + if (page == NULL) + return MuError_BadNull; + if (fn == NULL) + return err; + + ctx = fz_clone_context(page->doc->mu->ctx); + if (ctx == NULL) + return MuError_OOM; + + fz_lock(ctx, DOCLOCK); + + fz_try(ctx) + fn(ctx, page->page, arg); + fz_catch(ctx) + err = MuError_Generic; + + fz_unlock(ctx, DOCLOCK); + + fz_drop_context(ctx); + + return err; +} + static void render_worker(void *arg) { MuOfficeRender *render = (MuOfficeRender *)arg; @@ -815,17 +984,25 @@ static void render_worker(void *arg) float scaley; fz_matrix matrix; fz_rect page_bounds; + int locked = 0; if (ctx == NULL) return; fz_var(pixmap); fz_var(dev); + fz_var(locked); fz_try(ctx) { if (page->list == NULL) + { + fz_lock(ctx, DOCLOCK); + locked = 1; page->list = fz_new_display_list_from_page(ctx, page->page); + locked = 0; + fz_unlock(ctx, DOCLOCK); + } /* Make a pixmap from the bitmap */ if (!render->area_valid) { @@ -865,6 +1042,8 @@ static void render_worker(void *arg) } fz_catch(ctx) { + if (locked) + fz_unlock(ctx, DOCLOCK); err = MuError_Generic; goto fail; } |