summaryrefslogtreecommitdiff
path: root/source/helpers
diff options
context:
space:
mode:
Diffstat (limited to 'source/helpers')
-rw-r--r--source/helpers/mu-office-lib/mu-office-lib.c189
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;
}