summaryrefslogtreecommitdiff
path: root/fitz
diff options
context:
space:
mode:
authorRobin Watts <robin.watts@artifex.com>2012-03-13 20:25:38 +0000
committerRobin Watts <robin.watts@artifex.com>2012-03-13 20:59:19 +0000
commit3212863288c4ad6396482b8fdb14db2af27c123f (patch)
tree9d7c7efe3a585c538f6e8d0edd5e3a77b5b8b6b5 /fitz
parentb6e9b2f8fe172d7175cea3d14d89f986688639af (diff)
parent33dc06b61c0816854193f006c35a9e797f098a22 (diff)
downloadmupdf-3212863288c4ad6396482b8fdb14db2af27c123f.tar.xz
Merge master and pg_android branches
Bring up to date with current APIs, including text device changes.
Diffstat (limited to 'fitz')
-rw-r--r--fitz/base_context.c14
-rw-r--r--fitz/base_error.c4
-rw-r--r--fitz/base_geometry.c2
-rw-r--r--fitz/base_hash.c111
-rw-r--r--fitz/base_memory.c2
-rw-r--r--fitz/base_object.c1265
-rw-r--r--fitz/base_string.c29
-rw-r--r--fitz/crypt_aes.c2
-rw-r--r--fitz/crypt_arc4.c2
-rw-r--r--fitz/crypt_md5.c2
-rw-r--r--fitz/crypt_sha2.c2
-rw-r--r--fitz/dev_bbox.c6
-rw-r--r--fitz/dev_list.c18
-rw-r--r--fitz/dev_null.c8
-rw-r--r--fitz/dev_text.c692
-rw-r--r--fitz/dev_trace.c18
-rw-r--r--fitz/doc_document.c2
-rw-r--r--fitz/doc_link.c2
-rw-r--r--fitz/doc_outline.c36
-rw-r--r--fitz/filt_basic.c2
-rw-r--r--fitz/filt_dctd.c13
-rw-r--r--fitz/filt_faxd.c2
-rw-r--r--fitz/filt_flate.c2
-rw-r--r--fitz/filt_jbig2d.c2
-rw-r--r--fitz/filt_lzwd.c2
-rw-r--r--fitz/filt_predict.c2
-rw-r--r--fitz/fitz-internal.h1092
-rw-r--r--fitz/fitz.h2567
-rw-r--r--fitz/image_jpeg.c5
-rw-r--r--fitz/image_jpx.c4
-rw-r--r--fitz/image_md5.c11
-rw-r--r--fitz/image_png.c2
-rw-r--r--fitz/image_save.c32
-rw-r--r--fitz/image_tiff.c4
-rw-r--r--fitz/res_bitmap.c47
-rw-r--r--fitz/res_colorspace.c74
-rw-r--r--fitz/res_font.c34
-rw-r--r--fitz/res_halftone.c13
-rw-r--r--fitz/res_path.c18
-rw-r--r--fitz/res_pixmap.c85
-rw-r--r--fitz/res_shade.c36
-rw-r--r--fitz/res_store.c165
-rw-r--r--fitz/res_text.c19
-rw-r--r--fitz/stm_buffer.c22
-rw-r--r--fitz/stm_open.c2
-rw-r--r--fitz/stm_read.c10
46 files changed, 3591 insertions, 2893 deletions
diff --git a/fitz/base_context.c b/fitz/base_context.c
index fe69ff8e..075a3d02 100644
--- a/fitz/base_context.c
+++ b/fitz/base_context.c
@@ -1,12 +1,4 @@
-#include "fitz.h"
-
-static fz_obj *
-fz_resolve_indirect_null(fz_obj *ref)
-{
- return ref;
-}
-
-fz_obj *(*fz_resolve_indirect)(fz_obj*) = fz_resolve_indirect_null;
+#include "fitz-internal.h"
void
fz_free_context(fz_context *ctx)
@@ -130,7 +122,9 @@ fz_clone_context_internal(fz_context *ctx)
if (ctx == NULL || ctx->alloc == NULL)
return NULL;
new_ctx = new_context_phase1(ctx->alloc, ctx->locks);
- new_ctx->store = fz_store_keep(ctx);
+ /* Inherit AA defaults from old context. */
+ fz_copy_aa_context(new_ctx, ctx);
+ new_ctx->store = fz_keep_store_context(ctx);
new_ctx->glyph_cache = fz_keep_glyph_cache(ctx);
new_ctx->font = fz_keep_font_context(ctx);
return new_ctx;
diff --git a/fitz/base_error.c b/fitz/base_error.c
index 6b54fb69..71a32a2e 100644
--- a/fitz/base_error.c
+++ b/fitz/base_error.c
@@ -1,4 +1,4 @@
-#include "fitz.h"
+#include "fitz-internal.h"
/* Warning context */
@@ -46,7 +46,7 @@ void fz_warn(fz_context *ctx, char *fmt, ...)
static void throw(fz_error_context *ex)
{
if (ex->top >= 0) {
- longjmp(ex->stack[ex->top].buffer, 1);
+ fz_longjmp(ex->stack[ex->top].buffer, 1);
} else {
fprintf(stderr, "uncaught exception: %s\n", ex->message);
LOGE("uncaught exception: %s\n", ex->message);
diff --git a/fitz/base_geometry.c b/fitz/base_geometry.c
index fc5ce517..84134179 100644
--- a/fitz/base_geometry.c
+++ b/fitz/base_geometry.c
@@ -1,4 +1,4 @@
-#include "fitz.h"
+#include "fitz-internal.h"
#define MAX4(a,b,c,d) MAX(MAX(a,b), MAX(c,d))
#define MIN4(a,b,c,d) MIN(MIN(a,b), MIN(c,d))
diff --git a/fitz/base_hash.c b/fitz/base_hash.c
index 630f6b6a..4ba02f4d 100644
--- a/fitz/base_hash.c
+++ b/fitz/base_hash.c
@@ -1,4 +1,4 @@
-#include "fitz.h"
+#include "fitz-internal.h"
/*
Simple hashtable with open addressing linear probe.
@@ -22,6 +22,7 @@ struct fz_hash_table_s
int keylen;
int size;
int load;
+ int lock; /* -1 or the lock used to protect this hash table */
fz_hash_entry *ents;
};
@@ -42,7 +43,7 @@ static unsigned hash(unsigned char *s, int len)
}
fz_hash_table *
-fz_new_hash_table(fz_context *ctx, int initialsize, int keylen)
+fz_new_hash_table(fz_context *ctx, int initialsize, int keylen, int lock)
{
fz_hash_table *table;
@@ -52,6 +53,7 @@ fz_new_hash_table(fz_context *ctx, int initialsize, int keylen)
table->keylen = keylen;
table->size = initialsize;
table->load = 0;
+ table->lock = lock;
fz_try(ctx)
{
table->ents = fz_malloc_array(ctx, table->size, sizeof(fz_hash_entry));
@@ -98,10 +100,45 @@ fz_free_hash(fz_context *ctx, fz_hash_table *table)
fz_free(ctx, table);
}
+static void *
+do_hash_insert(fz_context *ctx, fz_hash_table *table, void *key, void *val)
+{
+ fz_hash_entry *ents;
+ unsigned size;
+ unsigned pos;
+
+ ents = table->ents;
+ size = table->size;
+ pos = hash(key, table->keylen) % size;
+
+ if (table->lock >= 0)
+ fz_assert_lock_held(ctx, table->lock);
+
+ while (1)
+ {
+ if (!ents[pos].val)
+ {
+ memcpy(ents[pos].key, key, table->keylen);
+ ents[pos].val = val;
+ table->load ++;
+ return NULL;
+ }
+
+ if (memcmp(key, ents[pos].key, table->keylen) == 0)
+ {
+ fz_warn(ctx, "assert: overwrite hash slot");
+ return ents[pos].val;
+ }
+
+ pos = (pos + 1) % size;
+ }
+}
+
static void
fz_resize_hash(fz_context *ctx, fz_hash_table *table, int newsize)
{
fz_hash_entry *oldents = table->ents;
+ fz_hash_entry *newents = table->ents;
int oldsize = table->size;
int oldload = table->load;
int i;
@@ -112,7 +149,22 @@ fz_resize_hash(fz_context *ctx, fz_hash_table *table, int newsize)
return;
}
- table->ents = fz_malloc_array(ctx, newsize, sizeof(fz_hash_entry));
+ if (table->lock == FZ_LOCK_ALLOC)
+ fz_unlock(ctx, FZ_LOCK_ALLOC);
+ newents = fz_malloc_array(ctx, newsize, sizeof(fz_hash_entry));
+ if (table->lock == FZ_LOCK_ALLOC)
+ fz_lock(ctx, FZ_LOCK_ALLOC);
+ if (table->lock >= 0)
+ {
+ if (table->size >= newsize)
+ {
+ /* Someone else fixed it before we could lock! */
+ fz_unlock(ctx, table->lock);
+ fz_free(ctx, newents);
+ return;
+ }
+ }
+ table->ents = newents;
memset(table->ents, 0, sizeof(fz_hash_entry) * newsize);
table->size = newsize;
table->load = 0;
@@ -121,11 +173,15 @@ fz_resize_hash(fz_context *ctx, fz_hash_table *table, int newsize)
{
if (oldents[i].val)
{
- fz_hash_insert(ctx, table, oldents[i].key, oldents[i].val);
+ do_hash_insert(ctx, table, oldents[i].key, oldents[i].val);
}
}
+ if (table->lock == FZ_LOCK_ALLOC)
+ fz_unlock(ctx, FZ_LOCK_ALLOC);
fz_free(ctx, oldents);
+ if (table->lock == FZ_LOCK_ALLOC)
+ fz_lock(ctx, FZ_LOCK_ALLOC);
}
void *
@@ -135,6 +191,9 @@ fz_hash_find(fz_context *ctx, fz_hash_table *table, void *key)
unsigned size = table->size;
unsigned pos = hash(key, table->keylen) % size;
+ if (table->lock >= 0)
+ fz_assert_lock_held(ctx, table->lock);
+
while (1)
{
if (!ents[pos].val)
@@ -150,37 +209,12 @@ fz_hash_find(fz_context *ctx, fz_hash_table *table, void *key)
void *
fz_hash_insert(fz_context *ctx, fz_hash_table *table, void *key, void *val)
{
- fz_hash_entry *ents;
- unsigned size;
- unsigned pos;
-
if (table->load > table->size * 8 / 10)
{
fz_resize_hash(ctx, table, table->size * 2);
}
- ents = table->ents;
- size = table->size;
- pos = hash(key, table->keylen) % size;
-
- while (1)
- {
- if (!ents[pos].val)
- {
- memcpy(ents[pos].key, key, table->keylen);
- ents[pos].val = val;
- table->load ++;
- return NULL;
- }
-
- if (memcmp(key, ents[pos].key, table->keylen) == 0)
- {
- fz_warn(ctx, "assert: overwrite hash slot");
- return ents[pos].val;
- }
-
- pos = (pos + 1) % size;
- }
+ return do_hash_insert(ctx, table, key, val);
}
void
@@ -191,11 +225,14 @@ fz_hash_remove(fz_context *ctx, fz_hash_table *table, void *key)
unsigned pos = hash(key, table->keylen) % size;
unsigned hole, look, code;
+ if (table->lock >= 0)
+ fz_assert_lock_held(ctx, table->lock);
+
while (1)
{
if (!ents[pos].val)
{
- fz_warn(ctx, "assert: remove inexistent hash entry");
+ fz_warn(ctx, "assert: remove non-existent hash entry");
return;
}
@@ -231,22 +268,22 @@ fz_hash_remove(fz_context *ctx, fz_hash_table *table, void *key)
}
void
-fz_debug_hash(fz_context *ctx, fz_hash_table *table)
+fz_print_hash(fz_context *ctx, FILE *out, fz_hash_table *table)
{
int i, k;
- printf("cache load %d / %d\n", table->load, table->size);
+ fprintf(out, "cache load %d / %d\n", table->load, table->size);
for (i = 0; i < table->size; i++)
{
if (!table->ents[i].val)
- printf("table % 4d: empty\n", i);
+ fprintf(out, "table % 4d: empty\n", i);
else
{
- printf("table % 4d: key=", i);
+ fprintf(out, "table % 4d: key=", i);
for (k = 0; k < MAX_KEY_LEN; k++)
- printf("%02x", ((char*)table->ents[i].key)[k]);
- printf(" val=$%p\n", table->ents[i].val);
+ fprintf(out, "%02x", ((char*)table->ents[i].key)[k]);
+ fprintf(out, " val=$%p\n", table->ents[i].val);
}
}
}
diff --git a/fitz/base_memory.c b/fitz/base_memory.c
index c9ec2628..32c7ff84 100644
--- a/fitz/base_memory.c
+++ b/fitz/base_memory.c
@@ -1,4 +1,4 @@
-#include "fitz.h"
+#include "fitz-internal.h"
static void *
do_scavenging_malloc(fz_context *ctx, unsigned int size)
diff --git a/fitz/base_object.c b/fitz/base_object.c
deleted file mode 100644
index 964c5bb4..00000000
--- a/fitz/base_object.c
+++ /dev/null
@@ -1,1265 +0,0 @@
-#include "fitz.h"
-
-typedef enum fz_objkind_e
-{
- FZ_NULL,
- FZ_BOOL,
- FZ_INT,
- FZ_REAL,
- FZ_STRING,
- FZ_NAME,
- FZ_ARRAY,
- FZ_DICT,
- FZ_INDIRECT
-} fz_objkind;
-
-struct keyval
-{
- fz_obj *k;
- fz_obj *v;
-};
-
-struct fz_obj_s
-{
- int refs;
- fz_objkind kind;
- fz_context *ctx;
- union
- {
- int b;
- int i;
- float f;
- struct {
- unsigned short len;
- char buf[1];
- } s;
- char n[1];
- struct {
- int len;
- int cap;
- fz_obj **items;
- } a;
- struct {
- char sorted;
- char marked;
- int len;
- int cap;
- struct keyval *items;
- } d;
- struct {
- int num;
- int gen;
- struct pdf_xref_s *xref;
- } r;
- } u;
-};
-
-fz_obj *
-fz_new_null(fz_context *ctx)
-{
- fz_obj *obj;
- obj = Memento_label(fz_malloc(ctx, sizeof(fz_obj)), "fz_obj(null)");
- obj->ctx = ctx;
- obj->refs = 1;
- obj->kind = FZ_NULL;
- return obj;
-}
-
-fz_obj *
-fz_new_bool(fz_context *ctx, int b)
-{
- fz_obj *obj;
- obj = Memento_label(fz_malloc(ctx, sizeof(fz_obj)), "fz_obj(bool)");
- obj->ctx = ctx;
- obj->refs = 1;
- obj->kind = FZ_BOOL;
- obj->u.b = b;
- return obj;
-}
-
-fz_obj *
-fz_new_int(fz_context *ctx, int i)
-{
- fz_obj *obj;
- obj = Memento_label(fz_malloc(ctx, sizeof(fz_obj)), "fz_obj(int)");
- obj->ctx = ctx;
- obj->refs = 1;
- obj->kind = FZ_INT;
- obj->u.i = i;
- return obj;
-}
-
-fz_obj *
-fz_new_real(fz_context *ctx, float f)
-{
- fz_obj *obj;
- obj = Memento_label(fz_malloc(ctx, sizeof(fz_obj)), "fz_obj(real)");
- obj->ctx = ctx;
- obj->refs = 1;
- obj->kind = FZ_REAL;
- obj->u.f = f;
- return obj;
-}
-
-fz_obj *
-fz_new_string(fz_context *ctx, char *str, int len)
-{
- fz_obj *obj;
- obj = Memento_label(fz_malloc(ctx, offsetof(fz_obj, u.s.buf) + len + 1), "fz_obj(string)");
- obj->ctx = ctx;
- obj->refs = 1;
- obj->kind = FZ_STRING;
- obj->u.s.len = len;
- memcpy(obj->u.s.buf, str, len);
- obj->u.s.buf[len] = '\0';
- return obj;
-}
-
-fz_obj *
-fz_new_name(fz_context *ctx, char *str)
-{
- fz_obj *obj;
- obj = Memento_label(fz_malloc(ctx, offsetof(fz_obj, u.n) + strlen(str) + 1), "fz_obj(name)");
- obj->ctx = ctx;
- obj->refs = 1;
- obj->kind = FZ_NAME;
- strcpy(obj->u.n, str);
- return obj;
-}
-
-fz_obj *
-fz_new_indirect(fz_context *ctx, int num, int gen, void *xref)
-{
- fz_obj *obj;
- obj = Memento_label(fz_malloc(ctx, sizeof(fz_obj)), "fz_obj(indirect)");
- obj->ctx = ctx;
- obj->refs = 1;
- obj->kind = FZ_INDIRECT;
- obj->u.r.num = num;
- obj->u.r.gen = gen;
- obj->u.r.xref = xref;
- return obj;
-}
-
-fz_obj *
-fz_keep_obj(fz_obj *obj)
-{
- assert(obj);
- obj->refs ++;
- return obj;
-}
-
-int fz_is_indirect(fz_obj *obj)
-{
- return obj ? obj->kind == FZ_INDIRECT : 0;
-}
-
-#define RESOLVE(obj) \
- do { \
- if (obj && obj->kind == FZ_INDIRECT) \
- {\
- fz_assert_lock_not_held(obj->ctx, FZ_LOCK_FILE); \
- obj = fz_resolve_indirect(obj); \
- } \
- } while (0)
-
-int fz_is_null(fz_obj *obj)
-{
- RESOLVE(obj);
- return obj ? obj->kind == FZ_NULL : 0;
-}
-
-int fz_is_bool(fz_obj *obj)
-{
- RESOLVE(obj);
- return obj ? obj->kind == FZ_BOOL : 0;
-}
-
-int fz_is_int(fz_obj *obj)
-{
- RESOLVE(obj);
- return obj ? obj->kind == FZ_INT : 0;
-}
-
-int fz_is_real(fz_obj *obj)
-{
- RESOLVE(obj);
- return obj ? obj->kind == FZ_REAL : 0;
-}
-
-int fz_is_string(fz_obj *obj)
-{
- RESOLVE(obj);
- return obj ? obj->kind == FZ_STRING : 0;
-}
-
-int fz_is_name(fz_obj *obj)
-{
- RESOLVE(obj);
- return obj ? obj->kind == FZ_NAME : 0;
-}
-
-int fz_is_array(fz_obj *obj)
-{
- RESOLVE(obj);
- return obj ? obj->kind == FZ_ARRAY : 0;
-}
-
-int fz_is_dict(fz_obj *obj)
-{
- RESOLVE(obj);
- return obj ? obj->kind == FZ_DICT : 0;
-}
-
-int fz_to_bool(fz_obj *obj)
-{
- RESOLVE(obj);
- if (!obj)
- return 0;
- return obj->kind == FZ_BOOL ? obj->u.b : 0;
-}
-
-int fz_to_int(fz_obj *obj)
-{
- RESOLVE(obj);
- if (!obj)
- return 0;
- if (obj->kind == FZ_INT)
- return obj->u.i;
- if (obj->kind == FZ_REAL)
- return (int)(obj->u.f + 0.5f); /* No roundf in MSVC */
- return 0;
-}
-
-float fz_to_real(fz_obj *obj)
-{
- RESOLVE(obj);
- if (!obj)
- return 0;
- if (obj->kind == FZ_REAL)
- return obj->u.f;
- if (obj->kind == FZ_INT)
- return obj->u.i;
- return 0;
-}
-
-char *fz_to_name(fz_obj *obj)
-{
- RESOLVE(obj);
- if (!obj || obj->kind != FZ_NAME)
- return "";
- return obj->u.n;
-}
-
-char *fz_to_str_buf(fz_obj *obj)
-{
- RESOLVE(obj);
- if (!obj || obj->kind != FZ_STRING)
- return "";
- return obj->u.s.buf;
-}
-
-int fz_to_str_len(fz_obj *obj)
-{
- RESOLVE(obj);
- if (!obj || obj->kind != FZ_STRING)
- return 0;
- return obj->u.s.len;
-}
-
-/* for use by pdf_crypt_obj_imp to decrypt AES string in place */
-void fz_set_str_len(fz_obj *obj, int newlen)
-{
- RESOLVE(obj);
- if (!obj || obj->kind != FZ_STRING)
- return; /* This should never happen */
- if (newlen > obj->u.s.len)
- return; /* This should never happen */
- obj->u.s.len = newlen;
-}
-
-fz_obj *fz_to_dict(fz_obj *obj)
-{
- RESOLVE(obj);
- return (obj && obj->kind == FZ_DICT ? obj : NULL);
-}
-
-int fz_to_num(fz_obj *obj)
-{
- if (!obj || obj->kind != FZ_INDIRECT)
- return 0;
- return obj->u.r.num;
-}
-
-int fz_to_gen(fz_obj *obj)
-{
- if (!obj || obj->kind != FZ_INDIRECT)
- return 0;
- return obj->u.r.gen;
-}
-
-void *fz_get_indirect_document(fz_obj *obj)
-{
- if (!obj || obj->kind != FZ_INDIRECT)
- return NULL;
- return obj->u.r.xref;
-}
-
-int
-fz_objcmp(fz_obj *a, fz_obj *b)
-{
- int i;
-
- if (a == b)
- return 0;
-
- if (!a || !b)
- return 1;
-
- if (a->kind != b->kind)
- return 1;
-
- switch (a->kind)
- {
- case FZ_NULL:
- return 0;
-
- case FZ_BOOL:
- return a->u.b - b->u.b;
-
- case FZ_INT:
- return a->u.i - b->u.i;
-
- case FZ_REAL:
- if (a->u.f < b->u.f)
- return -1;
- if (a->u.f > b->u.f)
- return 1;
- return 0;
-
- case FZ_STRING:
- if (a->u.s.len < b->u.s.len)
- {
- if (memcmp(a->u.s.buf, b->u.s.buf, a->u.s.len) <= 0)
- return -1;
- return 1;
- }
- if (a->u.s.len > b->u.s.len)
- {
- if (memcmp(a->u.s.buf, b->u.s.buf, b->u.s.len) >= 0)
- return 1;
- return -1;
- }
- return memcmp(a->u.s.buf, b->u.s.buf, a->u.s.len);
-
- case FZ_NAME:
- return strcmp(a->u.n, b->u.n);
-
- case FZ_INDIRECT:
- if (a->u.r.num == b->u.r.num)
- return a->u.r.gen - b->u.r.gen;
- return a->u.r.num - b->u.r.num;
-
- case FZ_ARRAY:
- if (a->u.a.len != b->u.a.len)
- return a->u.a.len - b->u.a.len;
- for (i = 0; i < a->u.a.len; i++)
- if (fz_objcmp(a->u.a.items[i], b->u.a.items[i]))
- return 1;
- return 0;
-
- case FZ_DICT:
- if (a->u.d.len != b->u.d.len)
- return a->u.d.len - b->u.d.len;
- for (i = 0; i < a->u.d.len; i++)
- {
- if (fz_objcmp(a->u.d.items[i].k, b->u.d.items[i].k))
- return 1;
- if (fz_objcmp(a->u.d.items[i].v, b->u.d.items[i].v))
- return 1;
- }
- return 0;
-
- }
- return 1;
-}
-
-static char *
-fz_objkindstr(fz_obj *obj)
-{
- if (!obj)
- return "<NULL>";
- switch (obj->kind)
- {
- case FZ_NULL: return "null";
- case FZ_BOOL: return "boolean";
- case FZ_INT: return "integer";
- case FZ_REAL: return "real";
- case FZ_STRING: return "string";
- case FZ_NAME: return "name";
- case FZ_ARRAY: return "array";
- case FZ_DICT: return "dictionary";
- case FZ_INDIRECT: return "reference";
- }
- return "<unknown>";
-}
-
-fz_obj *
-fz_new_array(fz_context *ctx, int initialcap)
-{
- fz_obj *obj;
- int i;
-
- obj = Memento_label(fz_malloc(ctx, sizeof(fz_obj)), "fz_obj(array)");
- obj->ctx = ctx;
- obj->refs = 1;
- obj->kind = FZ_ARRAY;
-
- obj->u.a.len = 0;
- obj->u.a.cap = initialcap > 1 ? initialcap : 6;
-
- fz_try(ctx)
- {
- obj->u.a.items = Memento_label(fz_malloc_array(ctx, obj->u.a.cap, sizeof(fz_obj*)), "fz_obj(array items)");
- }
- fz_catch(ctx)
- {
- fz_free(ctx, obj);
- fz_rethrow(ctx);
- }
- for (i = 0; i < obj->u.a.cap; i++)
- obj->u.a.items[i] = NULL;
-
- return obj;
-}
-
-static void
-fz_array_grow(fz_obj *obj)
-{
- int i;
-
- obj->u.a.cap = (obj->u.a.cap * 3) / 2;
- obj->u.a.items = fz_resize_array(obj->ctx, obj->u.a.items, obj->u.a.cap, sizeof(fz_obj*));
-
- for (i = obj->u.a.len ; i < obj->u.a.cap; i++)
- obj->u.a.items[i] = NULL;
-}
-
-fz_obj *
-fz_copy_array(fz_context *ctx, fz_obj *obj)
-{
- fz_obj *arr;
- int i;
- int n;
-
- RESOLVE(obj);
- if (!obj || obj->kind != FZ_ARRAY)
- fz_warn(ctx, "assert: not an array (%s)", fz_objkindstr(obj));
-
- arr = fz_new_array(ctx, fz_array_len(obj));
- n = fz_array_len(obj);
- for (i = 0; i < n; i++)
- fz_array_push(arr, fz_array_get(obj, i));
-
- return arr;
-}
-
-int
-fz_array_len(fz_obj *obj)
-{
- RESOLVE(obj);
- if (!obj || obj->kind != FZ_ARRAY)
- return 0;
- return obj->u.a.len;
-}
-
-fz_obj *
-fz_array_get(fz_obj *obj, int i)
-{
- RESOLVE(obj);
-
- if (!obj || obj->kind != FZ_ARRAY)
- return NULL;
-
- if (i < 0 || i >= obj->u.a.len)
- return NULL;
-
- return obj->u.a.items[i];
-}
-
-void
-fz_array_put(fz_obj *obj, int i, fz_obj *item)
-{
- RESOLVE(obj);
-
- if (!obj)
- return; /* Can't warn :( */
- if (obj->kind != FZ_ARRAY)
- fz_warn(obj->ctx, "assert: not an array (%s)", fz_objkindstr(obj));
- else if (i < 0)
- fz_warn(obj->ctx, "assert: index %d < 0", i);
- else if (i >= obj->u.a.len)
- fz_warn(obj->ctx, "assert: index %d > length %d", i, obj->u.a.len);
- else
- {
- if (obj->u.a.items[i])
- fz_drop_obj(obj->u.a.items[i]);
- obj->u.a.items[i] = fz_keep_obj(item);
- }
-}
-
-void
-fz_array_push(fz_obj *obj, fz_obj *item)
-{
- RESOLVE(obj);
-
- if (!obj)
- return; /* Can't warn :( */
- if (obj->kind != FZ_ARRAY)
- fz_warn(obj->ctx, "assert: not an array (%s)", fz_objkindstr(obj));
- else
- {
- if (obj->u.a.len + 1 > obj->u.a.cap)
- fz_array_grow(obj);
- obj->u.a.items[obj->u.a.len] = fz_keep_obj(item);
- obj->u.a.len++;
- }
-}
-
-void
-fz_array_insert(fz_obj *obj, fz_obj *item)
-{
- RESOLVE(obj);
-
- if (!obj)
- return; /* Can't warn :( */
- if (obj->kind != FZ_ARRAY)
- fz_warn(obj->ctx, "assert: not an array (%s)", fz_objkindstr(obj));
- else
- {
- if (obj->u.a.len + 1 > obj->u.a.cap)
- fz_array_grow(obj);
- memmove(obj->u.a.items + 1, obj->u.a.items, obj->u.a.len * sizeof(fz_obj*));
- obj->u.a.items[0] = fz_keep_obj(item);
- obj->u.a.len++;
- }
-}
-
-int
-fz_array_contains(fz_obj *arr, fz_obj *obj)
-{
- int i;
-
- for (i = 0; i < fz_array_len(arr); i++)
- if (!fz_objcmp(fz_array_get(arr, i), obj))
- return 1;
-
- return 0;
-}
-
-/* dicts may only have names as keys! */
-
-static int keyvalcmp(const void *ap, const void *bp)
-{
- const struct keyval *a = ap;
- const struct keyval *b = bp;
- return strcmp(fz_to_name(a->k), fz_to_name(b->k));
-}
-
-fz_obj *
-fz_new_dict(fz_context *ctx, int initialcap)
-{
- fz_obj *obj;
- int i;
-
- obj = Memento_label(fz_malloc(ctx, sizeof(fz_obj)), "fz_obj(dict)");
- obj->ctx = ctx;
- obj->refs = 1;
- obj->kind = FZ_DICT;
-
- obj->u.d.sorted = 0;
- obj->u.d.marked = 0;
- obj->u.d.len = 0;
- obj->u.d.cap = initialcap > 1 ? initialcap : 10;
-
- fz_try(ctx)
- {
- obj->u.d.items = Memento_label(fz_malloc_array(ctx, obj->u.d.cap, sizeof(struct keyval)), "fz_obj(dict items)");
- }
- fz_catch(ctx)
- {
- fz_free(ctx, obj);
- fz_rethrow(ctx);
- }
- for (i = 0; i < obj->u.d.cap; i++)
- {
- obj->u.d.items[i].k = NULL;
- obj->u.d.items[i].v = NULL;
- }
-
- return obj;
-}
-
-static void
-fz_dict_grow(fz_obj *obj)
-{
- int i;
-
- obj->u.d.cap = (obj->u.d.cap * 3) / 2;
- obj->u.d.items = fz_resize_array(obj->ctx, obj->u.d.items, obj->u.d.cap, sizeof(struct keyval));
-
- for (i = obj->u.d.len; i < obj->u.d.cap; i++)
- {
- obj->u.d.items[i].k = NULL;
- obj->u.d.items[i].v = NULL;
- }
-}
-
-fz_obj *
-fz_copy_dict(fz_context *ctx, fz_obj *obj)
-{
- fz_obj *dict;
- int i, n;
-
- RESOLVE(obj);
- if (obj && obj->kind != FZ_DICT)
- fz_warn(ctx, "assert: not a dict (%s)", fz_objkindstr(obj));
-
- n = fz_dict_len(obj);
- dict = fz_new_dict(ctx, n);
- for (i = 0; i < n; i++)
- fz_dict_put(dict, fz_dict_get_key(obj, i), fz_dict_get_val(obj, i));
-
- return dict;
-}
-
-int
-fz_dict_len(fz_obj *obj)
-{
- RESOLVE(obj);
- if (!obj || obj->kind != FZ_DICT)
- return 0;
- return obj->u.d.len;
-}
-
-fz_obj *
-fz_dict_get_key(fz_obj *obj, int i)
-{
- RESOLVE(obj);
- if (!obj || obj->kind != FZ_DICT)
- return NULL;
-
- if (i < 0 || i >= obj->u.d.len)
- return NULL;
-
- return obj->u.d.items[i].k;
-}
-
-fz_obj *
-fz_dict_get_val(fz_obj *obj, int i)
-{
- RESOLVE(obj);
- if (!obj || obj->kind != FZ_DICT)
- return NULL;
-
- if (i < 0 || i >= obj->u.d.len)
- return NULL;
-
- return obj->u.d.items[i].v;
-}
-
-static int
-fz_dict_finds(fz_obj *obj, char *key, int *location)
-{
- if (obj->u.d.sorted && obj->u.d.len > 0)
- {
- int l = 0;
- int r = obj->u.d.len - 1;
-
- if (strcmp(fz_to_name(obj->u.d.items[r].k), key) < 0)
- {
- if (location)
- *location = r + 1;
- return -1;
- }
-
- while (l <= r)
- {
- int m = (l + r) >> 1;
- int c = -strcmp(fz_to_name(obj->u.d.items[m].k), key);
- if (c < 0)
- r = m - 1;
- else if (c > 0)
- l = m + 1;
- else
- return m;
-
- if (location)
- *location = l;
- }
- }
-
- else
- {
- int i;
- for (i = 0; i < obj->u.d.len; i++)
- if (strcmp(fz_to_name(obj->u.d.items[i].k), key) == 0)
- return i;
-
- if (location)
- *location = obj->u.d.len;
- }
-
- return -1;
-}
-
-fz_obj *
-fz_dict_gets(fz_obj *obj, char *key)
-{
- int i;
-
- RESOLVE(obj);
- if (!obj || obj->kind != FZ_DICT)
- return NULL;
-
- i = fz_dict_finds(obj, key, NULL);
- if (i >= 0)
- return obj->u.d.items[i].v;
-
- return NULL;
-}
-
-fz_obj *
-fz_dict_get(fz_obj *obj, fz_obj *key)
-{
- if (!key || key->kind != FZ_NAME)
- return NULL;
- return fz_dict_gets(obj, fz_to_name(key));
-}
-
-fz_obj *
-fz_dict_getsa(fz_obj *obj, char *key, char *abbrev)
-{
- fz_obj *v;
- v = fz_dict_gets(obj, key);
- if (v)
- return v;
- return fz_dict_gets(obj, abbrev);
-}
-
-void
-fz_dict_put(fz_obj *obj, fz_obj *key, fz_obj *val)
-{
- int location;
- char *s;
- int i;
-
- RESOLVE(obj);
- if (!obj || obj->kind != FZ_DICT)
- {
- fz_warn(obj->ctx, "assert: not a dict (%s)", fz_objkindstr(obj));
- return;
- }
-
- RESOLVE(key);
- if (!key || key->kind != FZ_NAME)
- {
- fz_warn(obj->ctx, "assert: key is not a name (%s)", fz_objkindstr(obj));
- return;
- }
- else
- s = fz_to_name(key);
-
- if (!val)
- {
- fz_warn(obj->ctx, "assert: val does not exist for key (%s)", s);
- return;
- }
-
- if (obj->u.d.len > 100 && !obj->u.d.sorted)
- fz_sort_dict(obj);
-
- i = fz_dict_finds(obj, s, &location);
- if (i >= 0 && i < obj->u.d.len)
- {
- fz_drop_obj(obj->u.d.items[i].v);
- obj->u.d.items[i].v = fz_keep_obj(val);
- }
- else
- {
- if (obj->u.d.len + 1 > obj->u.d.cap)
- fz_dict_grow(obj);
-
- i = location;
- if (obj->u.d.sorted && obj->u.d.len > 0)
- memmove(&obj->u.d.items[i + 1],
- &obj->u.d.items[i],
- (obj->u.d.len - i) * sizeof(struct keyval));
-
- obj->u.d.items[i].k = fz_keep_obj(key);
- obj->u.d.items[i].v = fz_keep_obj(val);
- obj->u.d.len ++;
- }
-}
-
-void
-fz_dict_puts(fz_obj *obj, char *key, fz_obj *val)
-{
- fz_obj *keyobj = fz_new_name(obj->ctx, key);
- fz_dict_put(obj, keyobj, val);
- fz_drop_obj(keyobj);
-}
-
-void
-fz_dict_dels(fz_obj *obj, char *key)
-{
- RESOLVE(obj);
-
- if (!obj || obj->kind != FZ_DICT)
- fz_warn(obj->ctx, "assert: not a dict (%s)", fz_objkindstr(obj));
- else
- {
- int i = fz_dict_finds(obj, key, NULL);
- if (i >= 0)
- {
- fz_drop_obj(obj->u.d.items[i].k);
- fz_drop_obj(obj->u.d.items[i].v);
- obj->u.d.sorted = 0;
- obj->u.d.items[i] = obj->u.d.items[obj->u.d.len-1];
- obj->u.d.len --;
- }
- }
-}
-
-void
-fz_dict_del(fz_obj *obj, fz_obj *key)
-{
- RESOLVE(key);
- if (!key || key->kind != FZ_NAME)
- fz_warn(obj->ctx, "assert: key is not a name (%s)", fz_objkindstr(obj));
- else
- fz_dict_dels(obj, key->u.n);
-}
-
-void
-fz_sort_dict(fz_obj *obj)
-{
- RESOLVE(obj);
- if (!obj || obj->kind != FZ_DICT)
- return;
- if (!obj->u.d.sorted)
- {
- qsort(obj->u.d.items, obj->u.d.len, sizeof(struct keyval), keyvalcmp);
- obj->u.d.sorted = 1;
- }
-}
-
-int
-fz_dict_marked(fz_obj *obj)
-{
- RESOLVE(obj);
- if (!obj || obj->kind != FZ_DICT)
- return 0;
- return obj->u.d.marked;
-}
-
-int
-fz_dict_mark(fz_obj *obj)
-{
- int marked;
- RESOLVE(obj);
- if (!obj || obj->kind != FZ_DICT)
- return 0;
- marked = obj->u.d.marked;
- obj->u.d.marked = 1;
- return marked;
-}
-
-void
-fz_dict_unmark(fz_obj *obj)
-{
- RESOLVE(obj);
- if (!obj || obj->kind != FZ_DICT)
- return;
- obj->u.d.marked = 0;
-}
-
-static void
-fz_free_array(fz_obj *obj)
-{
- int i;
-
- for (i = 0; i < obj->u.a.len; i++)
- if (obj->u.a.items[i])
- fz_drop_obj(obj->u.a.items[i]);
-
- fz_free(obj->ctx, obj->u.a.items);
- fz_free(obj->ctx, obj);
-}
-
-static void
-fz_free_dict(fz_obj *obj)
-{
- int i;
-
- for (i = 0; i < obj->u.d.len; i++) {
- if (obj->u.d.items[i].k)
- fz_drop_obj(obj->u.d.items[i].k);
- if (obj->u.d.items[i].v)
- fz_drop_obj(obj->u.d.items[i].v);
- }
-
- fz_free(obj->ctx, obj->u.d.items);
- fz_free(obj->ctx, obj);
-}
-
-void
-fz_drop_obj(fz_obj *obj)
-{
- if (!obj)
- return;
- if (--obj->refs)
- return;
- if (obj->kind == FZ_ARRAY)
- fz_free_array(obj);
- else if (obj->kind == FZ_DICT)
- fz_free_dict(obj);
- else
- fz_free(obj->ctx, obj);
-}
-
-/* Pretty printing objects */
-
-struct fmt
-{
- char *buf;
- int cap;
- int len;
- int indent;
- int tight;
- int col;
- int sep;
- int last;
-};
-
-static void fmt_obj(struct fmt *fmt, fz_obj *obj);
-
-static inline int iswhite(int ch)
-{
- return
- ch == '\000' ||
- ch == '\011' ||
- ch == '\012' ||
- ch == '\014' ||
- ch == '\015' ||
- ch == '\040';
-}
-
-static inline int isdelim(int ch)
-{
- return ch == '(' || ch == ')' ||
- ch == '<' || ch == '>' ||
- ch == '[' || ch == ']' ||
- ch == '{' || ch == '}' ||
- ch == '/' ||
- ch == '%';
-}
-
-static inline void fmt_putc(struct fmt *fmt, int c)
-{
- if (fmt->sep && !isdelim(fmt->last) && !isdelim(c)) {
- fmt->sep = 0;
- fmt_putc(fmt, ' ');
- }
- fmt->sep = 0;
-
- if (fmt->buf && fmt->len < fmt->cap)
- fmt->buf[fmt->len] = c;
-
- if (c == '\n')
- fmt->col = 0;
- else
- fmt->col ++;
-
- fmt->len ++;
-
- fmt->last = c;
-}
-
-static inline void fmt_indent(struct fmt *fmt)
-{
- int i = fmt->indent;
- while (i--) {
- fmt_putc(fmt, ' ');
- fmt_putc(fmt, ' ');
- }
-}
-
-static inline void fmt_puts(struct fmt *fmt, char *s)
-{
- while (*s)
- fmt_putc(fmt, *s++);
-}
-
-static inline void fmt_sep(struct fmt *fmt)
-{
- fmt->sep = 1;
-}
-
-static void fmt_str(struct fmt *fmt, fz_obj *obj)
-{
- char *s = fz_to_str_buf(obj);
- int n = fz_to_str_len(obj);
- int i, c;
-
- fmt_putc(fmt, '(');
- for (i = 0; i < n; i++)
- {
- c = (unsigned char)s[i];
- if (c == '\n')
- fmt_puts(fmt, "\\n");
- else if (c == '\r')
- fmt_puts(fmt, "\\r");
- else if (c == '\t')
- fmt_puts(fmt, "\\t");
- else if (c == '\b')
- fmt_puts(fmt, "\\b");
- else if (c == '\f')
- fmt_puts(fmt, "\\f");
- else if (c == '(')
- fmt_puts(fmt, "\\(");
- else if (c == ')')
- fmt_puts(fmt, "\\)");
- else if (c < 32 || c >= 127) {
- char buf[16];
- fmt_putc(fmt, '\\');
- sprintf(buf, "%03o", c);
- fmt_puts(fmt, buf);
- }
- else
- fmt_putc(fmt, c);
- }
- fmt_putc(fmt, ')');
-}
-
-static void fmt_hex(struct fmt *fmt, fz_obj *obj)
-{
- char *s = fz_to_str_buf(obj);
- int n = fz_to_str_len(obj);
- int i, b, c;
-
- fmt_putc(fmt, '<');
- for (i = 0; i < n; i++) {
- b = (unsigned char) s[i];
- c = (b >> 4) & 0x0f;
- fmt_putc(fmt, c < 0xA ? c + '0' : c + 'A' - 0xA);
- c = (b) & 0x0f;
- fmt_putc(fmt, c < 0xA ? c + '0' : c + 'A' - 0xA);
- }
- fmt_putc(fmt, '>');
-}
-
-static void fmt_name(struct fmt *fmt, fz_obj *obj)
-{
- unsigned char *s = (unsigned char *) fz_to_name(obj);
- int i, c;
-
- fmt_putc(fmt, '/');
-
- for (i = 0; s[i]; i++)
- {
- if (isdelim(s[i]) || iswhite(s[i]) ||
- s[i] == '#' || s[i] < 32 || s[i] >= 127)
- {
- fmt_putc(fmt, '#');
- c = (s[i] >> 4) & 0xf;
- fmt_putc(fmt, c < 0xA ? c + '0' : c + 'A' - 0xA);
- c = s[i] & 0xf;
- fmt_putc(fmt, c < 0xA ? c + '0' : c + 'A' - 0xA);
- }
- else
- {
- fmt_putc(fmt, s[i]);
- }
- }
-}
-
-static void fmt_array(struct fmt *fmt, fz_obj *obj)
-{
- int i, n;
-
- n = fz_array_len(obj);
- if (fmt->tight) {
- fmt_putc(fmt, '[');
- for (i = 0; i < n; i++) {
- fmt_obj(fmt, fz_array_get(obj, i));
- fmt_sep(fmt);
- }
- fmt_putc(fmt, ']');
- }
- else {
- fmt_puts(fmt, "[ ");
- for (i = 0; i < n; i++) {
- if (fmt->col > 60) {
- fmt_putc(fmt, '\n');
- fmt_indent(fmt);
- }
- fmt_obj(fmt, fz_array_get(obj, i));
- fmt_putc(fmt, ' ');
- }
- fmt_putc(fmt, ']');
- fmt_sep(fmt);
- }
-}
-
-static void fmt_dict(struct fmt *fmt, fz_obj *obj)
-{
- int i, n;
- fz_obj *key, *val;
-
- n = fz_dict_len(obj);
- if (fmt->tight) {
- fmt_puts(fmt, "<<");
- for (i = 0; i < n; i++) {
- fmt_obj(fmt, fz_dict_get_key(obj, i));
- fmt_sep(fmt);
- fmt_obj(fmt, fz_dict_get_val(obj, i));
- fmt_sep(fmt);
- }
- fmt_puts(fmt, ">>");
- }
- else {
- fmt_puts(fmt, "<<\n");
- fmt->indent ++;
- for (i = 0; i < n; i++) {
- key = fz_dict_get_key(obj, i);
- val = fz_dict_get_val(obj, i);
- fmt_indent(fmt);
- fmt_obj(fmt, key);
- fmt_putc(fmt, ' ');
- if (!fz_is_indirect(val) && fz_is_array(val))
- fmt->indent ++;
- fmt_obj(fmt, val);
- fmt_putc(fmt, '\n');
- if (!fz_is_indirect(val) && fz_is_array(val))
- fmt->indent --;
- }
- fmt->indent --;
- fmt_indent(fmt);
- fmt_puts(fmt, ">>");
- }
-}
-
-static void fmt_obj(struct fmt *fmt, fz_obj *obj)
-{
- char buf[256];
-
- if (!obj)
- fmt_puts(fmt, "<NULL>");
- else if (fz_is_indirect(obj))
- {
- sprintf(buf, "%d %d R", fz_to_num(obj), fz_to_gen(obj));
- fmt_puts(fmt, buf);
- }
- else if (fz_is_null(obj))
- fmt_puts(fmt, "null");
- else if (fz_is_bool(obj))
- fmt_puts(fmt, fz_to_bool(obj) ? "true" : "false");
- else if (fz_is_int(obj))
- {
- sprintf(buf, "%d", fz_to_int(obj));
- fmt_puts(fmt, buf);
- }
- else if (fz_is_real(obj))
- {
- sprintf(buf, "%g", fz_to_real(obj));
- if (strchr(buf, 'e')) /* bad news! */
- sprintf(buf, fabsf(fz_to_real(obj)) > 1 ? "%1.1f" : "%1.8f", fz_to_real(obj));
- fmt_puts(fmt, buf);
- }
- else if (fz_is_string(obj))
- {
- char *str = fz_to_str_buf(obj);
- int len = fz_to_str_len(obj);
- int added = 0;
- int i, c;
- for (i = 0; i < len; i++) {
- c = (unsigned char)str[i];
- if (strchr("()\\\n\r\t\b\f", c))
- added ++;
- else if (c < 32 || c >= 127)
- added += 3;
- }
- if (added < len)
- fmt_str(fmt, obj);
- else
- fmt_hex(fmt, obj);
- }
- else if (fz_is_name(obj))
- fmt_name(fmt, obj);
- else if (fz_is_array(obj))
- fmt_array(fmt, obj);
- else if (fz_is_dict(obj))
- fmt_dict(fmt, obj);
- else
- fmt_puts(fmt, "<unknown object>");
-}
-
-static int
-fz_sprint_obj(char *s, int n, fz_obj *obj, int tight)
-{
- struct fmt fmt;
-
- fmt.indent = 0;
- fmt.col = 0;
- fmt.sep = 0;
- fmt.last = 0;
-
- fmt.tight = tight;
- fmt.buf = s;
- fmt.cap = n;
- fmt.len = 0;
- fmt_obj(&fmt, obj);
-
- if (fmt.buf && fmt.len < fmt.cap)
- fmt.buf[fmt.len] = '\0';
-
- return fmt.len;
-}
-
-int
-fz_fprint_obj(FILE *fp, fz_obj *obj, int tight)
-{
- char buf[1024];
- char *ptr;
- int n;
-
- n = fz_sprint_obj(NULL, 0, obj, tight);
- if ((n + 1) < sizeof buf)
- {
- fz_sprint_obj(buf, sizeof buf, obj, tight);
- fputs(buf, fp);
- fputc('\n', fp);
- }
- else
- {
- ptr = fz_malloc(obj->ctx, n + 1);
- fz_sprint_obj(ptr, n + 1, obj, tight);
- fputs(ptr, fp);
- fputc('\n', fp);
- fz_free(obj->ctx, ptr);
- }
- return n;
-}
-
-void
-fz_debug_obj(fz_obj *obj)
-{
- fz_fprint_obj(stdout, obj, 0);
-}
-
-void
-fz_debug_ref(fz_obj *ref)
-{
- fz_debug_obj(fz_resolve_indirect(ref));
-}
diff --git a/fitz/base_string.c b/fitz/base_string.c
index dd9f8ea2..8ed08911 100644
--- a/fitz/base_string.c
+++ b/fitz/base_string.c
@@ -1,11 +1,4 @@
-#include "fitz.h"
-
-int
-fz_is_big_endian(void)
-{
- static const int one = 1;
- return *(char*)&one == 0;
-}
+#include "fitz-internal.h"
char *
fz_strsep(char **stringp, const char *delim)
@@ -36,8 +29,8 @@ fz_strlcpy(char *dst, const char *src, int siz)
if (n == 0) {
if (siz != 0)
*d = '\0'; /* NUL-terminate dst */
- while (*s++)
- ;
+ while (*s++)
+ ;
}
return(s - src - 1); /* count does not include NUL */
@@ -108,7 +101,7 @@ enum
};
int
-chartorune(int *rune, char *str)
+fz_chartorune(int *rune, char *str)
{
int c, c1, c2, c3;
long l;
@@ -183,16 +176,15 @@ bad:
}
int
-runetochar(char *str, int *rune)
+fz_runetochar(char *str, int rune)
{
/* Runes are signed, so convert to unsigned for range check. */
- unsigned long c;
+ unsigned long c = (unsigned long)rune;
/*
* one character sequence
* 00000-0007F => 00-7F
*/
- c = *rune;
if(c <= Rune1) {
str[0] = c;
return 1;
@@ -240,10 +232,10 @@ runetochar(char *str, int *rune)
}
int
-runelen(int c)
+fz_runelen(int c)
{
char str[10];
- return runetochar(str, &c);
+ return fz_runetochar(str, c);
}
float fz_atof(const char *s)
@@ -256,10 +248,11 @@ float fz_atof(const char *s)
* as we convert to a float. */
errno = 0;
d = strtod(s, NULL);
- if (errno == ERANGE || d > FLT_MAX || d < -FLT_MAX) {
+ if (errno == ERANGE || isnan(d)) {
/* Return 1.0, as it's a small known value that won't cause a
- * divide by 0. */
+ divide by 0. */
return 1.0;
}
+ d = CLAMP(d, -FLT_MAX, FLT_MAX);
return (float)d;
}
diff --git a/fitz/crypt_aes.c b/fitz/crypt_aes.c
index afdff0fe..4d8c4498 100644
--- a/fitz/crypt_aes.c
+++ b/fitz/crypt_aes.c
@@ -36,7 +36,7 @@
* http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf
*/
-#include "fitz.h"
+#include "fitz-internal.h"
#define aes_context fz_aes
diff --git a/fitz/crypt_arc4.c b/fitz/crypt_arc4.c
index 272891ce..596bf652 100644
--- a/fitz/crypt_arc4.c
+++ b/fitz/crypt_arc4.c
@@ -21,7 +21,7 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include "fitz.h"
+#include "fitz-internal.h"
void
fz_arc4_init(fz_arc4 *arc4, const unsigned char *key, unsigned keylen)
diff --git a/fitz/crypt_md5.c b/fitz/crypt_md5.c
index b6e06845..87c0909d 100644
--- a/fitz/crypt_md5.c
+++ b/fitz/crypt_md5.c
@@ -23,7 +23,7 @@ These notices must be retained in any copies of any part of this
documentation and/or software.
*/
-#include "fitz.h"
+#include "fitz-internal.h"
/* Constants for MD5Transform routine */
enum
diff --git a/fitz/crypt_sha2.c b/fitz/crypt_sha2.c
index f17146c6..64284cfa 100644
--- a/fitz/crypt_sha2.c
+++ b/fitz/crypt_sha2.c
@@ -7,7 +7,7 @@ This file has been put into the public domain.
You can do whatever you want with this file.
*/
-#include "fitz.h"
+#include "fitz-internal.h"
static inline int isbigendian(void)
{
diff --git a/fitz/dev_bbox.c b/fitz/dev_bbox.c
index 636ceb94..163780d0 100644
--- a/fitz/dev_bbox.c
+++ b/fitz/dev_bbox.c
@@ -1,4 +1,4 @@
-#include "fitz.h"
+#include "fitz-internal.h"
/* TODO: add clip stack and use to intersect bboxes */
@@ -47,7 +47,7 @@ fz_bbox_fill_shade(fz_device *dev, fz_shade *shade, fz_matrix ctm, float alpha)
}
static void
-fz_bbox_fill_image(fz_device *dev, fz_pixmap *image, fz_matrix ctm, float alpha)
+fz_bbox_fill_image(fz_device *dev, fz_image *image, fz_matrix ctm, float alpha)
{
fz_bbox *result = dev->user;
fz_bbox bbox = fz_round_rect(fz_transform_rect(ctm, fz_unit_rect));
@@ -55,7 +55,7 @@ fz_bbox_fill_image(fz_device *dev, fz_pixmap *image, fz_matrix ctm, float alpha)
}
static void
-fz_bbox_fill_image_mask(fz_device *dev, fz_pixmap *image, fz_matrix ctm,
+fz_bbox_fill_image_mask(fz_device *dev, fz_image *image, fz_matrix ctm,
fz_colorspace *colorspace, float *color, float alpha)
{
fz_bbox_fill_image(dev, image, ctm, alpha);
diff --git a/fitz/dev_list.c b/fitz/dev_list.c
index adc691d0..d0dfabc5 100644
--- a/fitz/dev_list.c
+++ b/fitz/dev_list.c
@@ -1,4 +1,4 @@
-#include "fitz.h"
+#include "fitz-internal.h"
typedef struct fz_display_node_s fz_display_node;
@@ -37,7 +37,7 @@ struct fz_display_node_s
fz_path *path;
fz_text *text;
fz_shade *shade;
- fz_pixmap *image;
+ fz_image *image;
int blendmode;
} item;
fz_stroke_state *stroke;
@@ -207,7 +207,7 @@ fz_free_display_node(fz_context *ctx, fz_display_node *node)
case FZ_CMD_FILL_IMAGE:
case FZ_CMD_FILL_IMAGE_MASK:
case FZ_CMD_CLIP_IMAGE_MASK:
- fz_drop_pixmap(ctx, node->item.image);
+ fz_drop_image(ctx, node->item.image);
break;
case FZ_CMD_POP_CLIP:
case FZ_CMD_BEGIN_MASK:
@@ -435,35 +435,35 @@ fz_list_fill_shade(fz_device *dev, fz_shade *shade, fz_matrix ctm, float alpha)
}
static void
-fz_list_fill_image(fz_device *dev, fz_pixmap *image, fz_matrix ctm, float alpha)
+fz_list_fill_image(fz_device *dev, fz_image *image, fz_matrix ctm, float alpha)
{
fz_display_node *node;
node = fz_new_display_node(dev->ctx, FZ_CMD_FILL_IMAGE, ctm, NULL, NULL, alpha);
node->rect = fz_transform_rect(ctm, fz_unit_rect);
- node->item.image = fz_keep_pixmap(dev->ctx, image);
+ node->item.image = fz_keep_image(dev->ctx, image);
fz_append_display_node(dev->user, node);
}
static void
-fz_list_fill_image_mask(fz_device *dev, fz_pixmap *image, fz_matrix ctm,
+fz_list_fill_image_mask(fz_device *dev, fz_image *image, fz_matrix ctm,
fz_colorspace *colorspace, float *color, float alpha)
{
fz_display_node *node;
node = fz_new_display_node(dev->ctx, FZ_CMD_FILL_IMAGE_MASK, ctm, colorspace, color, alpha);
node->rect = fz_transform_rect(ctm, fz_unit_rect);
- node->item.image = fz_keep_pixmap(dev->ctx, image);
+ node->item.image = fz_keep_image(dev->ctx, image);
fz_append_display_node(dev->user, node);
}
static void
-fz_list_clip_image_mask(fz_device *dev, fz_pixmap *image, fz_rect *rect, fz_matrix ctm)
+fz_list_clip_image_mask(fz_device *dev, fz_image *image, fz_rect *rect, fz_matrix ctm)
{
fz_display_node *node;
node = fz_new_display_node(dev->ctx, FZ_CMD_CLIP_IMAGE_MASK, ctm, NULL, NULL, 0);
node->rect = fz_transform_rect(ctm, fz_unit_rect);
if (rect)
node->rect = fz_intersect_rect(node->rect, *rect);
- node->item.image = fz_keep_pixmap(dev->ctx, image);
+ node->item.image = fz_keep_image(dev->ctx, image);
fz_append_display_node(dev->user, node);
}
diff --git a/fitz/dev_null.c b/fitz/dev_null.c
index b4ba5cbe..886cebe1 100644
--- a/fitz/dev_null.c
+++ b/fitz/dev_null.c
@@ -1,4 +1,4 @@
-#include "fitz.h"
+#include "fitz-internal.h"
fz_device *
fz_new_device(fz_context *ctx, void *user)
@@ -103,14 +103,14 @@ fz_fill_shade(fz_device *dev, fz_shade *shade, fz_matrix ctm, float alpha)
}
void
-fz_fill_image(fz_device *dev, fz_pixmap *image, fz_matrix ctm, float alpha)
+fz_fill_image(fz_device *dev, fz_image *image, fz_matrix ctm, float alpha)
{
if (dev->fill_image)
dev->fill_image(dev, image, ctm, alpha);
}
void
-fz_fill_image_mask(fz_device *dev, fz_pixmap *image, fz_matrix ctm,
+fz_fill_image_mask(fz_device *dev, fz_image *image, fz_matrix ctm,
fz_colorspace *colorspace, float *color, float alpha)
{
if (dev->fill_image_mask)
@@ -118,7 +118,7 @@ fz_fill_image_mask(fz_device *dev, fz_pixmap *image, fz_matrix ctm,
}
void
-fz_clip_image_mask(fz_device *dev, fz_pixmap *image, fz_rect *rect, fz_matrix ctm)
+fz_clip_image_mask(fz_device *dev, fz_image *image, fz_rect *rect, fz_matrix ctm)
{
if (dev->clip_image_mask)
dev->clip_image_mask(dev, image, rect, ctm);
diff --git a/fitz/dev_text.c b/fitz/dev_text.c
index d38fab21..7a059e5a 100644
--- a/fitz/dev_text.c
+++ b/fitz/dev_text.c
@@ -1,7 +1,8 @@
-#include "fitz.h"
+#include "fitz-internal.h"
#define LINE_DIST 0.9f
#define SPACE_DIST 0.2f
+#define PARAGRAPH_DIST 0.5f
#include <ft2build.h>
#include FT_FREETYPE_H
@@ -11,60 +12,211 @@ typedef struct fz_text_device_s fz_text_device;
struct fz_text_device_s
{
+ fz_text_sheet *sheet;
+ fz_text_page *page;
+ fz_text_line cur_line;
+ fz_text_span cur_span;
fz_point point;
- fz_text_span *head;
- fz_text_span *span;
};
-fz_text_span *
-fz_new_text_span(fz_context *ctx)
+fz_text_sheet *
+fz_new_text_sheet(fz_context *ctx)
{
- fz_text_span *span;
- span = fz_malloc_struct(ctx, fz_text_span);
- span->font = NULL;
- span->wmode = 0;
- span->size = 0;
- span->len = 0;
- span->cap = 0;
- span->text = NULL;
- span->next = NULL;
- span->eol = 0;
- return span;
+ fz_text_sheet *sheet = fz_malloc(ctx, sizeof *sheet);
+ sheet->maxid = 0;
+ sheet->style = NULL;
+ return sheet;
}
void
-fz_free_text_span(fz_context *ctx, fz_text_span *span)
+fz_free_text_sheet(fz_context *ctx, fz_text_sheet *sheet)
+{
+ fz_text_style *style = sheet->style;
+ while (style)
+ {
+ fz_text_style *next = style->next;
+ fz_drop_font(ctx, style->font);
+ fz_free(ctx, style);
+ style = next;
+ }
+}
+
+static fz_text_style *
+fz_lookup_text_style_imp(fz_context *ctx, fz_text_sheet *sheet,
+ float size, fz_font *font, int wmode, int script)
+{
+ fz_text_style *style;
+
+ for (style = sheet->style; style; style = style->next)
+ {
+ if (style->font == font &&
+ style->size == size &&
+ style->wmode == wmode &&
+ style->script == script) /* FIXME: others */
+ {
+ return style;
+ }
+ }
+
+ /* Better make a new one and add it to our list */
+ style = fz_malloc(ctx, sizeof *style);
+ style->id = sheet->maxid++;
+ style->font = fz_keep_font(ctx, font);
+ style->size = size;
+ style->wmode = wmode;
+ style->script = script;
+ style->next = sheet->style;
+ sheet->style = style;
+ return style;
+}
+
+static fz_text_style *
+fz_lookup_text_style(fz_context *ctx, fz_text_sheet *sheet, fz_text *text, fz_matrix *ctm,
+ fz_colorspace *colorspace, float *color, float alpha, fz_stroke_state *stroke)
{
- fz_text_span *next;
+ float size = 1.0f;
+ fz_font *font = text ? text->font : NULL;
+ int wmode = text ? text->wmode : 0;
+ if (ctm && text)
+ {
+ fz_matrix tm = text->trm;
+ fz_matrix trm;
+ tm.e = 0;
+ tm.f = 0;
+ trm = fz_concat(tm, *ctm);
+ size = fz_matrix_expansion(trm);
+ }
+ return fz_lookup_text_style_imp(ctx, sheet, size, font, wmode, 0);
+}
- while (span)
+fz_text_page *
+fz_new_text_page(fz_context *ctx, fz_rect mediabox)
+{
+ fz_text_page *page = fz_malloc(ctx, sizeof(*page));
+ page->mediabox = mediabox;
+ page->len = 0;
+ page->cap = 0;
+ page->blocks = NULL;
+ return page;
+}
+
+void
+fz_free_text_page(fz_context *ctx, fz_text_page *page)
+{
+ fz_text_block *block;
+ fz_text_line *line;
+ fz_text_span *span;
+ for (block = page->blocks; block < page->blocks + page->len; block++)
{
- if (span->font)
- fz_drop_font(ctx, span->font);
- next = span->next;
- fz_free(ctx, span->text);
- fz_free(ctx, span);
- span = next;
+ for (line = block->lines; line < block->lines + block->len; line++)
+ {
+ for (span = line->spans; span < line->spans + line->len; span++)
+ {
+ fz_free(ctx, span->text);
+ }
+ fz_free(ctx, line->spans);
+ }
+ fz_free(ctx, block->lines);
}
+ fz_free(ctx, page->blocks);
+ fz_free(ctx, page);
}
static void
-fz_add_text_char_imp(fz_context *ctx, fz_text_span *span, int c, fz_bbox bbox)
+append_char(fz_context *ctx, fz_text_span *span, int c, fz_rect bbox)
{
- if (span->len + 1 >= span->cap)
+ if (span->len == span->cap)
{
- span->cap = span->cap > 1 ? (span->cap * 3) / 2 : 80;
- span->text = fz_resize_array(ctx, span->text, span->cap, sizeof(fz_text_char));
+ span->cap = MAX(64, span->cap * 2);
+ span->text = fz_resize_array(ctx, span->text, span->cap, sizeof(*span->text));
}
+ span->bbox = fz_union_rect(span->bbox, bbox);
span->text[span->len].c = c;
span->text[span->len].bbox = bbox;
- span->len ++;
+ span->len++;
+}
+
+static void
+init_span(fz_context *ctx, fz_text_span *span, fz_text_style *style)
+{
+ span->style = style;
+ span->bbox = fz_empty_rect;
+ span->len = span->cap = 0;
+ span->text = NULL;
+}
+
+static void
+append_span(fz_context *ctx, fz_text_line *line, fz_text_span *span)
+{
+ if (line->len == line->cap)
+ {
+ line->cap = MAX(8, line->cap * 2);
+ line->spans = fz_resize_array(ctx, line->spans, line->cap, sizeof(*line->spans));
+ }
+ line->bbox = fz_union_rect(line->bbox, span->bbox);
+ line->spans[line->len++] = *span;
}
-static fz_bbox
-fz_split_bbox(fz_bbox bbox, int i, int n)
+static void
+init_line(fz_context *ctx, fz_text_line *line)
+{
+ line->bbox = fz_empty_rect;
+ line->len = line->cap = 0;
+ line->spans = NULL;
+}
+
+static void
+append_line(fz_context *ctx, fz_text_block *block, fz_text_line *line)
{
- float w = (float)(bbox.x1 - bbox.x0) / n;
+ if (block->len == block->cap)
+ {
+ block->cap = MAX(16, block->cap * 2);
+ block->lines = fz_resize_array(ctx, block->lines, block->cap, sizeof *block->lines);
+ }
+ block->bbox = fz_union_rect(block->bbox, line->bbox);
+ block->lines[block->len++] = *line;
+}
+
+static fz_text_block *
+lookup_block_for_line(fz_context *ctx, fz_text_page *page, fz_text_line *line)
+{
+ float size = line->len > 0 && line->spans[0].len > 0 ? line->spans[0].style->size : 1;
+ int i;
+
+ for (i = 0; i < page->len; i++)
+ {
+ fz_text_block *block = page->blocks + i;
+ int w = block->bbox.x1 - block->bbox.x0;
+ if (block->bbox.y0 - line->bbox.y1 < size * PARAGRAPH_DIST)
+ if (line->bbox.x0 < block->bbox.x1 && line->bbox.x1 > block->bbox.x0)
+ if (ABS(line->bbox.x0 - block->bbox.x0) < w / 4)
+ return block;
+ }
+
+ if (page->len == page->cap)
+ {
+ page->cap = MAX(16, page->cap * 2);
+ page->blocks = fz_resize_array(ctx, page->blocks, page->cap, sizeof(*page->blocks));
+ }
+
+ page->blocks[page->len].bbox = fz_empty_rect;
+ page->blocks[page->len].len = 0;
+ page->blocks[page->len].cap = 0;
+ page->blocks[page->len].lines = NULL;
+
+ return &page->blocks[page->len++];
+}
+
+static void
+insert_line(fz_context *ctx, fz_text_page *page, fz_text_line *line)
+{
+ append_line(ctx, lookup_block_for_line(ctx, page, line), line);
+}
+
+static fz_rect
+fz_split_bbox(fz_rect bbox, int i, int n)
+{
+ float w = (bbox.x1 - bbox.x0) / n;
float x0 = bbox.x0;
bbox.x0 = x0 + i * w;
bbox.x1 = x0 + (i + 1) * w;
@@ -72,154 +224,71 @@ fz_split_bbox(fz_bbox bbox, int i, int n)
}
static void
-fz_add_text_char(fz_context *ctx, fz_text_span **last, fz_font *font, float size, int wmode, int c, fz_bbox bbox)
+fz_flush_text_line(fz_context *ctx, fz_text_device *dev, fz_text_style *style)
{
- fz_text_span *span = *last;
-
- if (!span->font)
- {
- span->font = fz_keep_font(ctx, font);
- span->size = size;
- }
+ append_span(ctx, &dev->cur_line, &dev->cur_span);
+ insert_line(ctx, dev->page, &dev->cur_line);
+ init_span(ctx, &dev->cur_span, style);
+ init_line(ctx, &dev->cur_line);
+}
- if ((span->font != font || span->size != size || span->wmode != wmode) && c != 32)
+static void
+fz_add_text_char_imp(fz_context *ctx, fz_text_device *dev, fz_text_style *style, int c, fz_rect bbox)
+{
+ if (!dev->cur_span.style)
+ dev->cur_span.style = style;
+ if (style != dev->cur_span.style)
{
- span = fz_new_text_span(ctx);
- span->font = fz_keep_font(ctx, font);
- span->size = size;
- span->wmode = wmode;
- (*last)->next = span;
- *last = span;
+ append_span(ctx, &dev->cur_line, &dev->cur_span);
+ init_span(ctx, &dev->cur_span, style);
}
+ append_char(ctx, &dev->cur_span, c, bbox);
+}
+static void
+fz_add_text_char(fz_context *ctx, fz_text_device *dev, fz_text_style *style, int c, fz_rect bbox)
+{
switch (c)
{
case -1: /* ignore when one unicode character maps to multiple glyphs */
break;
case 0xFB00: /* ff */
- fz_add_text_char_imp(ctx, span, 'f', fz_split_bbox(bbox, 0, 2));
- fz_add_text_char_imp(ctx, span, 'f', fz_split_bbox(bbox, 1, 2));
+ fz_add_text_char_imp(ctx, dev, style, 'f', fz_split_bbox(bbox, 0, 2));
+ fz_add_text_char_imp(ctx, dev, style, 'f', fz_split_bbox(bbox, 1, 2));
break;
case 0xFB01: /* fi */
- fz_add_text_char_imp(ctx, span, 'f', fz_split_bbox(bbox, 0, 2));
- fz_add_text_char_imp(ctx, span, 'i', fz_split_bbox(bbox, 1, 2));
+ fz_add_text_char_imp(ctx, dev, style, 'f', fz_split_bbox(bbox, 0, 2));
+ fz_add_text_char_imp(ctx, dev, style, 'i', fz_split_bbox(bbox, 1, 2));
break;
case 0xFB02: /* fl */
- fz_add_text_char_imp(ctx, span, 'f', fz_split_bbox(bbox, 0, 2));
- fz_add_text_char_imp(ctx, span, 'l', fz_split_bbox(bbox, 1, 2));
+ fz_add_text_char_imp(ctx, dev, style, 'f', fz_split_bbox(bbox, 0, 2));
+ fz_add_text_char_imp(ctx, dev, style, 'l', fz_split_bbox(bbox, 1, 2));
break;
case 0xFB03: /* ffi */
- fz_add_text_char_imp(ctx, span, 'f', fz_split_bbox(bbox, 0, 3));
- fz_add_text_char_imp(ctx, span, 'f', fz_split_bbox(bbox, 1, 3));
- fz_add_text_char_imp(ctx, span, 'i', fz_split_bbox(bbox, 2, 3));
+ fz_add_text_char_imp(ctx, dev, style, 'f', fz_split_bbox(bbox, 0, 3));
+ fz_add_text_char_imp(ctx, dev, style, 'f', fz_split_bbox(bbox, 1, 3));
+ fz_add_text_char_imp(ctx, dev, style, 'i', fz_split_bbox(bbox, 2, 3));
break;
case 0xFB04: /* ffl */
- fz_add_text_char_imp(ctx, span, 'f', fz_split_bbox(bbox, 0, 3));
- fz_add_text_char_imp(ctx, span, 'f', fz_split_bbox(bbox, 1, 3));
- fz_add_text_char_imp(ctx, span, 'l', fz_split_bbox(bbox, 2, 3));
+ fz_add_text_char_imp(ctx, dev, style, 'f', fz_split_bbox(bbox, 0, 3));
+ fz_add_text_char_imp(ctx, dev, style, 'f', fz_split_bbox(bbox, 1, 3));
+ fz_add_text_char_imp(ctx, dev, style, 'l', fz_split_bbox(bbox, 2, 3));
break;
case 0xFB05: /* long st */
case 0xFB06: /* st */
- fz_add_text_char_imp(ctx, span, 's', fz_split_bbox(bbox, 0, 2));
- fz_add_text_char_imp(ctx, span, 't', fz_split_bbox(bbox, 1, 2));
+ fz_add_text_char_imp(ctx, dev, style, 's', fz_split_bbox(bbox, 0, 2));
+ fz_add_text_char_imp(ctx, dev, style, 't', fz_split_bbox(bbox, 1, 2));
break;
default:
- fz_add_text_char_imp(ctx, span, c, bbox);
+ fz_add_text_char_imp(ctx, dev, style, c, bbox);
break;
}
}
static void
-fz_divide_text_chars(fz_text_span **last, int n, fz_bbox bbox)
-{
- fz_text_span *span = *last;
- int i, x;
- x = span->len - n;
- if (x >= 0)
- for (i = 0; i < n; i++)
- span->text[x + i].bbox = fz_split_bbox(bbox, i, n);
-}
-
-static void
-fz_add_text_newline(fz_context *ctx, fz_text_span **last, fz_font *font, float size, int wmode)
-{
- fz_text_span *span;
- span = fz_new_text_span(ctx);
- span->font = fz_keep_font(ctx, font);
- span->size = size;
- span->wmode = wmode;
- (*last)->eol = 1;
- (*last)->next = span;
- *last = span;
-}
-
-void
-fz_debug_text_span_xml(fz_text_span *span)
-{
- char buf[10];
- int c, n, k, i;
-
- while (span)
- {
- printf("<span font=\"%s\" size=\"%g\" wmode=\"%d\" eol=\"%d\">\n",
- span->font ? span->font->name : "NULL", span->size, span->wmode, span->eol);
-
- for (i = 0; i < span->len; i++)
- {
- printf("\t<char ucs=\"");
- c = span->text[i].c;
- if (c < 128)
- putchar(c);
- else
- {
- n = runetochar(buf, &c);
- for (k = 0; k < n; k++)
- putchar(buf[k]);
- }
- printf("\" bbox=\"%d %d %d %d\" />\n",
- span->text[i].bbox.x0,
- span->text[i].bbox.y0,
- span->text[i].bbox.x1,
- span->text[i].bbox.y1);
- }
-
- printf("</span>\n");
-
- span = span->next;
- }
-}
-
-void
-fz_debug_text_span(fz_text_span *span)
-{
- char buf[10];
- int c, n, k, i;
-
- while (span)
- {
- for (i = 0; i < span->len; i++)
- {
- c = span->text[i].c;
- if (c < 128)
- putchar(c);
- else
- {
- n = runetochar(buf, &c);
- for (k = 0; k < n; k++)
- putchar(buf[k]);
- }
- }
-
- if (span->eol)
- putchar('\n');
-
- span = span->next;
- }
-}
-
-static void
-fz_text_extract_span(fz_context *ctx, fz_text_span **last, fz_text *text, fz_matrix ctm, fz_point *pen)
+fz_text_extract(fz_context *ctx, fz_text_device *dev, fz_text *text, fz_matrix ctm, fz_text_style *style)
{
+ fz_point *pen = &dev->point;
fz_font *font = text->font;
FT_Face face = font->ft_face;
fz_matrix tm = text->trm;
@@ -233,19 +302,21 @@ fz_text_extract_span(fz_context *ctx, fz_text_span **last, fz_text *text, fz_mat
float ascender = 1;
float descender = 0;
int multi;
- int i, err;
+ int i, j, err;
+ int lastchar = ' ';
if (text->len == 0)
return;
- fz_lock(ctx, FZ_LOCK_FREETYPE);
if (font->ft_face)
{
+ fz_lock(ctx, FZ_LOCK_FREETYPE);
err = FT_Set_Char_Size(font->ft_face, 64, 64, 72, 72);
if (err)
fz_warn(ctx, "freetype set character size: %s", ft_error_string(err));
ascender = (float)face->ascender / face->units_per_EM;
descender = (float)face->descender / face->units_per_EM;
+ fz_unlock(ctx, FZ_LOCK_FREETYPE);
}
rect = fz_empty_rect;
@@ -264,6 +335,7 @@ fz_text_extract_span(fz_context *ctx, fz_text_span **last, fz_text *text, fz_mat
tm.e = 0;
tm.f = 0;
trm = fz_concat(tm, ctm);
+
dir = fz_transform_vector(trm, dir);
dist = sqrtf(dir.x * dir.x + dir.y * dir.y);
ndir.x = dir.x / dist;
@@ -271,19 +343,8 @@ fz_text_extract_span(fz_context *ctx, fz_text_span **last, fz_text *text, fz_mat
size = fz_matrix_expansion(trm);
- multi = 1;
-
for (i = 0; i < text->len; i++)
{
- if (text->items[i].gid < 0)
- {
- fz_add_text_char(ctx, last, font, size, text->wmode, text->items[i].ucs, fz_round_rect(rect));
- multi ++;
- fz_divide_text_chars(last, multi, fz_round_rect(rect));
- continue;
- }
- multi = 1;
-
/* Calculate new pen location and delta */
tm.e = text->items[i].x;
tm.f = text->items[i].y;
@@ -305,20 +366,19 @@ fz_text_extract_span(fz_context *ctx, fz_text_span **last, fz_text *text, fz_mat
if (dist > size * LINE_DIST)
{
- fz_add_text_newline(ctx, last, font, size, text->wmode);
+ fz_flush_text_line(ctx, dev, style);
+ lastchar = ' ';
}
- else if (fabsf(dot) > 0.95f && dist > size * SPACE_DIST)
+ else if (fabsf(dot) > 0.95f && dist > size * SPACE_DIST && lastchar != ' ')
{
- if ((*last)->len > 0 && (*last)->text[(*last)->len - 1].c != ' ')
- {
- fz_rect spacerect;
- spacerect.x0 = -0.2f;
- spacerect.y0 = 0;
- spacerect.x1 = 0;
- spacerect.y1 = 1;
- spacerect = fz_transform_rect(trm, spacerect);
- fz_add_text_char(ctx, last, font, size, text->wmode, ' ', fz_round_rect(spacerect));
- }
+ fz_rect spacerect;
+ spacerect.x0 = -0.2f;
+ spacerect.y0 = 0;
+ spacerect.x1 = 0;
+ spacerect.y1 = 1;
+ spacerect = fz_transform_rect(trm, spacerect);
+ fz_add_text_char(ctx, dev, style, ' ', spacerect);
+ lastchar = ' ';
}
}
@@ -331,8 +391,13 @@ fz_text_extract_span(fz_context *ctx, fz_text_span **last, fz_text *text, fz_mat
/* TODO: freetype returns broken vertical metrics */
/* if (text->wmode) mask |= FT_LOAD_VERTICAL_LAYOUT; */
+ fz_lock(ctx, FZ_LOCK_FREETYPE);
+ err = FT_Set_Char_Size(font->ft_face, 64, 64, 72, 72);
+ if (err)
+ fz_warn(ctx, "freetype set character size: %s", ft_error_string(err));
FT_Get_Advance(font->ft_face, text->items[i].gid, mask, &ftadv);
adv = ftadv / 65536.0f;
+ fz_unlock(ctx, FZ_LOCK_FREETYPE);
rect.x0 = 0;
rect.y0 = descender;
@@ -352,9 +417,27 @@ fz_text_extract_span(fz_context *ctx, fz_text_span **last, fz_text *text, fz_mat
pen->x = trm.e + dir.x * adv;
pen->y = trm.f + dir.y * adv;
- fz_add_text_char(ctx, last, font, size, text->wmode, text->items[i].ucs, fz_round_rect(rect));
+ /* Check for one glyph to many char mapping */
+ for (j = i + 1; j < text->len; j++)
+ if (text->items[j].gid >= 0)
+ break;
+ multi = j - i;
+
+ if (multi == 1)
+ {
+ fz_add_text_char(ctx, dev, style, text->items[i].ucs, rect);
+ }
+ else
+ {
+ for (j = 0; j < multi; j++)
+ {
+ fz_rect part = fz_split_bbox(rect, j, multi);
+ fz_add_text_char(ctx, dev, style, text->items[i].ucs, part);
+ }
+ }
+
+ lastchar = text->items[i].ucs;
}
- fz_unlock(ctx, FZ_LOCK_FREETYPE);
}
static void
@@ -362,7 +445,9 @@ fz_text_fill_text(fz_device *dev, fz_text *text, fz_matrix ctm,
fz_colorspace *colorspace, float *color, float alpha)
{
fz_text_device *tdev = dev->user;
- fz_text_extract_span(dev->ctx, &tdev->span, text, ctm, &tdev->point);
+ fz_text_style *style;
+ style = fz_lookup_text_style(dev->ctx, tdev->sheet, text, &ctm, colorspace, color, alpha, NULL);
+ fz_text_extract(dev->ctx, tdev, text, ctm, style);
}
static void
@@ -370,36 +455,57 @@ fz_text_stroke_text(fz_device *dev, fz_text *text, fz_stroke_state *stroke, fz_m
fz_colorspace *colorspace, float *color, float alpha)
{
fz_text_device *tdev = dev->user;
- fz_text_extract_span(dev->ctx, &tdev->span, text, ctm, &tdev->point);
+ fz_text_style *style;
+ style = fz_lookup_text_style(dev->ctx, tdev->sheet, text, &ctm, colorspace, color, alpha, stroke);
+ fz_text_extract(dev->ctx, tdev, text, ctm, style);
}
static void
fz_text_clip_text(fz_device *dev, fz_text *text, fz_matrix ctm, int accumulate)
{
fz_text_device *tdev = dev->user;
- fz_text_extract_span(dev->ctx, &tdev->span, text, ctm, &tdev->point);
+ fz_text_style *style;
+ style = fz_lookup_text_style(dev->ctx, tdev->sheet, text, &ctm, NULL, NULL, 0, NULL);
+ fz_text_extract(dev->ctx, tdev, text, ctm, style);
}
static void
fz_text_clip_stroke_text(fz_device *dev, fz_text *text, fz_stroke_state *stroke, fz_matrix ctm)
{
fz_text_device *tdev = dev->user;
- fz_text_extract_span(dev->ctx, &tdev->span, text, ctm, &tdev->point);
+ fz_text_style *style;
+ style = fz_lookup_text_style(dev->ctx, tdev->sheet, text, &ctm, NULL, NULL, 0, stroke);
+ fz_text_extract(dev->ctx, tdev, text, ctm, style);
}
static void
fz_text_ignore_text(fz_device *dev, fz_text *text, fz_matrix ctm)
{
fz_text_device *tdev = dev->user;
- fz_text_extract_span(dev->ctx, &tdev->span, text, ctm, &tdev->point);
+ fz_text_style *style;
+ style = fz_lookup_text_style(dev->ctx, tdev->sheet, text, &ctm, NULL, NULL, 0, NULL);
+ fz_text_extract(dev->ctx, tdev, text, ctm, style);
+}
+
+static int cmp_block(const void *av, const void *bv)
+{
+ const fz_text_block *a = av;
+ const fz_text_block *b = bv;
+ int x = a->bbox.x0 - b->bbox.x0;
+ if (x) return x;
+ return -(a->bbox.y0 - b->bbox.y0);
}
static void
fz_text_free_user(fz_device *dev)
{
+ fz_context *ctx = dev->ctx;
fz_text_device *tdev = dev->user;
- tdev->span->eol = 1;
+ append_span(ctx, &tdev->cur_line, &tdev->cur_span);
+ insert_line(ctx, tdev->page, &tdev->cur_line);
+
+ qsort(tdev->page->blocks, tdev->page->len, sizeof *tdev->page->blocks, cmp_block);
/* TODO: unicode NFC normalization */
/* TODO: bidi logical reordering */
@@ -408,15 +514,19 @@ fz_text_free_user(fz_device *dev)
}
fz_device *
-fz_new_text_device(fz_context *ctx, fz_text_span *root)
+fz_new_text_device(fz_context *ctx, fz_text_sheet *sheet, fz_text_page *page)
{
fz_device *dev;
+
fz_text_device *tdev = fz_malloc_struct(ctx, fz_text_device);
- tdev->head = root;
- tdev->span = root;
+ tdev->sheet = sheet;
+ tdev->page = page;
tdev->point.x = -1;
tdev->point.y = -1;
+ init_line(ctx, &tdev->cur_line);
+ init_span(ctx, &tdev->cur_span, NULL);
+
dev = fz_new_device(ctx, tdev);
dev->hints = FZ_IGNORE_IMAGE | FZ_IGNORE_SHADE;
dev->free_user = fz_text_free_user;
@@ -427,3 +537,209 @@ fz_new_text_device(fz_context *ctx, fz_text_span *root)
dev->ignore_text = fz_text_ignore_text;
return dev;
}
+
+/* XML, HTML and plain-text output */
+
+static int font_is_bold(fz_font *font)
+{
+ FT_Face face = font->ft_face;
+ if (face && (face->style_flags & FT_STYLE_FLAG_BOLD))
+ return 1;
+ if (strstr(font->name, "Bold"))
+ return 1;
+ return 0;
+}
+
+static int font_is_italic(fz_font *font)
+{
+ FT_Face face = font->ft_face;
+ if (face && (face->style_flags & FT_STYLE_FLAG_ITALIC))
+ return 1;
+ if (strstr(font->name, "Italic") || strstr(font->name, "Oblique"))
+ return 1;
+ return 0;
+}
+
+static void
+fz_print_style_begin(FILE *out, fz_text_style *style)
+{
+ int script = style->script;
+ fprintf(out, "<span class=\"s%d\">", style->id);
+ while (script-- > 0)
+ fprintf(out, "<sup>");
+ while (++script < 0)
+ fprintf(out, "<sub>");
+}
+
+static void
+fz_print_style_end(FILE *out, fz_text_style *style)
+{
+ int script = style->script;
+ while (script-- > 0)
+ fprintf(out, "</sup>");
+ while (++script < 0)
+ fprintf(out, "</sub>");
+ fprintf(out, "</span>");
+}
+
+static void
+fz_print_style(FILE *out, fz_text_style *style)
+{
+ char *s = strchr(style->font->name, '+');
+ s = s ? s + 1 : style->font->name;
+ fprintf(out, "span.s%d{font-family:\"%s\";font-size:%gpt;",
+ style->id, s, style->size);
+ if (font_is_italic(style->font))
+ fprintf(out, "font-style:italic;");
+ if (font_is_bold(style->font))
+ fprintf(out, "font-weight:bold;");
+ fprintf(out, "}\n");
+}
+
+void
+fz_print_text_sheet(fz_context *ctx, FILE *out, fz_text_sheet *sheet)
+{
+ fz_text_style *style;
+ for (style = sheet->style; style; style = style->next)
+ fz_print_style(out, style);
+}
+
+void
+fz_print_text_page_html(fz_context *ctx, FILE *out, fz_text_page *page)
+{
+ int block_n, line_n, span_n, ch_n;
+ fz_text_style *style = NULL;
+ fz_text_block *block;
+ fz_text_line *line;
+ fz_text_span *span;
+
+ fprintf(out, "<div class=\"page\">\n");
+
+ for (block_n = 0; block_n < page->len; block_n++)
+ {
+ block = &page->blocks[block_n];
+ fprintf(out, "<div class=\"block\">\n");
+ for (line_n = 0; line_n < block->len; line_n++)
+ {
+ line = &block->lines[line_n];
+ fprintf(out, "<p>");
+ style = NULL;
+
+ for (span_n = 0; span_n < line->len; span_n++)
+ {
+ span = &line->spans[span_n];
+ if (style != span->style)
+ {
+ if (style != NULL)
+ fz_print_style_end(out, style);
+ fz_print_style_begin(out, span->style);
+ style = span->style;
+ }
+
+ for (ch_n = 0; ch_n < span->len; ch_n++)
+ {
+ fz_text_char *ch = &span->text[ch_n];
+ if (ch->c == '<')
+ fprintf(out, "&lt;");
+ else if (ch->c == '>')
+ fprintf(out, "&gt;");
+ else if (ch->c == '&')
+ fprintf(out, "&amp;");
+ else if (ch->c >= 32 && ch->c <= 127)
+ fprintf(out, "%c", ch->c);
+ else
+ fprintf(out, "&#x%x;", ch->c);
+ }
+ }
+ fz_print_style_end(out, style);
+ fprintf(out, "</p>\n");
+ }
+ fprintf(out, "</div>\n");
+ }
+
+ fprintf(out, "</div>\n");
+}
+
+void
+fz_print_text_page_xml(fz_context *ctx, FILE *out, fz_text_page *page)
+{
+ fz_text_block *block;
+ fz_text_line *line;
+ fz_text_span *span;
+ fz_text_char *ch;
+ char *s;
+
+ fprintf(out, "<page>\n");
+ for (block = page->blocks; block < page->blocks + page->len; block++)
+ {
+ fprintf(out, "<block bbox=\"%g %g %g %g\">\n",
+ block->bbox.x0, block->bbox.y0, block->bbox.x1, block->bbox.y1);
+ for (line = block->lines; line < block->lines + block->len; line++)
+ {
+ fprintf(out, "<line bbox=\"%g %g %g %g\">\n",
+ line->bbox.x0, line->bbox.y0, line->bbox.x1, line->bbox.y1);
+ for (span = line->spans; span < line->spans + line->len; span++)
+ {
+ fz_text_style *style = span->style;
+ s = strchr(style->font->name, '+');
+ s = s ? s + 1 : style->font->name;
+ fprintf(out, "<span bbox=\"%g %g %g %g\" font=\"%s\" size=\"%g\">\n",
+ span->bbox.x0, span->bbox.y0, span->bbox.x1, span->bbox.y1,
+ s, style->size);
+ for (ch = span->text; ch < span->text + span->len; ch++)
+ {
+ fprintf(out, "<char bbox=\"%g %g %g %g\" c=\"",
+ ch->bbox.x0, ch->bbox.y0, ch->bbox.x1, ch->bbox.y1);
+ switch (ch->c)
+ {
+ case '<': fprintf(out, "&lt;"); break;
+ case '>': fprintf(out, "&gt;"); break;
+ case '&': fprintf(out, "&amp;"); break;
+ case '"': fprintf(out, "&quot;"); break;
+ case '\'': fprintf(out, "&apos;"); break;
+ default:
+ if (ch->c >= 32 && ch->c <= 127)
+ fprintf(out, "%c", ch->c);
+ else
+ fprintf(out, "&#x%x;", ch->c);
+ break;
+ }
+ fprintf(out, "\"/>\n");
+ }
+ fprintf(out, "</span>\n");
+ }
+ fprintf(out, "</line>\n");
+ }
+ fprintf(out, "</block>\n");
+ }
+ fprintf(out, "</page>\n");
+}
+
+void
+fz_print_text_page(fz_context *ctx, FILE *out, fz_text_page *page)
+{
+ fz_text_block *block;
+ fz_text_line *line;
+ fz_text_span *span;
+ fz_text_char *ch;
+ char utf[10];
+ int i, n;
+
+ for (block = page->blocks; block < page->blocks + page->len; block++)
+ {
+ for (line = block->lines; line < block->lines + block->len; line++)
+ {
+ for (span = line->spans; span < line->spans + line->len; span++)
+ {
+ for (ch = span->text; ch < span->text + span->len; ch++)
+ {
+ n = fz_runetochar(utf, ch->c);
+ for (i = 0; i < n; i++)
+ putc(utf[i], out);
+ }
+ }
+ fprintf(out, "\n");
+ }
+ fprintf(out, "\n");
+ }
+}
diff --git a/fitz/dev_trace.c b/fitz/dev_trace.c
index 1c2e1ed1..b3c73ff2 100644
--- a/fitz/dev_trace.c
+++ b/fitz/dev_trace.c
@@ -1,4 +1,4 @@
-#include "fitz.h"
+#include "fitz-internal.h"
static void
fz_trace_matrix(fz_matrix ctm)
@@ -145,7 +145,7 @@ fz_trace_fill_text(fz_device *dev, fz_text *text, fz_matrix ctm,
fz_trace_matrix(ctm);
fz_trace_trm(text->trm);
printf(">\n");
- fz_debug_text(dev->ctx, text, 0);
+ fz_print_text(dev->ctx, stdout, text);
printf("</fill_text>\n");
}
@@ -158,7 +158,7 @@ fz_trace_stroke_text(fz_device *dev, fz_text *text, fz_stroke_state *stroke, fz_
fz_trace_matrix(ctm);
fz_trace_trm(text->trm);
printf(">\n");
- fz_debug_text(dev->ctx, text, 0);
+ fz_print_text(dev->ctx, stdout, text);
printf("</stroke_text>\n");
}
@@ -170,7 +170,7 @@ fz_trace_clip_text(fz_device *dev, fz_text *text, fz_matrix ctm, int accumulate)
fz_trace_matrix(ctm);
fz_trace_trm(text->trm);
printf(">\n");
- fz_debug_text(dev->ctx, text, 0);
+ fz_print_text(dev->ctx, stdout, text);
printf("</clip_text>\n");
}
@@ -181,7 +181,7 @@ fz_trace_clip_stroke_text(fz_device *dev, fz_text *text, fz_stroke_state *stroke
fz_trace_matrix(ctm);
fz_trace_trm(text->trm);
printf(">\n");
- fz_debug_text(dev->ctx, text, 0);
+ fz_print_text(dev->ctx, stdout, text);
printf("</clip_stroke_text>\n");
}
@@ -192,12 +192,12 @@ fz_trace_ignore_text(fz_device *dev, fz_text *text, fz_matrix ctm)
fz_trace_matrix(ctm);
fz_trace_trm(text->trm);
printf(">\n");
- fz_debug_text(dev->ctx, text, 0);
+ fz_print_text(dev->ctx, stdout, text);
printf("</ignore_text>\n");
}
static void
-fz_trace_fill_image(fz_device *dev, fz_pixmap *image, fz_matrix ctm, float alpha)
+fz_trace_fill_image(fz_device *dev, fz_image *image, fz_matrix ctm, float alpha)
{
printf("<fill_image alpha=\"%g\" ", alpha);
fz_trace_matrix(ctm);
@@ -213,7 +213,7 @@ fz_trace_fill_shade(fz_device *dev, fz_shade *shade, fz_matrix ctm, float alpha)
}
static void
-fz_trace_fill_image_mask(fz_device *dev, fz_pixmap *image, fz_matrix ctm,
+fz_trace_fill_image_mask(fz_device *dev, fz_image *image, fz_matrix ctm,
fz_colorspace *colorspace, float *color, float alpha)
{
printf("<fill_image_mask ");
@@ -223,7 +223,7 @@ fz_colorspace *colorspace, float *color, float alpha)
}
static void
-fz_trace_clip_image_mask(fz_device *dev, fz_pixmap *image, fz_rect *rect, fz_matrix ctm)
+fz_trace_clip_image_mask(fz_device *dev, fz_image *image, fz_rect *rect, fz_matrix ctm)
{
printf("<clip_image_mask ");
fz_trace_matrix(ctm);
diff --git a/fitz/doc_document.c b/fitz/doc_document.c
index ca13af72..2da7a110 100644
--- a/fitz/doc_document.c
+++ b/fitz/doc_document.c
@@ -1,4 +1,4 @@
-#include "fitz.h"
+#include "fitz-internal.h"
/* Yuck! Promiscuous we are. */
extern struct pdf_document *pdf_open_document(fz_context *ctx, char *filename);
diff --git a/fitz/doc_link.c b/fitz/doc_link.c
index 71f5dfbf..d558d18a 100644
--- a/fitz/doc_link.c
+++ b/fitz/doc_link.c
@@ -1,4 +1,4 @@
-#include "fitz.h"
+#include "fitz-internal.h"
void
fz_free_link_dest(fz_context *ctx, fz_link_dest *dest)
diff --git a/fitz/doc_outline.c b/fitz/doc_outline.c
index b69debaf..71694851 100644
--- a/fitz/doc_outline.c
+++ b/fitz/doc_outline.c
@@ -1,4 +1,4 @@
-#include "fitz.h"
+#include "fitz-internal.h"
void
fz_free_outline(fz_context *ctx, fz_outline *outline)
@@ -14,37 +14,49 @@ fz_free_outline(fz_context *ctx, fz_outline *outline)
}
}
-void
-fz_debug_outline_xml(fz_context *ctx, fz_outline *outline, int level)
+static void
+do_debug_outline_xml(FILE *out, fz_outline *outline, int level)
{
while (outline)
{
- printf("<outline title=\"%s\" page=\"%d\"", outline->title, outline->dest.kind == FZ_LINK_GOTO ? outline->dest.ld.gotor.page + 1 : 0);
+ fprintf(out, "<outline title=\"%s\" page=\"%d\"", outline->title, outline->dest.kind == FZ_LINK_GOTO ? outline->dest.ld.gotor.page + 1 : 0);
if (outline->down)
{
- printf(">\n");
- fz_debug_outline_xml(ctx, outline->down, level + 1);
- printf("</outline>\n");
+ fprintf(out, ">\n");
+ do_debug_outline_xml(out, outline->down, level + 1);
+ fprintf(out, "</outline>\n");
}
else
{
- printf(" />\n");
+ fprintf(out, " />\n");
}
outline = outline->next;
}
}
void
-fz_debug_outline(fz_context *ctx, fz_outline *outline, int level)
+fz_print_outline_xml(fz_context *ctx, FILE *out, fz_outline *outline)
+{
+ do_debug_outline_xml(out, outline, 0);
+}
+
+static void
+do_debug_outline(FILE *out, fz_outline *outline, int level)
{
int i;
while (outline)
{
for (i = 0; i < level; i++)
- putchar('\t');
- printf("%s\t%d\n", outline->title, outline->dest.kind == FZ_LINK_GOTO ? outline->dest.ld.gotor.page + 1 : 0);
+ fputc('\t', out);
+ fprintf(out, "%s\t%d\n", outline->title, outline->dest.kind == FZ_LINK_GOTO ? outline->dest.ld.gotor.page + 1 : 0);
if (outline->down)
- fz_debug_outline(ctx, outline->down, level + 1);
+ do_debug_outline(out, outline->down, level + 1);
outline = outline->next;
}
}
+
+void
+fz_print_outline(fz_context *ctx, FILE *out, fz_outline *outline)
+{
+ do_debug_outline(out, outline, 0);
+}
diff --git a/fitz/filt_basic.c b/fitz/filt_basic.c
index ae239fed..09d63402 100644
--- a/fitz/filt_basic.c
+++ b/fitz/filt_basic.c
@@ -1,4 +1,4 @@
-#include "fitz.h"
+#include "fitz-internal.h"
/* Pretend we have a filter that just copies data forever */
diff --git a/fitz/filt_dctd.c b/fitz/filt_dctd.c
index 4357f3d7..23744f01 100644
--- a/fitz/filt_dctd.c
+++ b/fitz/filt_dctd.c
@@ -1,4 +1,4 @@
-#include "fitz.h"
+#include "fitz-internal.h"
#include <jpeglib.h>
#include <setjmp.h>
@@ -12,6 +12,7 @@ struct fz_dctd_s
int color_transform;
int init;
int stride;
+ int factor;
unsigned char *scanline;
unsigned char *rp, *wp;
struct jpeg_decompress_struct cinfo;
@@ -150,6 +151,9 @@ read_dctd(fz_stream *stm, unsigned char *buf, int len)
break;
}
+ cinfo->scale_num = 8/state->factor;
+ cinfo->scale_denom = 8;
+
jpeg_start_decompress(cinfo);
state->stride = cinfo->output_width * cinfo->output_components;
@@ -216,6 +220,12 @@ skip:
fz_stream *
fz_open_dctd(fz_stream *chain, int color_transform)
{
+ return fz_open_resized_dctd(chain, color_transform, 1);
+}
+
+fz_stream *
+fz_open_resized_dctd(fz_stream *chain, int color_transform, int factor)
+{
fz_context *ctx = chain->ctx;
fz_dctd *state = NULL;
@@ -228,6 +238,7 @@ fz_open_dctd(fz_stream *chain, int color_transform)
state->chain = chain;
state->color_transform = color_transform;
state->init = 0;
+ state->factor = factor;
}
fz_catch(ctx)
{
diff --git a/fitz/filt_faxd.c b/fitz/filt_faxd.c
index 4e522eb5..ada7e87b 100644
--- a/fitz/filt_faxd.c
+++ b/fitz/filt_faxd.c
@@ -1,4 +1,4 @@
-#include "fitz.h"
+#include "fitz-internal.h"
/* Fax G3/G4 decoder */
diff --git a/fitz/filt_flate.c b/fitz/filt_flate.c
index 2eb0c563..24b6c081 100644
--- a/fitz/filt_flate.c
+++ b/fitz/filt_flate.c
@@ -1,4 +1,4 @@
-#include "fitz.h"
+#include "fitz-internal.h"
#include <zlib.h>
diff --git a/fitz/filt_jbig2d.c b/fitz/filt_jbig2d.c
index 3afcbcb0..415534c0 100644
--- a/fitz/filt_jbig2d.c
+++ b/fitz/filt_jbig2d.c
@@ -1,4 +1,4 @@
-#include "fitz.h"
+#include "fitz-internal.h"
#ifdef _WIN32 /* Microsoft Visual C++ */
diff --git a/fitz/filt_lzwd.c b/fitz/filt_lzwd.c
index ac952ccf..3ee4d34c 100644
--- a/fitz/filt_lzwd.c
+++ b/fitz/filt_lzwd.c
@@ -1,4 +1,4 @@
-#include "fitz.h"
+#include "fitz-internal.h"
/* TODO: error checking */
diff --git a/fitz/filt_predict.c b/fitz/filt_predict.c
index 8221c251..e68743d3 100644
--- a/fitz/filt_predict.c
+++ b/fitz/filt_predict.c
@@ -1,4 +1,4 @@
-#include "fitz.h"
+#include "fitz-internal.h"
/* TODO: check if this works with 16bpp images */
diff --git a/fitz/fitz-internal.h b/fitz/fitz-internal.h
new file mode 100644
index 00000000..0a639b1c
--- /dev/null
+++ b/fitz/fitz-internal.h
@@ -0,0 +1,1092 @@
+#ifndef FITZ_INTERNAL_H
+#define FITZ_INTERNAL_H
+
+#include "fitz.h"
+
+struct fz_warn_context_s
+{
+ char message[256];
+ int count;
+};
+
+
+fz_context *fz_clone_context_internal(fz_context *ctx);
+
+void fz_new_aa_context(fz_context *ctx);
+void fz_free_aa_context(fz_context *ctx);
+void fz_copy_aa_context(fz_context *dst, fz_context *src);
+
+/* Default allocator */
+extern fz_alloc_context fz_alloc_default;
+
+/* Default locks */
+extern fz_locks_context fz_locks_default;
+
+#if defined(MEMENTO) || defined(DEBUG)
+#define FITZ_DEBUG_LOCKING
+#endif
+
+#ifdef FITZ_DEBUG_LOCKING
+
+void fz_assert_lock_held(fz_context *ctx, int lock);
+void fz_assert_lock_not_held(fz_context *ctx, int lock);
+void fz_lock_debug_lock(fz_context *ctx, int lock);
+void fz_lock_debug_unlock(fz_context *ctx, int lock);
+
+#else
+
+#define fz_assert_lock_held(A,B) do { } while (0)
+#define fz_assert_lock_not_held(A,B) do { } while (0)
+#define fz_lock_debug_lock(A,B) do { } while (0)
+#define fz_lock_debug_unlock(A,B) do { } while (0)
+
+#endif /* !FITZ_DEBUG_LOCKING */
+
+static inline void
+fz_lock(fz_context *ctx, int lock)
+{
+ fz_lock_debug_lock(ctx, lock);
+ ctx->locks->lock(ctx->locks->user, lock);
+}
+
+static inline void
+fz_unlock(fz_context *ctx, int lock)
+{
+ fz_lock_debug_unlock(ctx, lock);
+ ctx->locks->unlock(ctx->locks->user, lock);
+}
+
+
+/*
+ * Basic runtime and utility functions
+ */
+
+/*
+ fz_malloc_struct: Allocate storage for a structure (with scavenging),
+ clear it, and (in Memento builds) tag the pointer as belonging to a
+ struct of this type.
+
+ CTX: The context.
+
+ STRUCT: The structure type.
+
+ Returns a pointer to allocated (and cleared) structure. Throws
+ exception on failure to allocate.
+*/
+/* alloc and zero a struct, and tag it for memento */
+#define fz_malloc_struct(CTX, STRUCT) \
+ Memento_label(fz_calloc(CTX,1,sizeof(STRUCT)), #STRUCT)
+
+/* Range checking atof */
+float fz_atof(const char *s);
+
+/*
+ * Generic hash-table with fixed-length keys.
+ */
+
+typedef struct fz_hash_table_s fz_hash_table;
+
+fz_hash_table *fz_new_hash_table(fz_context *ctx, int initialsize, int keylen, int lock);
+void fz_print_hash(fz_context *ctx, FILE *out, fz_hash_table *table);
+void fz_empty_hash(fz_context *ctx, fz_hash_table *table);
+void fz_free_hash(fz_context *ctx, fz_hash_table *table);
+
+void *fz_hash_find(fz_context *ctx, fz_hash_table *table, void *key);
+void *fz_hash_insert(fz_context *ctx, fz_hash_table *table, void *key, void *val);
+void fz_hash_remove(fz_context *ctx, fz_hash_table *table, void *key);
+
+int fz_hash_len(fz_context *ctx, fz_hash_table *table);
+void *fz_hash_get_key(fz_context *ctx, fz_hash_table *table, int idx);
+void *fz_hash_get_val(fz_context *ctx, fz_hash_table *table, int idx);
+
+/*
+ * Math and geometry
+ */
+
+/* Multiply scaled two integers in the 0..255 range */
+static inline int fz_mul255(int a, int b)
+{
+ /* see Jim Blinn's book "Dirty Pixels" for how this works */
+ int x = a * b + 128;
+ x += x >> 8;
+ return x >> 8;
+}
+
+/* Expand a value A from the 0...255 range to the 0..256 range */
+#define FZ_EXPAND(A) ((A)+((A)>>7))
+
+/* Combine values A (in any range) and B (in the 0..256 range),
+ * to give a single value in the same range as A was. */
+#define FZ_COMBINE(A,B) (((A)*(B))>>8)
+
+/* Combine values A and C (in the same (any) range) and B and D (in the
+ * 0..256 range), to give a single value in the same range as A and C were. */
+#define FZ_COMBINE2(A,B,C,D) (FZ_COMBINE((A), (B)) + FZ_COMBINE((C), (D)))
+
+/* Blend SRC and DST (in the same range) together according to
+ * AMOUNT (in the 0...256 range). */
+#define FZ_BLEND(SRC, DST, AMOUNT) ((((SRC)-(DST))*(AMOUNT) + ((DST)<<8))>>8)
+
+void fz_gridfit_matrix(fz_matrix *m);
+float fz_matrix_max_expansion(fz_matrix m);
+
+/*
+ * Basic crypto functions.
+ * Independent of the rest of fitz.
+ * For further encapsulation in filters, or not.
+ */
+
+/* md5 digests */
+
+typedef struct fz_md5_s fz_md5;
+
+struct fz_md5_s
+{
+ unsigned int state[4];
+ unsigned int count[2];
+ unsigned char buffer[64];
+};
+
+void fz_md5_init(fz_md5 *state);
+void fz_md5_update(fz_md5 *state, const unsigned char *input, unsigned inlen);
+void fz_md5_final(fz_md5 *state, unsigned char digest[16]);
+
+/* sha-256 digests */
+
+typedef struct fz_sha256_s fz_sha256;
+
+struct fz_sha256_s
+{
+ unsigned int state[8];
+ unsigned int count[2];
+ union {
+ unsigned char u8[64];
+ unsigned int u32[16];
+ } buffer;
+};
+
+void fz_sha256_init(fz_sha256 *state);
+void fz_sha256_update(fz_sha256 *state, const unsigned char *input, unsigned int inlen);
+void fz_sha256_final(fz_sha256 *state, unsigned char digest[32]);
+
+/* arc4 crypto */
+
+typedef struct fz_arc4_s fz_arc4;
+
+struct fz_arc4_s
+{
+ unsigned x;
+ unsigned y;
+ unsigned char state[256];
+};
+
+void fz_arc4_init(fz_arc4 *state, const unsigned char *key, unsigned len);
+void fz_arc4_encrypt(fz_arc4 *state, unsigned char *dest, const unsigned char *src, unsigned len);
+
+/* AES block cipher implementation from XYSSL */
+
+typedef struct fz_aes_s fz_aes;
+
+#define AES_DECRYPT 0
+#define AES_ENCRYPT 1
+
+struct fz_aes_s
+{
+ int nr; /* number of rounds */
+ unsigned long *rk; /* AES round keys */
+ unsigned long buf[68]; /* unaligned data */
+};
+
+void aes_setkey_enc( fz_aes *ctx, const unsigned char *key, int keysize );
+void aes_setkey_dec( fz_aes *ctx, const unsigned char *key, int keysize );
+void aes_crypt_cbc( fz_aes *ctx, int mode, int length,
+ unsigned char iv[16],
+ const unsigned char *input,
+ unsigned char *output );
+
+/*
+ Resource store
+
+ MuPDF stores decoded "objects" into a store for potential reuse.
+ If the size of the store gets too big, objects stored within it can
+ be evicted and freed to recover space. When MuPDF comes to decode
+ such an object, it will check to see if a version of this object is
+ already in the store - if it is, it will simply reuse it. If not, it
+ will decode it and place it into the store.
+
+ All objects that can be placed into the store are derived from the
+ fz_storable type (i.e. this should be the first component of the
+ objects structure). This allows for consistent (thread safe)
+ reference counting, and includes a function that will be called to
+ free the object as soon as the reference count reaches zero.
+
+ Most objects offer fz_keep_XXXX/fz_drop_XXXX functions derived
+ from fz_keep_storable/fz_drop_storable. Creation of such objects
+ includes a call to FZ_INIT_STORABLE to set up the fz_storable header.
+ */
+
+typedef struct fz_storable_s fz_storable;
+
+typedef void (fz_store_free_fn)(fz_context *, fz_storable *);
+
+struct fz_storable_s {
+ int refs;
+ fz_store_free_fn *free;
+};
+
+#define FZ_INIT_STORABLE(S_,RC,FREE) \
+ do { fz_storable *S = &(S_)->storable; S->refs = (RC); \
+ S->free = (FREE); \
+ } while (0)
+
+void *fz_keep_storable(fz_context *, fz_storable *);
+void fz_drop_storable(fz_context *, fz_storable *);
+
+/*
+ The store can be seen as a dictionary that maps keys to fz_storable
+ values. In order to allow keys of different types to be stored, we
+ have a structure full of functions for each key 'type'; this
+ fz_store_type pointer is stored with each key, and tells the store
+ how to perform certain operations (like taking/dropping a reference,
+ comparing two keys, outputting details for debugging etc).
+
+ The store uses a hash table internally for speed where possible. In
+ order for this to work, we need a mechanism for turning a generic
+ 'key' into 'a hashable string'. For this purpose the type structure
+ contains a make_hash_key function pointer that maps from a void *
+ to an fz_store_hash structure. If make_hash_key function returns 0,
+ then the key is determined not to be hashable, and the value is
+ not stored in the hash table.
+*/
+typedef struct fz_store_hash_s fz_store_hash;
+
+struct fz_store_hash_s
+{
+ fz_store_free_fn *free;
+ union
+ {
+ struct
+ {
+ int i0;
+ int i1;
+ } i;
+ struct
+ {
+ void *ptr;
+ int i;
+ } pi;
+ } u;
+};
+
+typedef struct fz_store_type_s fz_store_type;
+
+struct fz_store_type_s
+{
+ int (*make_hash_key)(fz_store_hash *, void *);
+ void *(*keep_key)(fz_context *,void *);
+ void (*drop_key)(fz_context *,void *);
+ int (*cmp_key)(void *, void *);
+ void (*debug)(void *);
+};
+
+/*
+ fz_store_new_context: Create a new store inside the context
+
+ max: The maximum size (in bytes) that the store is allowed to grow
+ to. FZ_STORE_UNLIMITED means no limit.
+*/
+void fz_new_store_context(fz_context *ctx, unsigned int max);
+
+/*
+ fz_drop_store_context: Drop a reference to the store.
+*/
+void fz_drop_store_context(fz_context *ctx);
+
+/*
+ fz_keep_store_context: Take a reference to the store.
+*/
+fz_store *fz_keep_store_context(fz_context *ctx);
+
+/*
+ fz_print_store: Dump the contents of the store for debugging.
+*/
+void fz_print_store(fz_context *ctx, FILE *out);
+
+/*
+ fz_store_item: Add an item to the store.
+
+ Add an item into the store, returning NULL for success. If an item
+ with the same key is found in the store, then our item will not be
+ inserted, and the function will return a pointer to that value
+ instead. This function takes its own reference to val, as required
+ (i.e. the caller maintains ownership of its own reference).
+
+ key: The key to use to index the item.
+
+ val: The value to store.
+
+ itemsize: The size in bytes of the value (as counted towards the
+ store size).
+
+ type: Functions used to manipulate the key.
+*/
+void *fz_store_item(fz_context *ctx, void *key, void *val, unsigned int itemsize, fz_store_type *type);
+
+/*
+ fz_find_item: Find an item within the store.
+
+ free: The function used to free the value (to ensure we get a value
+ of the correct type).
+
+ key: The key to use to index the item.
+
+ type: Functions used to manipulate the key.
+
+ Returns NULL for not found, otherwise returns a pointer to the value
+ indexed by key to which a reference has been taken.
+*/
+void *fz_find_item(fz_context *ctx, fz_store_free_fn *free, void *key, fz_store_type *type);
+
+/*
+ fz_remove_item: Remove an item from the store.
+
+ If an item indexed by the given key exists in the store, remove it.
+
+ free: The function used to free the value (to ensure we get a value
+ of the correct type).
+
+ key: The key to use to find the item to remove.
+
+ type: Functions used to manipulate the key.
+*/
+void fz_remove_item(fz_context *ctx, fz_store_free_fn *free, void *key, fz_store_type *type);
+
+/*
+ fz_empty_store: Evict everything from the store.
+*/
+void fz_empty_store(fz_context *ctx);
+
+/*
+ fz_store_scavenge: Internal function used as part of the scavenging
+ allocator; when we fail to allocate memory, before returning a
+ failure to the caller, we try to scavenge space within the store by
+ evicting at least 'size' bytes. The allocator then retries.
+
+ size: The number of bytes we are trying to have free.
+
+ phase: What phase of the scavenge we are in. Updated on exit.
+
+ Returns non zero if we managed to free any memory.
+*/
+int fz_store_scavenge(fz_context *ctx, unsigned int size, int *phase);
+
+struct fz_buffer_s
+{
+ int refs;
+ unsigned char *data;
+ int cap, len;
+};
+
+/*
+ fz_new_buffer: Create a new buffer.
+
+ capacity: Initial capacity.
+
+ Returns pointer to new buffer. Throws exception on allocation
+ failure.
+*/
+fz_buffer *fz_new_buffer(fz_context *ctx, int capacity);
+
+/*
+ fz_resize_buffer: Ensure that a buffer has a given capacity,
+ truncating data if required.
+
+ buf: The buffer to alter.
+
+ capacity: The desired capacity for the buffer. If the current size
+ of the buffer contents is smaller than capacity, it is truncated.
+
+*/
+void fz_resize_buffer(fz_context *ctx, fz_buffer *buf, int capacity);
+
+/*
+ fz_grow_buffer: Make some space within a buffer (i.e. ensure that
+ capacity > size).
+
+ buf: The buffer to grow.
+
+ May throw exception on failure to allocate.
+*/
+void fz_grow_buffer(fz_context *ctx, fz_buffer *buf);
+
+/*
+ fz_trim_buffer: Trim wasted capacity from a buffer.
+
+ buf: The buffer to trim.
+*/
+void fz_trim_buffer(fz_context *ctx, fz_buffer *buf);
+
+struct fz_stream_s
+{
+ fz_context *ctx;
+ int refs;
+ int error;
+ int eof;
+ int pos;
+ int avail;
+ int bits;
+ int locked;
+ unsigned char *bp, *rp, *wp, *ep;
+ void *state;
+ int (*read)(fz_stream *stm, unsigned char *buf, int len);
+ void (*close)(fz_context *ctx, void *state);
+ void (*seek)(fz_stream *stm, int offset, int whence);
+ unsigned char buf[4096];
+};
+
+void fz_lock_stream(fz_stream *stm);
+
+fz_stream *fz_new_stream(fz_context *ctx, void*, int(*)(fz_stream*, unsigned char*, int), void(*)(fz_context *, void *));
+fz_stream *fz_keep_stream(fz_stream *stm);
+void fz_fill_buffer(fz_stream *stm);
+
+void fz_read_line(fz_stream *stm, char *buf, int max);
+
+static inline int fz_read_byte(fz_stream *stm)
+{
+ if (stm->rp == stm->wp)
+ {
+ fz_fill_buffer(stm);
+ return stm->rp < stm->wp ? *stm->rp++ : EOF;
+ }
+ return *stm->rp++;
+}
+
+static inline int fz_peek_byte(fz_stream *stm)
+{
+ if (stm->rp == stm->wp)
+ {
+ fz_fill_buffer(stm);
+ return stm->rp < stm->wp ? *stm->rp : EOF;
+ }
+ return *stm->rp;
+}
+
+static inline void fz_unread_byte(fz_stream *stm)
+{
+ if (stm->rp > stm->bp)
+ stm->rp--;
+}
+
+static inline int fz_is_eof(fz_stream *stm)
+{
+ if (stm->rp == stm->wp)
+ {
+ if (stm->eof)
+ return 1;
+ return fz_peek_byte(stm) == EOF;
+ }
+ return 0;
+}
+
+static inline unsigned int fz_read_bits(fz_stream *stm, int n)
+{
+ unsigned int x;
+
+ if (n <= stm->avail)
+ {
+ stm->avail -= n;
+ x = (stm->bits >> stm->avail) & ((1 << n) - 1);
+ }
+ else
+ {
+ x = stm->bits & ((1 << stm->avail) - 1);
+ n -= stm->avail;
+ stm->avail = 0;
+
+ while (n > 8)
+ {
+ x = (x << 8) | fz_read_byte(stm);
+ n -= 8;
+ }
+
+ if (n > 0)
+ {
+ stm->bits = fz_read_byte(stm);
+ stm->avail = 8 - n;
+ x = (x << n) | (stm->bits >> stm->avail);
+ }
+ }
+
+ return x;
+}
+
+static inline void fz_sync_bits(fz_stream *stm)
+{
+ stm->avail = 0;
+}
+
+static inline int fz_is_eof_bits(fz_stream *stm)
+{
+ return fz_is_eof(stm) && (stm->avail == 0 || stm->bits == EOF);
+}
+
+/*
+ * Data filters.
+ */
+
+fz_stream *fz_open_copy(fz_stream *chain);
+fz_stream *fz_open_null(fz_stream *chain, int len);
+fz_stream *fz_open_arc4(fz_stream *chain, unsigned char *key, unsigned keylen);
+fz_stream *fz_open_aesd(fz_stream *chain, unsigned char *key, unsigned keylen);
+fz_stream *fz_open_a85d(fz_stream *chain);
+fz_stream *fz_open_ahxd(fz_stream *chain);
+fz_stream *fz_open_rld(fz_stream *chain);
+fz_stream *fz_open_dctd(fz_stream *chain, int color_transform);
+fz_stream *fz_open_resized_dctd(fz_stream *chain, int color_transform, int factor);
+fz_stream *fz_open_faxd(fz_stream *chain,
+ int k, int end_of_line, int encoded_byte_align,
+ int columns, int rows, int end_of_block, int black_is_1);
+fz_stream *fz_open_flated(fz_stream *chain);
+fz_stream *fz_open_lzwd(fz_stream *chain, int early_change);
+fz_stream *fz_open_predict(fz_stream *chain, int predictor, int columns, int colors, int bpc);
+fz_stream *fz_open_jbig2d(fz_stream *chain, fz_buffer *global);
+
+/*
+ * Resources and other graphics related objects.
+ */
+
+enum { FZ_MAX_COLORS = 32 };
+
+int fz_lookup_blendmode(char *name);
+char *fz_blendmode_name(int blendmode);
+
+struct fz_bitmap_s
+{
+ int refs;
+ int w, h, stride, n;
+ unsigned char *samples;
+};
+
+fz_bitmap *fz_new_bitmap(fz_context *ctx, int w, int h, int n);
+
+void fz_bitmap_details(fz_bitmap *bitmap, int *w, int *h, int *n, int *stride);
+
+void fz_clear_bitmap(fz_context *ctx, fz_bitmap *bit);
+
+/*
+ Pixmaps represent a set of pixels for a 2 dimensional region of a
+ plane. Each pixel has n components per pixel, the last of which is
+ always alpha. The data is in premultiplied alpha when rendering, but
+ non-premultiplied for colorspace conversions and rescaling.
+
+ x, y: The minimum x and y coord of the region in pixels.
+
+ w, h: The width and height of the region in pixels.
+
+ n: The number of color components in the image. Always
+ includes a separate alpha channel. For mask images n=1, for greyscale
+ (plus alpha) images n=2, for rgb (plus alpha) images n=3.
+
+ interpolate: A boolean flag set to non-zero if the image
+ will be drawn using linear interpolation, or set to zero if
+ image will be using nearest neighbour sampling.
+
+ xres, yres: Image resolution in dpi. Default is 96 dpi.
+
+ colorspace: Pointer to a colorspace object describing the colorspace
+ the pixmap is in. If NULL, the image is a mask.
+
+ samples: A simple block of memory w * h * n bytes of memory in which
+ the components are stored. The first n bytes are components 0 to n-1
+ for the pixel at (x,y). Each successive n bytes gives another pixel
+ in scanline order. Subsequent scanlines follow on with no padding.
+
+ free_samples: Is zero when an application has provided its own
+ buffer for pixel data through fz_new_pixmap_with_bbox_and_data.
+ If not zero the buffer will be freed when fz_drop_pixmap is
+ called for the pixmap.
+*/
+struct fz_pixmap_s
+{
+ fz_storable storable;
+ int x, y, w, h, n;
+ int interpolate;
+ int xres, yres;
+ fz_colorspace *colorspace;
+ unsigned char *samples;
+ int free_samples;
+};
+
+void fz_free_pixmap_imp(fz_context *ctx, fz_storable *pix);
+
+void fz_clear_pixmap_rect_with_value(fz_context *ctx, fz_pixmap *pix, int value, fz_bbox r);
+void fz_copy_pixmap_rect(fz_context *ctx, fz_pixmap *dest, fz_pixmap *src, fz_bbox r);
+void fz_premultiply_pixmap(fz_context *ctx, fz_pixmap *pix);
+fz_pixmap *fz_alpha_from_gray(fz_context *ctx, fz_pixmap *gray, int luminosity);
+unsigned int fz_pixmap_size(fz_context *ctx, fz_pixmap *pix);
+
+fz_pixmap *fz_scale_pixmap(fz_context *ctx, fz_pixmap *src, float x, float y, float w, float h, fz_bbox *clip);
+
+fz_bbox fz_pixmap_bbox_no_ctx(fz_pixmap *src);
+
+struct fz_image_s
+{
+ fz_storable storable;
+ int w, h;
+ fz_image *mask;
+ fz_colorspace *colorspace;
+ fz_pixmap *(*get_pixmap)(fz_context *, fz_image *, int w, int h);
+};
+
+fz_pixmap *fz_load_jpx(fz_context *ctx, unsigned char *data, int size, fz_colorspace *cs);
+fz_pixmap *fz_load_jpeg(fz_context *doc, unsigned char *data, int size);
+fz_pixmap *fz_load_png(fz_context *doc, unsigned char *data, int size);
+fz_pixmap *fz_load_tiff(fz_context *doc, unsigned char *data, int size);
+
+struct fz_halftone_s
+{
+ int refs;
+ int n;
+ fz_pixmap *comp[1];
+};
+
+fz_halftone *fz_new_halftone(fz_context *ctx, int num_comps);
+fz_halftone *fz_default_halftone(fz_context *ctx, int num_comps);
+void fz_drop_halftone(fz_context *ctx, fz_halftone *half);
+fz_halftone *fz_keep_halftone(fz_context *ctx, fz_halftone *half);
+
+struct fz_colorspace_s
+{
+ fz_storable storable;
+ unsigned int size;
+ char name[16];
+ int n;
+ void (*to_rgb)(fz_context *ctx, fz_colorspace *, float *src, float *rgb);
+ void (*from_rgb)(fz_context *ctx, fz_colorspace *, float *rgb, float *dst);
+ void (*free_data)(fz_context *Ctx, fz_colorspace *);
+ void *data;
+};
+
+fz_colorspace *fz_new_colorspace(fz_context *ctx, char *name, int n);
+fz_colorspace *fz_keep_colorspace(fz_context *ctx, fz_colorspace *colorspace);
+void fz_drop_colorspace(fz_context *ctx, fz_colorspace *colorspace);
+void fz_free_colorspace_imp(fz_context *ctx, fz_storable *colorspace);
+
+void fz_convert_color(fz_context *ctx, fz_colorspace *dsts, float *dstv, fz_colorspace *srcs, float *srcv);
+
+/*
+ * Fonts come in two variants:
+ * Regular fonts are handled by FreeType.
+ * Type 3 fonts have callbacks to the interpreter.
+ */
+
+char *ft_error_string(int err);
+
+struct fz_font_s
+{
+ int refs;
+ char name[32];
+
+ void *ft_face; /* has an FT_Face if used */
+ int ft_substitute; /* ... substitute metrics */
+ int ft_bold; /* ... synthesize bold */
+ int ft_italic; /* ... synthesize italic */
+ int ft_hint; /* ... force hinting for DynaLab fonts */
+
+ /* origin of font data */
+ char *ft_file;
+ unsigned char *ft_data;
+ int ft_size;
+
+ fz_matrix t3matrix;
+ void *t3resources;
+ fz_buffer **t3procs; /* has 256 entries if used */
+ float *t3widths; /* has 256 entries if used */
+ char *t3flags; /* has 256 entries if used */
+ void *t3doc; /* a pdf_document for the callback */
+ void (*t3run)(void *doc, void *resources, fz_buffer *contents, fz_device *dev, fz_matrix ctm, void *gstate);
+ void (*t3freeres)(void *doc, void *resources);
+
+ fz_rect bbox; /* font bbox is used only for t3 fonts */
+
+ /* per glyph bounding box cache */
+ int use_glyph_bbox;
+ int bbox_count;
+ fz_rect *bbox_table;
+
+ /* substitute metrics */
+ int width_count;
+ int *width_table; /* in 1000 units */
+};
+
+void fz_new_font_context(fz_context *ctx);
+fz_font_context *fz_keep_font_context(fz_context *ctx);
+void fz_drop_font_context(fz_context *ctx);
+
+fz_font *fz_new_type3_font(fz_context *ctx, char *name, fz_matrix matrix);
+
+fz_font *fz_new_font_from_memory(fz_context *ctx, unsigned char *data, int len, int index, int use_glyph_bbox);
+fz_font *fz_new_font_from_file(fz_context *ctx, char *path, int index, int use_glyph_bbox);
+
+fz_font *fz_keep_font(fz_context *ctx, fz_font *font);
+void fz_drop_font(fz_context *ctx, fz_font *font);
+
+void fz_print_font(fz_context *ctx, FILE *out, fz_font *font);
+
+void fz_set_font_bbox(fz_context *ctx, fz_font *font, float xmin, float ymin, float xmax, float ymax);
+fz_rect fz_bound_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix trm);
+int fz_glyph_cacheable(fz_context *ctx, fz_font *font, int gid);
+
+/*
+ * Vector path buffer.
+ * It can be stroked and dashed, or be filled.
+ * It has a fill rule (nonzero or even_odd).
+ *
+ * When rendering, they are flattened, stroked and dashed straight
+ * into the Global Edge List.
+ */
+
+typedef struct fz_path_s fz_path;
+typedef struct fz_stroke_state_s fz_stroke_state;
+
+typedef union fz_path_item_s fz_path_item;
+
+typedef enum fz_path_item_kind_e
+{
+ FZ_MOVETO,
+ FZ_LINETO,
+ FZ_CURVETO,
+ FZ_CLOSE_PATH
+} fz_path_item_kind;
+
+typedef enum fz_linecap_e
+{
+ FZ_LINECAP_BUTT = 0,
+ FZ_LINECAP_ROUND = 1,
+ FZ_LINECAP_SQUARE = 2,
+ FZ_LINECAP_TRIANGLE = 3
+} fz_linecap;
+
+typedef enum fz_linejoin_e
+{
+ FZ_LINEJOIN_MITER = 0,
+ FZ_LINEJOIN_ROUND = 1,
+ FZ_LINEJOIN_BEVEL = 2,
+ FZ_LINEJOIN_MITER_XPS = 3
+} fz_linejoin;
+
+union fz_path_item_s
+{
+ fz_path_item_kind k;
+ float v;
+};
+
+struct fz_path_s
+{
+ int len, cap;
+ fz_path_item *items;
+ int last;
+};
+
+struct fz_stroke_state_s
+{
+ fz_linecap start_cap, dash_cap, end_cap;
+ fz_linejoin linejoin;
+ float linewidth;
+ float miterlimit;
+ float dash_phase;
+ int dash_len;
+ float dash_list[32];
+};
+
+fz_path *fz_new_path(fz_context *ctx);
+void fz_moveto(fz_context*, fz_path*, float x, float y);
+void fz_lineto(fz_context*, fz_path*, float x, float y);
+void fz_curveto(fz_context*,fz_path*, float, float, float, float, float, float);
+void fz_curvetov(fz_context*,fz_path*, float, float, float, float);
+void fz_curvetoy(fz_context*,fz_path*, float, float, float, float);
+void fz_closepath(fz_context*,fz_path*);
+void fz_free_path(fz_context *ctx, fz_path *path);
+
+void fz_transform_path(fz_context *ctx, fz_path *path, fz_matrix transform);
+
+fz_path *fz_clone_path(fz_context *ctx, fz_path *old);
+
+fz_rect fz_bound_path(fz_context *ctx, fz_path *path, fz_stroke_state *stroke, fz_matrix ctm);
+void fz_print_path(fz_context *ctx, FILE *out, fz_path *, int indent);
+
+/*
+ * Glyph cache
+ */
+
+void fz_new_glyph_cache_context(fz_context *ctx);
+fz_glyph_cache *fz_keep_glyph_cache(fz_context *ctx);
+void fz_drop_glyph_cache_context(fz_context *ctx);
+void fz_purge_glyph_cache(fz_context *ctx);
+
+fz_pixmap *fz_render_ft_glyph(fz_context *ctx, fz_font *font, int cid, fz_matrix trm, int aa);
+fz_pixmap *fz_render_t3_glyph(fz_context *ctx, fz_font *font, int cid, fz_matrix trm, fz_colorspace *model);
+fz_pixmap *fz_render_ft_stroked_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix trm, fz_matrix ctm, fz_stroke_state *state);
+fz_pixmap *fz_render_glyph(fz_context *ctx, fz_font*, int, fz_matrix, fz_colorspace *model);
+fz_pixmap *fz_render_stroked_glyph(fz_context *ctx, fz_font*, int, fz_matrix, fz_matrix, fz_stroke_state *stroke);
+void fz_render_t3_glyph_direct(fz_context *ctx, fz_device *dev, fz_font *font, int gid, fz_matrix trm, void *gstate);
+
+/*
+ * Text buffer.
+ *
+ * The trm field contains the a, b, c and d coefficients.
+ * The e and f coefficients come from the individual elements,
+ * together they form the transform matrix for the glyph.
+ *
+ * Glyphs are referenced by glyph ID.
+ * The Unicode text equivalent is kept in a separate array
+ * with indexes into the glyph array.
+ */
+
+typedef struct fz_text_s fz_text;
+typedef struct fz_text_item_s fz_text_item;
+
+struct fz_text_item_s
+{
+ float x, y;
+ int gid; /* -1 for one gid to many ucs mappings */
+ int ucs; /* -1 for one ucs to many gid mappings */
+};
+
+struct fz_text_s
+{
+ fz_font *font;
+ fz_matrix trm;
+ int wmode;
+ int len, cap;
+ fz_text_item *items;
+};
+
+fz_text *fz_new_text(fz_context *ctx, fz_font *face, fz_matrix trm, int wmode);
+void fz_add_text(fz_context *ctx, fz_text *text, int gid, int ucs, float x, float y);
+void fz_free_text(fz_context *ctx, fz_text *text);
+fz_rect fz_bound_text(fz_context *ctx, fz_text *text, fz_matrix ctm);
+fz_text *fz_clone_text(fz_context *ctx, fz_text *old);
+void fz_print_text(fz_context *ctx, FILE *out, fz_text*);
+
+/*
+ * The shading code uses gouraud shaded triangle meshes.
+ */
+
+enum
+{
+ FZ_LINEAR,
+ FZ_RADIAL,
+ FZ_MESH,
+};
+
+typedef struct fz_shade_s fz_shade;
+
+struct fz_shade_s
+{
+ fz_storable storable;
+
+ fz_rect bbox; /* can be fz_infinite_rect */
+ fz_colorspace *colorspace;
+
+ fz_matrix matrix; /* matrix from pattern dict */
+ int use_background; /* background color for fills but not 'sh' */
+ float background[FZ_MAX_COLORS];
+
+ int use_function;
+ float function[256][FZ_MAX_COLORS + 1];
+
+ int type; /* linear, radial, mesh */
+ int extend[2];
+
+ int mesh_len;
+ int mesh_cap;
+ float *mesh; /* [x y 0], [x y r], [x y t] or [x y c1 ... cn] */
+};
+
+fz_shade *fz_keep_shade(fz_context *ctx, fz_shade *shade);
+void fz_drop_shade(fz_context *ctx, fz_shade *shade);
+void fz_free_shade_imp(fz_context *ctx, fz_storable *shade);
+void fz_print_shade(fz_context *ctx, FILE *out, fz_shade *shade);
+
+fz_rect fz_bound_shade(fz_context *ctx, fz_shade *shade, fz_matrix ctm);
+void fz_paint_shade(fz_context *ctx, fz_shade *shade, fz_matrix ctm, fz_pixmap *dest, fz_bbox bbox);
+
+/*
+ * Scan converter
+ */
+
+typedef struct fz_gel_s fz_gel;
+
+fz_gel *fz_new_gel(fz_context *ctx);
+void fz_insert_gel(fz_gel *gel, float x0, float y0, float x1, float y1);
+void fz_reset_gel(fz_gel *gel, fz_bbox clip);
+void fz_sort_gel(fz_gel *gel);
+fz_bbox fz_bound_gel(fz_gel *gel);
+void fz_free_gel(fz_gel *gel);
+int fz_is_rect_gel(fz_gel *gel);
+
+void fz_scan_convert(fz_gel *gel, int eofill, fz_bbox clip, fz_pixmap *pix, unsigned char *colorbv);
+
+void fz_flatten_fill_path(fz_gel *gel, fz_path *path, fz_matrix ctm, float flatness);
+void fz_flatten_stroke_path(fz_gel *gel, fz_path *path, fz_stroke_state *stroke, fz_matrix ctm, float flatness, float linewidth);
+void fz_flatten_dash_path(fz_gel *gel, fz_path *path, fz_stroke_state *stroke, fz_matrix ctm, float flatness, float linewidth);
+
+/*
+ * The device interface.
+ */
+
+fz_device *fz_new_draw_device_type3(fz_context *ctx, fz_pixmap *dest);
+
+enum
+{
+ /* Hints */
+ FZ_IGNORE_IMAGE = 1,
+ FZ_IGNORE_SHADE = 2,
+
+ /* Flags */
+ FZ_DEVFLAG_MASK = 1,
+ FZ_DEVFLAG_COLOR = 2,
+ FZ_DEVFLAG_UNCACHEABLE = 4,
+ FZ_DEVFLAG_FILLCOLOR_UNDEFINED = 8,
+ FZ_DEVFLAG_STROKECOLOR_UNDEFINED = 16,
+ FZ_DEVFLAG_STARTCAP_UNDEFINED = 32,
+ FZ_DEVFLAG_DASHCAP_UNDEFINED = 64,
+ FZ_DEVFLAG_ENDCAP_UNDEFINED = 128,
+ FZ_DEVFLAG_LINEJOIN_UNDEFINED = 256,
+ FZ_DEVFLAG_MITERLIMIT_UNDEFINED = 512,
+ FZ_DEVFLAG_LINEWIDTH_UNDEFINED = 1024,
+ /* Arguably we should have a bit for the dash pattern itself being
+ * undefined, but that causes problems; do we assume that it should
+ * always be set to non-dashing at the start of every glyph? */
+};
+
+struct fz_device_s
+{
+ int hints;
+ int flags;
+
+ void *user;
+ void (*free_user)(fz_device *);
+ fz_context *ctx;
+
+ void (*fill_path)(fz_device *, fz_path *, int even_odd, fz_matrix, fz_colorspace *, float *color, float alpha);
+ void (*stroke_path)(fz_device *, fz_path *, fz_stroke_state *, fz_matrix, fz_colorspace *, float *color, float alpha);
+ void (*clip_path)(fz_device *, fz_path *, fz_rect *rect, int even_odd, fz_matrix);
+ void (*clip_stroke_path)(fz_device *, fz_path *, fz_rect *rect, fz_stroke_state *, fz_matrix);
+
+ void (*fill_text)(fz_device *, fz_text *, fz_matrix, fz_colorspace *, float *color, float alpha);
+ void (*stroke_text)(fz_device *, fz_text *, fz_stroke_state *, fz_matrix, fz_colorspace *, float *color, float alpha);
+ void (*clip_text)(fz_device *, fz_text *, fz_matrix, int accumulate);
+ void (*clip_stroke_text)(fz_device *, fz_text *, fz_stroke_state *, fz_matrix);
+ void (*ignore_text)(fz_device *, fz_text *, fz_matrix);
+
+ void (*fill_shade)(fz_device *, fz_shade *shd, fz_matrix ctm, float alpha);
+ void (*fill_image)(fz_device *, fz_image *img, fz_matrix ctm, float alpha);
+ void (*fill_image_mask)(fz_device *, fz_image *img, fz_matrix ctm, fz_colorspace *, float *color, float alpha);
+ void (*clip_image_mask)(fz_device *, fz_image *img, fz_rect *rect, fz_matrix ctm);
+
+ void (*pop_clip)(fz_device *);
+
+ void (*begin_mask)(fz_device *, fz_rect, int luminosity, fz_colorspace *, float *bc);
+ void (*end_mask)(fz_device *);
+ void (*begin_group)(fz_device *, fz_rect, int isolated, int knockout, int blendmode, float alpha);
+ void (*end_group)(fz_device *);
+
+ void (*begin_tile)(fz_device *, fz_rect area, fz_rect view, float xstep, float ystep, fz_matrix ctm);
+ void (*end_tile)(fz_device *);
+};
+
+void fz_fill_path(fz_device *dev, fz_path *path, int even_odd, fz_matrix ctm, fz_colorspace *colorspace, float *color, float alpha);
+void fz_stroke_path(fz_device *dev, fz_path *path, fz_stroke_state *stroke, fz_matrix ctm, fz_colorspace *colorspace, float *color, float alpha);
+void fz_clip_path(fz_device *dev, fz_path *path, fz_rect *rect, int even_odd, fz_matrix ctm);
+void fz_clip_stroke_path(fz_device *dev, fz_path *path, fz_rect *rect, fz_stroke_state *stroke, fz_matrix ctm);
+void fz_fill_text(fz_device *dev, fz_text *text, fz_matrix ctm, fz_colorspace *colorspace, float *color, float alpha);
+void fz_stroke_text(fz_device *dev, fz_text *text, fz_stroke_state *stroke, fz_matrix ctm, fz_colorspace *colorspace, float *color, float alpha);
+void fz_clip_text(fz_device *dev, fz_text *text, fz_matrix ctm, int accumulate);
+void fz_clip_stroke_text(fz_device *dev, fz_text *text, fz_stroke_state *stroke, fz_matrix ctm);
+void fz_ignore_text(fz_device *dev, fz_text *text, fz_matrix ctm);
+void fz_pop_clip(fz_device *dev);
+void fz_fill_shade(fz_device *dev, fz_shade *shade, fz_matrix ctm, float alpha);
+void fz_fill_image(fz_device *dev, fz_image *image, fz_matrix ctm, float alpha);
+void fz_fill_image_mask(fz_device *dev, fz_image *image, fz_matrix ctm, fz_colorspace *colorspace, float *color, float alpha);
+void fz_clip_image_mask(fz_device *dev, fz_image *image, fz_rect *rect, fz_matrix ctm);
+void fz_begin_mask(fz_device *dev, fz_rect area, int luminosity, fz_colorspace *colorspace, float *bc);
+void fz_end_mask(fz_device *dev);
+void fz_begin_group(fz_device *dev, fz_rect area, int isolated, int knockout, int blendmode, float alpha);
+void fz_end_group(fz_device *dev);
+void fz_begin_tile(fz_device *dev, fz_rect area, fz_rect view, float xstep, float ystep, fz_matrix ctm);
+void fz_end_tile(fz_device *dev);
+
+fz_device *fz_new_device(fz_context *ctx, void *user);
+
+
+
+/*
+ * Plotting functions.
+ */
+
+void fz_decode_tile(fz_pixmap *pix, float *decode);
+void fz_decode_indexed_tile(fz_pixmap *pix, float *decode, int maxval);
+void fz_unpack_tile(fz_pixmap *dst, unsigned char * restrict src, int n, int depth, int stride, int scale);
+
+void fz_paint_solid_alpha(unsigned char * restrict dp, int w, int alpha);
+void fz_paint_solid_color(unsigned char * restrict dp, int n, int w, unsigned char *color);
+
+void fz_paint_span(unsigned char * restrict dp, unsigned char * restrict sp, int n, int w, int alpha);
+void fz_paint_span_with_color(unsigned char * restrict dp, unsigned char * restrict mp, int n, int w, unsigned char *color);
+
+void fz_paint_image(fz_pixmap *dst, fz_bbox scissor, fz_pixmap *shape, fz_pixmap *img, fz_matrix ctm, int alpha);
+void fz_paint_image_with_color(fz_pixmap *dst, fz_bbox scissor, fz_pixmap *shape, fz_pixmap *img, fz_matrix ctm, unsigned char *colorbv);
+
+void fz_paint_pixmap(fz_pixmap *dst, fz_pixmap *src, int alpha);
+void fz_paint_pixmap_with_mask(fz_pixmap *dst, fz_pixmap *src, fz_pixmap *msk);
+void fz_paint_pixmap_with_rect(fz_pixmap *dst, fz_pixmap *src, int alpha, fz_bbox bbox);
+
+void fz_blend_pixmap(fz_pixmap *dst, fz_pixmap *src, int alpha, int blendmode, int isolated, fz_pixmap *shape);
+void fz_blend_pixel(unsigned char dp[3], unsigned char bp[3], unsigned char sp[3], int blendmode);
+
+enum
+{
+ /* PDF 1.4 -- standard separable */
+ FZ_BLEND_NORMAL,
+ FZ_BLEND_MULTIPLY,
+ FZ_BLEND_SCREEN,
+ FZ_BLEND_OVERLAY,
+ FZ_BLEND_DARKEN,
+ FZ_BLEND_LIGHTEN,
+ FZ_BLEND_COLOR_DODGE,
+ FZ_BLEND_COLOR_BURN,
+ FZ_BLEND_HARD_LIGHT,
+ FZ_BLEND_SOFT_LIGHT,
+ FZ_BLEND_DIFFERENCE,
+ FZ_BLEND_EXCLUSION,
+
+ /* PDF 1.4 -- standard non-separable */
+ FZ_BLEND_HUE,
+ FZ_BLEND_SATURATION,
+ FZ_BLEND_COLOR,
+ FZ_BLEND_LUMINOSITY,
+
+ /* For packing purposes */
+ FZ_BLEND_MODEMASK = 15,
+ FZ_BLEND_ISOLATED = 16,
+ FZ_BLEND_KNOCKOUT = 32
+};
+
+struct fz_document_s
+{
+ void (*close)(fz_document *);
+ int (*needs_password)(fz_document *doc);
+ int (*authenticate_password)(fz_document *doc, char *password);
+ fz_outline *(*load_outline)(fz_document *doc);
+ int (*count_pages)(fz_document *doc);
+ fz_page *(*load_page)(fz_document *doc, int number);
+ fz_link *(*load_links)(fz_document *doc, fz_page *page);
+ fz_rect (*bound_page)(fz_document *doc, fz_page *page);
+ void (*run_page)(fz_document *doc, fz_page *page, fz_device *dev, fz_matrix transform, fz_cookie *cookie);
+ void (*free_page)(fz_document *doc, fz_page *page);
+};
+
+#endif
diff --git a/fitz/fitz.h b/fitz/fitz.h
index d2672031..26751824 100644
--- a/fitz/fitz.h
+++ b/fitz/fitz.h
@@ -1,9 +1,9 @@
-#ifndef _FITZ_H_
-#define _FITZ_H_
+#ifndef FITZ_H
+#define FITZ_H
/*
- * Include the standard libc headers.
- */
+ Include the standard libc headers.
+*/
#include <stdio.h>
#include <stdlib.h>
@@ -15,13 +15,27 @@
#include <assert.h>
#include <errno.h>
#include <limits.h> /* INT_MAX & co */
-#include <float.h> /* FLT_EPSILON */
+#include <float.h> /* FLT_EPSILON, FLT_MAX & co */
#include <fcntl.h> /* O_RDONLY & co */
#include <setjmp.h>
#include "memento.h"
+/*
+ Some versions of setjmp/longjmp (notably MacOSX and ios) store/restore
+ signal handlers too. We don't alter signal handlers within mupdf, so
+ there is no need for us to store/restore - hence we use the
+ non-restoring variants. This makes a large speed difference.
+*/
+#ifdef __APPLE__
+#define fz_setjmp _setjmp
+#define fz_longjmp _longjmp
+#else
+#define fz_setjmp setjmp
+#define fz_longjmp longjmp
+#endif
+
#ifdef __ANDROID__
#include <android/log.h>
#define LOG_TAG "libmupdf"
@@ -38,10 +52,11 @@
#define MIN(a,b) ( (a) < (b) ? (a) : (b) )
#define MAX(a,b) ( (a) > (b) ? (a) : (b) )
#define CLAMP(x,a,b) ( (x) > (b) ? (b) : ( (x) < (a) ? (a) : (x) ) )
+#define DIV_BY_ZERO(a, b, min, max) (((a) < 0) ^ ((b) < 0) ? (min) : (max))
/*
- * Some differences in libc can be smoothed over
- */
+ Some differences in libc can be smoothed over
+*/
#ifdef _MSC_VER /* Microsoft Visual C */
@@ -54,7 +69,7 @@
int gettimeofday(struct timeval *tv, struct timezone *tz);
#define snprintf _snprintf
-#define strtoll _strtoi64
+#define isnan _isnan
#else /* Unix or close enough */
@@ -75,8 +90,8 @@ int gettimeofday(struct timeval *tv, struct timezone *tz);
#endif
/*
- * Variadic macros, inline and restrict keywords
- */
+ Variadic macros, inline and restrict keywords
+*/
#if __STDC_VERSION__ == 199901L /* C99 */
#elif _MSC_VER >= 1500 /* MSVC 9 or newer */
@@ -91,8 +106,8 @@ int gettimeofday(struct timeval *tv, struct timezone *tz);
#endif
/*
- * GCC can do type checking of printf strings
- */
+ GCC can do type checking of printf strings
+*/
#ifndef __printflike
#if __GNUC__ > 2 || __GNUC__ == 2 && __GNUC_MINOR__ >= 7
@@ -103,7 +118,9 @@ int gettimeofday(struct timeval *tv, struct timezone *tz);
#endif
#endif
-/* Contexts */
+/*
+ Contexts
+*/
typedef struct fz_alloc_context_s fz_alloc_context;
typedef struct fz_error_context_s fz_error_context;
@@ -123,9 +140,6 @@ struct fz_alloc_context_s
void (*free)(void *, void *);
};
-/* Default allocator */
-extern fz_alloc_context fz_alloc_default;
-
struct fz_error_context_s
{
int top;
@@ -140,139 +154,13 @@ void fz_var_imp(void *);
#define fz_var(var) fz_var_imp((void *)&(var))
/*
-
-MuPDF uses a set of exception handling macros to simplify error return
-and cleanup. Conceptually, they work a lot like C++'s try/catch system,
-but do not require any special compiler support.
-
-The basic formulation is as follows:
-
- fz_try(ctx)
- {
- // Try to perform a task. Never 'return', 'goto' or 'longjmp' out
- // of here. 'break' may be used to safely exit (just) the try block
- // scope.
- }
- fz_always(ctx)
- {
- // Any code here is always executed, regardless of whether an
- // exception was thrown within the try or not. Never 'return', 'goto'
- // or longjmp out from here. 'break' may be used to safely exit (just)
- // the always block scope.
- }
- fz_catch(ctx)
- {
- // This code is called (after any always block) only if something
- // within the fz_try block (including any functions it called) threw
- // an exception. The code here is expected to handle the exception
- // (maybe record/report the error, cleanup any stray state etc) and
- // can then either exit the block, or pass on the exception to a
- // higher level (enclosing) fz_try block (using fz_throw, or
- // fz_rethrow).
- }
-
-The fz_always block is optional, and can safely be omitted.
-
-The macro based nature of this system has 3 main limitations:
-
-1) Never return from within try (or 'goto' or longjmp out of it).
- This upsets the internal housekeeping of the macros and will cause
- problems later on. The code will detect such things happening, but
- by then it is too late to give a helpful error report as to where the
- original infraction occurred.
-
-2) The fz_try(ctx) { ... } fz_always(ctx) { ... } fz_catch(ctx) { ... }
- is not one atomic C statement. That is to say, if you do:
-
- if (condition)
- fz_try(ctx) { ... }
- fz_catch(ctx) { ... }
-
- then you will not get what you want. Use the following instead:
-
- if (condition) {
- fz_try(ctx) { ... }
- fz_catch(ctx) { ... }
- }
-
-3) The macros are implemented using setjmp and longjmp, and so the standard
- C restrictions on the use of those functions apply to fz_try/fz_catch
- too. In particular, any "truly local" variable that is set between the
- start of fz_try and something in fz_try throwing an exception may become
- undefined as part of the process of throwing that exception.
-
- As a way of mitigating this problem, we provide an fz_var() macro that
- tells the compiler to ensure that that variable is not unset by the
- act of throwing the exception.
-
-A model piece of code using these macros then might be:
-
- house build_house(plans *p)
- {
- material m = NULL;
- walls w = NULL;
- roof r = NULL;
- house h = NULL;
- tiles t = make_tiles();
-
- fz_var(w);
- fz_var(r);
- fz_var(h);
-
- fz_try(ctx)
- {
- fz_try(ctx)
- {
- m = make_bricks();
- }
- fz_catch(ctx)
- {
- // No bricks available, make do with straw?
- m = make_straw();
- }
- w = make_walls(m, p);
- r = make_roof(m, t);
- h = combine(w, r); // Note, NOT: return combine(w,r);
- }
- fz_always(ctx)
- {
- drop_walls(w);
- drop_roof(r);
- drop_material(m);
- drop_tiles(t);
- }
- fz_catch(ctx)
- {
- fz_throw(ctx, "build_house failed");
- }
- return h;
- }
-
-Things to note about this:
-
-a) If make_tiles throws an exception, this will immediately be handled
- by some higher level exception handler. If it succeeds, t will be
- set before fz_try starts, so there is no need to fz_var(t);
-
-b) We try first off to make some bricks as our building material. If
- this fails, we fall back to straw. If this fails, we'll end up in
- the fz_catch, and the process will fail neatly.
-
-c) We assume in this code that combine takes new reference to both the
- walls and the roof it uses, and therefore that w and r need to be
- cleaned up in all cases.
-
-d) We assume the standard C convention that it is safe to destroy
- NULL things.
-
+ Exception macro definitions. Just treat these as a black box - pay no
+ attention to the man behind the curtain.
*/
-/* Exception macro definitions. Just treat these as a black box - pay no
- * attention to the man behind the curtain. */
-
#define fz_try(ctx) \
if (fz_push_try(ctx->error), \
- (ctx->error->stack[ctx->error->top].code = setjmp(ctx->error->stack[ctx->error->top].buffer)) == 0) \
+ (ctx->error->stack[ctx->error->top].code = fz_setjmp(ctx->error->stack[ctx->error->top].buffer)) == 0) \
{ do {
#define fz_always(ctx) \
@@ -285,78 +173,22 @@ d) We assume the standard C convention that it is safe to destroy
} \
if (ctx->error->stack[ctx->error->top--].code)
-/*
-
-We also include a couple of other formulations of the macros, with
-different strengths and weaknesses. These will be removed shortly, but
-I want them in git for at least 1 revision so I have a record of them.
-
-A formulation of try/always/catch that lifts limitation 2 above, but
-has problems when try/catch are nested in the same function; the inner
-nestings need to use fz_always_(ctx, label) and fz_catch_(ctx, label)
-instead. This was held as too high a price to pay to drop limitation 2.
-
-#define fz_try(ctx) \
- if (fz_push_try(ctx->error), \
- (ctx->error->stack[ctx->error->top].code = setjmp(ctx->error->stack[ctx->error->top].buffer)) == 0) \
- { do {
-
-#define fz_always_(ctx, label) \
- } while (0); \
- goto ALWAYS_LABEL_ ## label ; \
- } \
- else if (ctx->error->stack[ctx->error->top].code) \
- { ALWAYS_LABEL_ ## label : \
- do {
-
-#define fz_catch_(ctx, label) \
- } while(0); \
- if (ctx->error->stack[ctx->error->top--].code) \
- goto CATCH_LABEL_ ## label; \
- } \
- else if (ctx->error->top--, 1) \
- CATCH_LABEL ## label:
-
-#define fz_always(ctx) fz_always_(ctx, TOP)
-#define fz_catch(ctx) fz_catch_(ctx, TOP)
-
-Another alternative formulation, that again removes limitation 2, but at
-the cost of an always block always costing us 1 extra longjmp per
-execution. Again this was felt to be too high a cost to use.
-
-#define fz_try(ctx) \
- if (fz_push_try(ctx->error), \
- (ctx->error->stack[ctx->error->top].code = setjmp(ctx->error->stack[ctx->error->top].buffer)) == 0) \
- { do {
-
-#define fz_always(ctx) \
- } while (0); \
- longjmp(ctx->error->stack[ctx->error->top].buffer, 3); \
- } \
- else if (ctx->error->stack[ctx->error->top].code & 1) \
- { do {
-
-#define fz_catch(ctx) \
- } while(0); \
- if (ctx->error->stack[ctx->error->top].code == 1) \
- longjmp(ctx->error->stack[ctx->error->top].buffer, 2); \
- ctx->error->top--;\
- } \
- else if (ctx->error->top--, 1)
-
-*/
-
void fz_push_try(fz_error_context *ex);
void fz_throw(fz_context *, char *, ...) __printflike(2, 3);
void fz_rethrow(fz_context *);
+void fz_warn(fz_context *ctx, char *fmt, ...) __printflike(2, 3);
-struct fz_warn_context_s
-{
- char message[256];
- int count;
-};
+/*
+ fz_flush_warnings: Flush any repeated warnings.
-void fz_warn(fz_context *ctx, char *fmt, ...) __printflike(2, 3);
+ Repeated warnings are buffered, counted and eventually printed
+ along with the number of repetitions. Call fz_flush_warnings
+ to force printing of the latest buffered warning and the
+ number of repetitions, for example to make sure that all
+ warnings are printed before exiting an application.
+
+ Does not throw exceptions.
+*/
void fz_flush_warnings(fz_context *ctx);
struct fz_context_s
@@ -371,42 +203,118 @@ struct fz_context_s
fz_glyph_cache *glyph_cache;
};
+/*
+ Specifies the maximum size in bytes of the resource store in
+ fz_context. Given as argument to fz_new_context.
+
+ FZ_STORE_UNLIMITED: Let resource store grow unbounded.
+
+ FZ_STORE_DEFAULT: A reasonable upper bound on the size, for
+ devices that are not memory constrained.
+*/
+enum {
+ FZ_STORE_UNLIMITED = 0,
+ FZ_STORE_DEFAULT = 256 << 20,
+};
+
+/*
+ fz_new_context: Allocate context containing global state.
+
+ The global state contains an exception stack, resource store,
+ etc. Most functions in MuPDF take a context argument to be
+ able to reference the global state. See fz_free_context for
+ freeing an allocated context.
+
+ alloc: Supply a custom memory allocator through a set of
+ function pointers. Set to NULL for the standard library
+ allocator. The context will keep the allocator pointer, so the
+ data it points to must not be modified or freed during the
+ lifetime of the context.
+
+ locks: Supply a set of locks and functions to lock/unlock
+ them, intended for multi-threaded applications. Set to NULL
+ when using MuPDF in a single-threaded applications. The
+ context will keep the locks pointer, so the data it points to
+ must not be modified or freed during the lifetime of the
+ context.
+
+ max_store: Maximum size in bytes of the resource store, before
+ it will start evicting cached resources such as fonts and
+ images. FZ_STORE_UNLIMITED can be used if a hard limit is not
+ desired. Use FZ_STORE_DEFAULT to get a reasonable size.
+
+ Does not throw exceptions, but may return NULL.
+*/
fz_context *fz_new_context(fz_alloc_context *alloc, fz_locks_context *locks, unsigned int max_store);
+
+/*
+ fz_clone_context: Make a clone of an existing context.
+
+ This function is meant to be used in multi-threaded
+ applications where each thread requires its own context, yet
+ parts of the global state, for example caching, is shared.
+
+ ctx: Context obtained from fz_new_context to make a copy of.
+ ctx must have had locks and lock/functions setup when created.
+ The two contexts will share the memory allocator, resource
+ store, locks and lock/unlock functions. They will each have
+ their own exception stacks though.
+
+ Does not throw exception, but may return NULL.
+*/
fz_context *fz_clone_context(fz_context *ctx);
-fz_context *fz_clone_context_internal(fz_context *ctx);
+
+/*
+ fz_free_context: Free a context and its global state.
+
+ The context and all of its global state is freed, and any
+ buffered warnings are flushed (see fz_flush_warnings). If NULL
+ is passed in nothing will happen.
+
+ Does not throw exceptions.
+*/
void fz_free_context(fz_context *ctx);
-void fz_new_aa_context(fz_context *ctx);
-void fz_free_aa_context(fz_context *ctx);
-
-/* Locking functions
- *
- * MuPDF is kept deliberately free of any knowledge of particular threading
- * systems. As such, in order for safe multi-threaded operation, we rely on
- * callbacks to client provided functions.
- *
- * A client is expected to provide FZ_LOCK_MAX mutexes, and a function to
- * lock/unlock each of them. These may be recursive mutexes, but do not have
- * to be.
- *
- * If a client does not intend to use multiple threads, then it may pass
- * NULL instead of the address of a lock structure.
- *
- * In order to avoid deadlocks, we have 1 simple rules internally as to how
- * we use locks: We can never take lock n when we already hold any lock i,
- * where 0 <= i <= n. In order to verify this, we have some debugging code
- * built in, that is enabled by defining FITZ_DEBUG_LOCKING.
- */
+/*
+ fz_aa_level: Get the number of bits of antialiasing we are
+ using. Between 0 and 8.
+*/
+int fz_aa_level(fz_context *ctx);
-#if defined(MEMENTO) || defined(DEBUG)
-#define FITZ_DEBUG_LOCKING
-#endif
+/*
+ fz_set_aa_level: Set the number of bits of antialiasing we should use.
+
+ bits: The number of bits of antialiasing to use (values are clamped
+ to within the 0 to 8 range).
+*/
+void fz_set_aa_level(fz_context *ctx, int bits);
+
+/*
+ Locking functions
+
+ MuPDF is kept deliberately free of any knowledge of particular
+ threading systems. As such, in order for safe multi-threaded
+ operation, we rely on callbacks to client provided functions.
+
+ A client is expected to provide FZ_LOCK_MAX number of mutexes,
+ and a function to lock/unlock each of them. These may be
+ recursive mutexes, but do not have to be.
+
+ If a client does not intend to use multiple threads, then it
+ may pass NULL instead of a lock structure.
+
+ In order to avoid deadlocks, we have one simple rule
+ internally as to how we use locks: We can never take lock n
+ when we already hold any lock i, where 0 <= i <= n. In order
+ to verify this, we have some debugging code, that can be
+ enabled by defining FITZ_DEBUG_LOCKING.
+*/
struct fz_locks_context_s
{
void *user;
- void (*lock)(void *, int);
- void (*unlock)(void *, int);
+ void (*lock)(void *user, int lock);
+ void (*unlock)(void *user, int lock);
};
enum {
@@ -417,1076 +325,1257 @@ enum {
FZ_LOCK_MAX
};
-/* Default locks */
-extern fz_locks_context fz_locks_default;
+/*
+ Memory Allocation and Scavenging:
-#ifdef FITZ_DEBUG_LOCKING
+ All calls to MuPDFs allocator functions pass through to the
+ underlying allocators passed in when the initial context is
+ created, after locks are taken (using the supplied locking function)
+ to ensure that only one thread at a time calls through.
-void fz_assert_lock_held(fz_context *ctx, int lock);
-void fz_assert_lock_not_held(fz_context *ctx, int lock);
-void fz_lock_debug_lock(fz_context *ctx, int lock);
-void fz_lock_debug_unlock(fz_context *ctx, int lock);
+ If the underlying allocator fails, MuPDF attempts to make room for
+ the allocation by evicting elements from the store, then retrying.
-#else
+ Any call to allocate may then result in several calls to the underlying
+ allocator, and result in elements that are only referred to by the
+ store being freed.
+*/
-#define fz_assert_lock_held(A,B) do { } while (0)
-#define fz_assert_lock_not_held(A,B) do { } while (0)
-#define fz_lock_debug_lock(A,B) do { } while (0)
-#define fz_lock_debug_unlock(A,B) do { } while (0)
+/*
+ fz_malloc: Allocate a block of memory (with scavenging)
-#endif /* !FITZ_DEBUG_LOCKING */
+ size: The number of bytes to allocate.
-static inline void
-fz_lock(fz_context *ctx, int lock)
-{
- fz_lock_debug_lock(ctx, lock);
- ctx->locks->lock(ctx->locks->user, lock);
-}
+ Returns a pointer to the allocated block. May return NULL if size is
+ 0. Throws exception on failure to allocate.
+*/
+void *fz_malloc(fz_context *ctx, unsigned int size);
-static inline void
-fz_unlock(fz_context *ctx, int lock)
-{
- fz_lock_debug_unlock(ctx, lock);
- ctx->locks->unlock(ctx->locks->user, lock);
-}
+/*
+ fz_calloc: Allocate a zeroed block of memory (with scavenging)
+
+ count: The number of objects to allocate space for.
+ size: The size (in bytes) of each object.
+
+ Returns a pointer to the allocated block. May return NULL if size
+ and/or count are 0. Throws exception on failure to allocate.
+*/
+void *fz_calloc(fz_context *ctx, unsigned int count, unsigned int size);
/*
- * Basic runtime and utility functions
- */
+ fz_malloc_array: Allocate a block of (non zeroed) memory (with
+ scavenging). Equivalent to fz_calloc without the memory clearing.
-/* memory allocation */
+ count: The number of objects to allocate space for.
-/* The following throw exceptions on failure to allocate */
-void *fz_malloc(fz_context *ctx, unsigned int size);
-void *fz_calloc(fz_context *ctx, unsigned int count, unsigned int size);
+ size: The size (in bytes) of each object.
+
+ Returns a pointer to the allocated block. May return NULL if size
+ and/or count are 0. Throws exception on failure to allocate.
+*/
void *fz_malloc_array(fz_context *ctx, unsigned int count, unsigned int size);
+
+/*
+ fz_resize_array: Resize a block of memory (with scavenging).
+
+ p: The existing block to resize
+
+ count: The number of objects to resize to.
+
+ size: The size (in bytes) of each object.
+
+ Returns a pointer to the resized block. May return NULL if size
+ and/or count are 0. Throws exception on failure to resize (original
+ block is left unchanged).
+*/
void *fz_resize_array(fz_context *ctx, void *p, unsigned int count, unsigned int size);
+
+/*
+ fz_strdup: Duplicate a C string (with scavenging)
+
+ s: The string to duplicate.
+
+ Returns a pointer to a duplicated string. Throws exception on failure
+ to allocate.
+*/
char *fz_strdup(fz_context *ctx, char *s);
+/*
+ fz_free: Frees an allocation.
+
+ Does not throw exceptions.
+*/
void fz_free(fz_context *ctx, void *p);
-/* The following returns NULL on failure to allocate */
+/*
+ fz_malloc_no_throw: Allocate a block of memory (with scavenging)
+
+ size: The number of bytes to allocate.
+
+ Returns a pointer to the allocated block. May return NULL if size is
+ 0. Returns NULL on failure to allocate.
+*/
void *fz_malloc_no_throw(fz_context *ctx, unsigned int size);
-void *fz_malloc_array_no_throw(fz_context *ctx, unsigned int count, unsigned int size);
+
+/*
+ fz_calloc_no_throw: Allocate a zeroed block of memory (with scavenging)
+
+ count: The number of objects to allocate space for.
+
+ size: The size (in bytes) of each object.
+
+ Returns a pointer to the allocated block. May return NULL if size
+ and/or count are 0. Returns NULL on failure to allocate.
+*/
void *fz_calloc_no_throw(fz_context *ctx, unsigned int count, unsigned int size);
+
+/*
+ fz_malloc_array_no_throw: Allocate a block of (non zeroed) memory
+ (with scavenging). Equivalent to fz_calloc_no_throw without the
+ memory clearing.
+
+ count: The number of objects to allocate space for.
+
+ size: The size (in bytes) of each object.
+
+ Returns a pointer to the allocated block. May return NULL if size
+ and/or count are 0. Returns NULL on failure to allocate.
+*/
+void *fz_malloc_array_no_throw(fz_context *ctx, unsigned int count, unsigned int size);
+
+/*
+ fz_resize_array_no_throw: Resize a block of memory (with scavenging).
+
+ p: The existing block to resize
+
+ count: The number of objects to resize to.
+
+ size: The size (in bytes) of each object.
+
+ Returns a pointer to the resized block. May return NULL if size
+ and/or count are 0. Returns NULL on failure to resize (original
+ block is left unchanged).
+*/
void *fz_resize_array_no_throw(fz_context *ctx, void *p, unsigned int count, unsigned int size);
+
+/*
+ fz_strdup_no_throw: Duplicate a C string (with scavenging)
+
+ s: The string to duplicate.
+
+ Returns a pointer to a duplicated string. Returns NULL on failure
+ to allocate.
+*/
char *fz_strdup_no_throw(fz_context *ctx, char *s);
-/* alloc and zero a struct, and tag it for memento */
-#define fz_malloc_struct(CTX, STRUCT) \
- Memento_label(fz_calloc(CTX,1,sizeof(STRUCT)), #STRUCT)
+/*
+ Safe string functions
+*/
+/*
+ fz_strsep: Given a pointer to a C string (or a pointer to NULL) break
+ it at the first occurence of a delimiter char (from a given set).
-/* runtime (hah!) test for endian-ness */
-int fz_is_big_endian(void);
+ stringp: Pointer to a C string pointer (or NULL). Updated on exit to
+ point to the first char of the string after the delimiter that was
+ found. The string pointed to by stringp will be corrupted by this
+ call (as the found delimiter will be overwritten by 0).
-/* safe string functions */
+ delim: A C string of acceptable delimiter characters.
+
+ Returns a pointer to a C string containing the chars of stringp up
+ to the first delimiter char (or the end of the string), or NULL.
+*/
char *fz_strsep(char **stringp, const char *delim);
-int fz_strlcpy(char *dst, const char *src, int n);
-int fz_strlcat(char *dst, const char *src, int n);
-/* Range checking atof */
-float fz_atof(const char *s);
+/*
+ fz_strlcpy: Copy at most n-1 chars of a string into a destination
+ buffer with null termination, returning the real length of the
+ initial string (excluding terminator).
-/* utf-8 encoding and decoding */
-int chartorune(int *rune, char *str);
-int runetochar(char *str, int *rune);
-int runelen(int c);
+ dst: Destination buffer, at least n bytes long.
-/* getopt */
-extern int fz_getopt(int nargc, char * const *nargv, const char *ostr);
-extern int fz_optind;
-extern char *fz_optarg;
+ src: C string (non-NULL).
+
+ n: Size of dst buffer in bytes.
+
+ Returns the length (excluding terminator) of src.
+*/
+int fz_strlcpy(char *dst, const char *src, int n);
/*
- * Generic hash-table with fixed-length keys.
- */
+ fz_strlcat: Concatenate 2 strings, with a maximum length.
-typedef struct fz_hash_table_s fz_hash_table;
+ dst: pointer to first string in a buffer of n bytes.
-fz_hash_table *fz_new_hash_table(fz_context *ctx, int initialsize, int keylen);
-void fz_debug_hash(fz_context *ctx, fz_hash_table *table);
-void fz_empty_hash(fz_context *ctx, fz_hash_table *table);
-void fz_free_hash(fz_context *ctx, fz_hash_table *table);
+ src: pointer to string to concatenate.
-void *fz_hash_find(fz_context *ctx, fz_hash_table *table, void *key);
-void *fz_hash_insert(fz_context *ctx, fz_hash_table *table, void *key, void *val);
-void fz_hash_remove(fz_context *ctx, fz_hash_table *table, void *key);
+ n: Size (in bytes) of buffer that dst is in.
-int fz_hash_len(fz_context *ctx, fz_hash_table *table);
-void *fz_hash_get_key(fz_context *ctx, fz_hash_table *table, int idx);
-void *fz_hash_get_val(fz_context *ctx, fz_hash_table *table, int idx);
+ Returns the real length that a concatenated dst + src would have been
+ (not including terminator).
+*/
+int fz_strlcat(char *dst, const char *src, int n);
/*
- * Math and geometry
- */
+ fz_chartorune: UTF8 decode a string of chars to a rune.
-/* Multiply scaled two integers in the 0..255 range */
-static inline int fz_mul255(int a, int b)
-{
- /* see Jim Blinn's book "Dirty Pixels" for how this works */
- int x = a * b + 128;
- x += x >> 8;
- return x >> 8;
-}
+ rune: Pointer to an int to assign the decoded 'rune' to.
-/* Expand a value A from the 0...255 range to the 0..256 range */
-#define FZ_EXPAND(A) ((A)+((A)>>7))
+ str: Pointer to a UTF8 encoded string
-/* Combine values A (in any range) and B (in the 0..256 range),
- * to give a single value in the same range as A was. */
-#define FZ_COMBINE(A,B) (((A)*(B))>>8)
+ Returns the number of bytes consumed. Does not throw exceptions.
+*/
+int fz_chartorune(int *rune, char *str);
-/* Combine values A and C (in the same (any) range) and B and D (in the
- * 0..256 range), to give a single value in the same range as A and C were. */
-#define FZ_COMBINE2(A,B,C,D) (FZ_COMBINE((A), (B)) + FZ_COMBINE((C), (D)))
+/*
+ runetochar: UTF8 encode a run to a string of chars.
-/* Blend SRC and DST (in the same range) together according to
- * AMOUNT (in the 0...256 range). */
-#define FZ_BLEND(SRC, DST, AMOUNT) ((((SRC)-(DST))*(AMOUNT) + ((DST)<<8))>>8)
+ str: Pointer to a place to put the UTF8 encoded string.
-typedef struct fz_matrix_s fz_matrix;
-typedef struct fz_point_s fz_point;
-typedef struct fz_rect_s fz_rect;
-typedef struct fz_bbox_s fz_bbox;
+ rune: Pointer to a 'rune'.
-extern const fz_rect fz_unit_rect;
-extern const fz_rect fz_empty_rect;
-extern const fz_rect fz_infinite_rect;
+ Returns the number of bytes the rune took to output. Does not throw
+ exceptions.
+*/
+int fz_runetochar(char *str, int rune);
-extern const fz_bbox fz_unit_bbox;
-extern const fz_bbox fz_empty_bbox;
-extern const fz_bbox fz_infinite_bbox;
+/*
+ fz_runelen: Count many chars are required to represent a rune.
-#define fz_is_empty_rect(r) ((r).x0 == (r).x1)
-#define fz_is_infinite_rect(r) ((r).x0 > (r).x1)
-#define fz_is_empty_bbox(b) ((b).x0 == (b).x1)
-#define fz_is_infinite_bbox(b) ((b).x0 > (b).x1)
+ rune: The rune to encode.
-struct fz_matrix_s
-{
- float a, b, c, d, e, f;
-};
+ Returns the number of bytes required to represent this run in UTF8.
+*/
+int fz_runelen(int rune);
+/* getopt */
+extern int fz_getopt(int nargc, char * const *nargv, const char *ostr);
+extern int fz_optind;
+extern char *fz_optarg;
+
+/*
+ fz_point is a point in a two-dimensional space.
+*/
+typedef struct fz_point_s fz_point;
struct fz_point_s
{
float x, y;
};
+/*
+ fz_rect is a rectangle represented by two diagonally opposite
+ corners at arbitrary coordinates.
+
+ Rectangles are always axis-aligned with the X- and Y- axes.
+ The relationship between the coordinates are that x0 <= x1 and
+ y0 <= y1 in all cases except for infinte rectangles. The area
+ of a rectangle is defined as (x1 - x0) * (y1 - y0). If either
+ x0 > x1 or y0 > y1 is true for a given rectangle then it is
+ defined to be infinite.
+
+ To check for empty or infinite rectangles use fz_is_empty_rect
+ and fz_is_infinite_rect. Compare to fz_bbox which has corners
+ at integer coordinates.
+
+ x0, y0: The top left corner.
+
+ x1, y1: The botton right corner.
+*/
+typedef struct fz_rect_s fz_rect;
struct fz_rect_s
{
float x0, y0;
float x1, y1;
};
+/*
+ fz_bbox is a bounding box similar to a fz_rect, except that
+ all corner coordinates are rounded to integer coordinates.
+ To check for empty or infinite bounding boxes use
+ fz_is_empty_bbox and fz_is_infinite_bbox.
+
+ x0, y0: The top left corner.
+
+ x1, y1: The bottom right corner.
+*/
+typedef struct fz_bbox_s fz_bbox;
struct fz_bbox_s
{
int x0, y0;
int x1, y1;
};
+/*
+ A rectangle with sides of length one.
+
+ The bottom left corner is at (0, 0) and the top right corner
+ is at (1, 1).
+*/
+extern const fz_rect fz_unit_rect;
+
+/*
+ A bounding box with sides of length one. See fz_unit_rect.
+*/
+extern const fz_bbox fz_unit_bbox;
+
+/*
+ An empty rectangle with an area equal to zero.
+
+ Both the top left and bottom right corner are at (0, 0).
+*/
+extern const fz_rect fz_empty_rect;
+
+/*
+ An empty bounding box. See fz_empty_rect.
+*/
+extern const fz_bbox fz_empty_bbox;
+
+/*
+ An infinite rectangle with negative area.
+
+ The corner (x0, y0) is at (1, 1) while the corner (x1, y1) is
+ at (-1, -1).
+*/
+extern const fz_rect fz_infinite_rect;
+
+/*
+ An infinite bounding box. See fz_infinite_rect.
+*/
+extern const fz_bbox fz_infinite_bbox;
+
+/*
+ fz_is_empty_rect: Check if rectangle is empty.
+
+ An empty rectangle is defined as one whose area is zero.
+*/
+#define fz_is_empty_rect(r) ((r).x0 == (r).x1 || (r).y0 == (r).y1)
+
+/*
+ fz_is_empty_bbox: Check if bounding box is empty.
+
+ Same definition of empty bounding boxes as for empty
+ rectangles. See fz_is_empty_rect.
+*/
+#define fz_is_empty_bbox(b) ((b).x0 == (b).x1 || (b).y0 == (b).y1)
+
+/*
+ fz_is_infinite: Check if rectangle is infinite.
+
+ An infinite rectangle is defined as one where either of the
+ two relationships between corner coordinates are not true.
+*/
+#define fz_is_infinite_rect(r) ((r).x0 > (r).x1 || (r).y0 > (r).y1)
+
+/*
+ fz_is_infinite_bbox: Check if bounding box is infinite.
+
+ Same definition of infinite bounding boxes as for infinite
+ rectangles. See fz_is_infinite_rect.
+*/
+#define fz_is_infinite_bbox(b) ((b).x0 > (b).x1 || (b).y0 > (b).y1)
+
+/*
+ fz_matrix is a a row-major 3x3 matrix used for representing
+ transformations of coordinates throughout MuPDF.
+
+ Since all points reside in a two-dimensional space, one vector
+ is always a constant unit vector; hence only some elements may
+ vary in a matrix. Below is how the elements map between
+ different representations.
+
+ / a b 0 \
+ | c d 0 | normally represented as [ a b c d e f ].
+ \ e f 1 /
+*/
+typedef struct fz_matrix_s fz_matrix;
+struct fz_matrix_s
+{
+ float a, b, c, d, e, f;
+};
+
+
+/*
+ fz_identity: Identity transform matrix.
+*/
extern const fz_matrix fz_identity;
-fz_matrix fz_concat(fz_matrix one, fz_matrix two);
+/*
+ fz_concat: Multiply two matrices.
+
+ The order of the two matrices are important since matrix
+ multiplication is not commutative.
+
+ Does not throw exceptions.
+*/
+fz_matrix fz_concat(fz_matrix left, fz_matrix right);
+
+/*
+ fz_scale: Create a scaling matrix.
+
+ The returned matrix is of the form [ sx 0 0 sy 0 0 ].
+
+ sx, sy: Scaling factors along the X- and Y-axes. A scaling
+ factor of 1.0 will not cause any scaling along the relevant
+ axis.
+
+ Does not throw exceptions.
+*/
fz_matrix fz_scale(float sx, float sy);
+
+/*
+ fz_shear: Create a shearing matrix.
+
+ The returned matrix is of the form [ 1 sy sx 1 0 0 ].
+
+ sx, sy: Shearing factors. A shearing factor of 0.0 will not
+ cause any shearing along the relevant axis.
+
+ Does not throw exceptions.
+*/
fz_matrix fz_shear(float sx, float sy);
-fz_matrix fz_rotate(float theta);
+
+/*
+ fz_rotate: Create a rotation matrix.
+
+ The returned matrix is of the form
+ [ cos(deg) sin(deg) -sin(deg) cos(deg) 0 0 ].
+
+ degrees: Degrees of counter clockwise rotation. Values less
+ than zero and greater than 360 are handled as expected.
+
+ Does not throw exceptions.
+*/
+fz_matrix fz_rotate(float degrees);
+
+/*
+ fz_translate: Create a translation matrix.
+
+ The returned matrix is of the form [ 1 0 0 1 tx ty ].
+
+ tx, ty: Translation distances along the X- and Y-axes. A
+ translation of 0 will not cause any translation along the
+ relevant axis.
+
+ Does not throw exceptions.
+*/
fz_matrix fz_translate(float tx, float ty);
-fz_matrix fz_invert_matrix(fz_matrix m);
+
+/*
+ fz_invert_matrix: Create an inverse matrix.
+
+ matrix: Matrix to invert. A degenerate matrix, where the
+ determinant is equal to zero, can not be inverted and the
+ original matrix is returned instead.
+
+ Does not throw exceptions.
+*/
+fz_matrix fz_invert_matrix(fz_matrix matrix);
+
+/*
+ fz_is_rectilinear: Check if a transformation is rectilinear.
+
+ Rectilinear means that no shearing is present and that any
+ rotations present are a multiple of 90 degrees. Usually this
+ is used to make sure that axis-aligned rectangles before the
+ transformation are still axis-aligned rectangles afterwards.
+
+ Does not throw exceptions.
+*/
int fz_is_rectilinear(fz_matrix m);
-float fz_matrix_expansion(fz_matrix m);
-float fz_matrix_max_expansion(fz_matrix m);
-fz_bbox fz_round_rect(fz_rect r);
-fz_bbox fz_intersect_bbox(fz_bbox a, fz_bbox b);
-fz_rect fz_intersect_rect(fz_rect a, fz_rect b);
-fz_bbox fz_union_bbox(fz_bbox a, fz_bbox b);
-fz_rect fz_union_rect(fz_rect a, fz_rect b);
+/*
+ fz_matrix_expansion: Calculate average scaling factor of matrix.
+*/
+float fz_matrix_expansion(fz_matrix m); /* sumatrapdf */
+
+/*
+ fz_round_rect: Convert a rect into a bounding box.
-fz_point fz_transform_point(fz_matrix m, fz_point p);
-fz_point fz_transform_vector(fz_matrix m, fz_point p);
-fz_rect fz_transform_rect(fz_matrix m, fz_rect r);
-fz_bbox fz_transform_bbox(fz_matrix m, fz_bbox b);
+ Coordinates in a bounding box are integers, so rounding of the
+ rects coordinates takes place. The top left corner is rounded
+ upwards and left while the bottom right corner is rounded
+ downwards and to the right. Overflows or underflowing
+ coordinates are clamped to INT_MIN/INT_MAX.
-void fz_gridfit_matrix(fz_matrix *m);
+ Does not throw exceptions.
+*/
+fz_bbox fz_round_rect(fz_rect rect);
/*
- * Basic crypto functions.
- * Independent of the rest of fitz.
- * For further encapsulation in filters, or not.
- */
+ fz_intersect_rect: Compute intersection of two rectangles.
-/* md5 digests */
+ Compute the largest axis-aligned rectangle that covers the
+ area covered by both given rectangles. If either rectangle is
+ empty then the intersection is also empty. If either rectangle
+ is infinite then the intersection is simply the non-infinite
+ rectangle. Should both rectangles be infinite, then the
+ intersection is also infinite.
-typedef struct fz_md5_s fz_md5;
+ Does not throw exceptions.
+*/
+fz_rect fz_intersect_rect(fz_rect a, fz_rect b);
-struct fz_md5_s
-{
- unsigned int state[4];
- unsigned int count[2];
- unsigned char buffer[64];
-};
+/*
+ fz_intersect_bbox: Compute intersection of two bounding boxes.
-void fz_md5_init(fz_md5 *state);
-void fz_md5_update(fz_md5 *state, const unsigned char *input, unsigned inlen);
-void fz_md5_final(fz_md5 *state, unsigned char digest[16]);
+ Similar to fz_intersect_rect but operates on two bounding
+ boxes instead of two rectangles.
-/* sha-256 digests */
+ Does not throw exceptions.
+*/
+fz_bbox fz_intersect_bbox(fz_bbox a, fz_bbox b);
-typedef struct fz_sha256_s fz_sha256;
+/*
+ fz_union_rect: Compute union of two rectangles.
-struct fz_sha256_s
-{
- unsigned int state[8];
- unsigned int count[2];
- union {
- unsigned char u8[64];
- unsigned int u32[16];
- } buffer;
-};
+ Compute the smallest axis-aligned rectangle that encompasses
+ both given rectangles. If either rectangle is infinite then
+ the union is also infinite. If either rectangle is empty then
+ the union is simply the non-empty rectangle. Should both
+ rectangles be empty, then the union is also empty.
-void fz_sha256_init(fz_sha256 *state);
-void fz_sha256_update(fz_sha256 *state, const unsigned char *input, unsigned int inlen);
-void fz_sha256_final(fz_sha256 *state, unsigned char digest[32]);
+ Does not throw exceptions.
+*/
+fz_rect fz_union_rect(fz_rect a, fz_rect b);
-/* arc4 crypto */
+/*
+ fz_union_bbox: Compute union of two bounding boxes.
-typedef struct fz_arc4_s fz_arc4;
+ Similar to fz_union_rect but operates on two bounding boxes
+ instead of two rectangles.
-struct fz_arc4_s
-{
- unsigned x;
- unsigned y;
- unsigned char state[256];
-};
+ Does not throw exceptions.
+*/
+fz_bbox fz_union_bbox(fz_bbox a, fz_bbox b);
-void fz_arc4_init(fz_arc4 *state, const unsigned char *key, unsigned len);
-void fz_arc4_encrypt(fz_arc4 *state, unsigned char *dest, const unsigned char *src, unsigned len);
+/*
+ fz_transform_point: Apply a transformation to a point.
-/* AES block cipher implementation from XYSSL */
+ transform: Transformation matrix to apply. See fz_concat,
+ fz_scale, fz_rotate and fz_translate for how to create a
+ matrix.
-typedef struct fz_aes_s fz_aes;
+ Does not throw exceptions.
+*/
+fz_point fz_transform_point(fz_matrix transform, fz_point point);
-#define AES_DECRYPT 0
-#define AES_ENCRYPT 1
+/*
+ fz_transform_vector: Apply a transformation to a vector.
-struct fz_aes_s
-{
- int nr; /* number of rounds */
- unsigned long *rk; /* AES round keys */
- unsigned long buf[68]; /* unaligned data */
-};
+ transform: Transformation matrix to apply. See fz_concat,
+ fz_scale and fz_rotate for how to create a matrix. Any
+ translation will be ignored.
-void aes_setkey_enc( fz_aes *ctx, const unsigned char *key, int keysize );
-void aes_setkey_dec( fz_aes *ctx, const unsigned char *key, int keysize );
-void aes_crypt_cbc( fz_aes *ctx, int mode, int length,
- unsigned char iv[16],
- const unsigned char *input,
- unsigned char *output );
+ Does not throw exceptions.
+*/
+fz_point fz_transform_vector(fz_matrix transform, fz_point vector);
/*
- * Dynamic objects.
- * The same type of objects as found in PDF and PostScript.
- * Used by the filters and the mupdf parser.
- */
+ fz_transform_rect: Apply a transform to a rectangle.
-typedef struct fz_obj_s fz_obj;
-
-extern fz_obj *(*fz_resolve_indirect)(fz_obj *obj);
-
-fz_obj *fz_new_null(fz_context *ctx);
-fz_obj *fz_new_bool(fz_context *ctx, int b);
-fz_obj *fz_new_int(fz_context *ctx, int i);
-fz_obj *fz_new_real(fz_context *ctx, float f);
-fz_obj *fz_new_name(fz_context *ctx, char *str);
-fz_obj *fz_new_string(fz_context *ctx, char *str, int len);
-fz_obj *fz_new_indirect(fz_context *ctx, int num, int gen, void *doc);
-
-fz_obj *fz_new_array(fz_context *ctx, int initialcap);
-fz_obj *fz_new_dict(fz_context *ctx, int initialcap);
-fz_obj *fz_copy_array(fz_context *ctx, fz_obj *array);
-fz_obj *fz_copy_dict(fz_context *ctx, fz_obj *dict);
-
-fz_obj *fz_keep_obj(fz_obj *obj);
-void fz_drop_obj(fz_obj *obj);
-
-/* type queries */
-int fz_is_null(fz_obj *obj);
-int fz_is_bool(fz_obj *obj);
-int fz_is_int(fz_obj *obj);
-int fz_is_real(fz_obj *obj);
-int fz_is_name(fz_obj *obj);
-int fz_is_string(fz_obj *obj);
-int fz_is_array(fz_obj *obj);
-int fz_is_dict(fz_obj *obj);
-int fz_is_indirect(fz_obj *obj);
-
-int fz_objcmp(fz_obj *a, fz_obj *b);
-
-/* dict marking and unmarking functions - to avoid infinite recursions */
-int fz_dict_marked(fz_obj *obj);
-int fz_dict_mark(fz_obj *obj);
-void fz_dict_unmark(fz_obj *obj);
-
-/* safe, silent failure, no error reporting on type mismatches */
-int fz_to_bool(fz_obj *obj);
-int fz_to_int(fz_obj *obj);
-float fz_to_real(fz_obj *obj);
-char *fz_to_name(fz_obj *obj);
-char *fz_to_str_buf(fz_obj *obj);
-fz_obj *fz_to_dict(fz_obj *obj);
-int fz_to_str_len(fz_obj *obj);
-int fz_to_num(fz_obj *obj);
-int fz_to_gen(fz_obj *obj);
-
-int fz_array_len(fz_obj *array);
-fz_obj *fz_array_get(fz_obj *array, int i);
-void fz_array_put(fz_obj *array, int i, fz_obj *obj);
-void fz_array_push(fz_obj *array, fz_obj *obj);
-void fz_array_insert(fz_obj *array, fz_obj *obj);
-int fz_array_contains(fz_obj *array, fz_obj *obj);
-
-int fz_dict_len(fz_obj *dict);
-fz_obj *fz_dict_get_key(fz_obj *dict, int idx);
-fz_obj *fz_dict_get_val(fz_obj *dict, int idx);
-fz_obj *fz_dict_get(fz_obj *dict, fz_obj *key);
-fz_obj *fz_dict_gets(fz_obj *dict, char *key);
-fz_obj *fz_dict_getsa(fz_obj *dict, char *key, char *abbrev);
-void fz_dict_put(fz_obj *dict, fz_obj *key, fz_obj *val);
-void fz_dict_puts(fz_obj *dict, char *key, fz_obj *val);
-void fz_dict_del(fz_obj *dict, fz_obj *key);
-void fz_dict_dels(fz_obj *dict, char *key);
-void fz_sort_dict(fz_obj *dict);
-
-int fz_fprint_obj(FILE *fp, fz_obj *obj, int tight);
-void fz_debug_obj(fz_obj *obj);
-void fz_debug_ref(fz_obj *obj);
-
-void fz_set_str_len(fz_obj *obj, int newlen); /* private */
-void *fz_get_indirect_document(fz_obj *obj); /* private */
-
-/*
- * Data buffers.
- */
+ After the four corner points of the axis-aligned rectangle
+ have been transformed it may not longer be axis-aligned. So a
+ new axis-aligned rectangle is created covering at least the
+ area of the transformed rectangle.
+ transform: Transformation matrix to apply. See fz_concat,
+ fz_scale and fz_rotate for how to create a matrix.
+
+ rect: Rectangle to be transformed. The two special cases
+ fz_empty_rect and fz_infinite_rect, may be used but are
+ returned unchanged as expected.
+
+ Does not throw exceptions.
+*/
+fz_rect fz_transform_rect(fz_matrix transform, fz_rect rect);
+
+/*
+ fz_transform_bbox: Transform a given bounding box.
+
+ Similar to fz_transform_rect, but operates on a bounding box
+ instead of a rectangle.
+
+ Does not throw exceptions.
+*/
+fz_bbox fz_transform_bbox(fz_matrix matrix, fz_bbox bbox);
+
+/*
+ fz_buffer is a wrapper around a dynamically allocated array of bytes.
+
+ Buffers have a capacity (the number of bytes storage immediately
+ available) and a current size.
+*/
typedef struct fz_buffer_s fz_buffer;
-struct fz_buffer_s
-{
- int refs;
- unsigned char *data;
- int cap, len;
-};
+/*
+ fz_keep_buffer: Increment the reference count for a buffer.
-fz_buffer *fz_new_buffer(fz_context *ctx, int size);
+ buf: The buffer to increment the reference count for.
+
+ Returns a pointer to the buffer. Does not throw exceptions.
+*/
fz_buffer *fz_keep_buffer(fz_context *ctx, fz_buffer *buf);
+
+/*
+ fz_drop_buffer: Decrement the reference count for a buffer.
+
+ buf: The buffer to decrement the reference count for.
+*/
void fz_drop_buffer(fz_context *ctx, fz_buffer *buf);
-void fz_resize_buffer(fz_context *ctx, fz_buffer *buf, int size);
-void fz_grow_buffer(fz_context *ctx, fz_buffer *buf);
+/*
+ fz_buffer_storage: Retrieve information on the storage currently used
+ by a buffer.
+
+ data: Pointer to place to retrieve data pointer.
+
+ Returns length of stream.
+*/
+int fz_buffer_storage(fz_context *ctx, fz_buffer *buf, unsigned char **data);
/*
- * Resource store
- */
+ fz_stream is a buffered reader capable of seeking in both
+ directions.
-typedef struct fz_storable_s fz_storable;
+ Streams are reference counted, so references must be dropped
+ by a call to fz_close.
-typedef struct fz_item_s fz_item;
+ Only the data between rp and wp is valid.
+*/
+typedef struct fz_stream_s fz_stream;
-typedef void (fz_store_free_fn)(fz_context *, fz_storable *);
+/*
+ fz_open_file: Open the named file and wrap it in a stream.
-struct fz_storable_s {
- int refs;
- fz_store_free_fn *free;
-};
+ filename: Path to a file as it would be given to open(2).
+*/
+fz_stream *fz_open_file(fz_context *ctx, const char *filename);
-#define FZ_INIT_STORABLE(S_,RC,FREE) \
- do { fz_storable *S = &(S_)->storable; S->refs = (RC); \
- S->free = (FREE); \
- } while (0)
+/*
+ fz_open_file_w: Open the named file and wrap it in a stream.
-enum {
- FZ_STORE_UNLIMITED = 0,
- FZ_STORE_DEFAULT = 256 << 20,
-};
+ This function is only available when compiling for Win32.
-void fz_new_store_context(fz_context *ctx, unsigned int max);
-void fz_drop_store_context(fz_context *ctx);
-fz_store *fz_store_keep(fz_context *ctx);
-void fz_debug_store(fz_context *ctx);
+ filename: Wide character path to the file as it would be given
+ to _wopen().
+*/
+fz_stream *fz_open_file_w(fz_context *ctx, const wchar_t *filename);
-void *fz_keep_storable(fz_context *, fz_storable *);
-void fz_drop_storable(fz_context *, fz_storable *);
+/*
+ fz_open_fd: Wrap an open file descriptor in a stream.
-void fz_store_item(fz_context *ctx, fz_obj *key, void *val, unsigned int itemsize);
-void *fz_find_item(fz_context *ctx, fz_store_free_fn *freefn, fz_obj *key);
-void fz_remove_item(fz_context *ctx, fz_store_free_fn *freefn, fz_obj *key);
-void fz_empty_store(fz_context *ctx);
-int fz_store_scavenge(fz_context *ctx, unsigned int size, int *phase);
+ file: An open file descriptor supporting bidirectional
+ seeking. The stream will take ownership of the file
+ descriptor, so it may not be modified or closed after the call
+ to fz_open_fd. When the stream is closed it will also close
+ the file descriptor.
+*/
+fz_stream *fz_open_fd(fz_context *ctx, int file);
/*
- * Buffered reader.
- * Only the data between rp and wp is valid data.
- */
+ fz_open_memory: Open a block of memory as a stream.
-typedef struct fz_stream_s fz_stream;
+ data: Pointer to start of data block. Ownership of the data block is
+ NOT passed in.
-struct fz_stream_s
-{
- fz_context *ctx;
- int refs;
- int error;
- int eof;
- int pos;
- int avail;
- int bits;
- int locked;
- unsigned char *bp, *rp, *wp, *ep;
- void *state;
- int (*read)(fz_stream *stm, unsigned char *buf, int len);
- void (*close)(fz_context *ctx, void *state);
- void (*seek)(fz_stream *stm, int offset, int whence);
- unsigned char buf[4096];
-};
+ len: Number of bytes in data block.
-fz_stream *fz_open_fd(fz_context *ctx, int file);
-fz_stream *fz_open_file(fz_context *ctx, const char *filename);
-fz_stream *fz_open_file_w(fz_context *ctx, const wchar_t *filename); /* only on win32 */
-fz_stream *fz_open_buffer(fz_context *ctx, fz_buffer *buf);
+ Returns pointer to newly created stream. May throw exceptions on
+ failure to allocate.
+*/
fz_stream *fz_open_memory(fz_context *ctx, unsigned char *data, int len);
-void fz_close(fz_stream *stm);
-void fz_lock_stream(fz_stream *stm);
-fz_stream *fz_new_stream(fz_context *ctx, void*, int(*)(fz_stream*, unsigned char*, int), void(*)(fz_context *, void *));
-fz_stream *fz_keep_stream(fz_stream *stm);
-void fz_fill_buffer(fz_stream *stm);
+/*
+ fz_open_buffer: Open a buffer as a stream.
+
+ buf: The buffer to open. Ownership of the buffer is NOT passed in
+ (this function takes it's own reference).
+ Returns pointer to newly created stream. May throw exceptions on
+ failure to allocate.
+*/
+fz_stream *fz_open_buffer(fz_context *ctx, fz_buffer *buf);
+
+/*
+ fz_close: Close an open stream.
+
+ Drops a reference for the stream. Once no references remain
+ the stream will be closed, as will any file descriptor the
+ stream is using.
+
+ Does not throw exceptions.
+*/
+void fz_close(fz_stream *stm);
+
+/*
+ fz_tell: return the current reading position within a stream
+*/
int fz_tell(fz_stream *stm);
+
+/*
+ fz_seek: Seek within a stream.
+
+ stm: The stream to seek within.
+
+ offset: The offset to seek to.
+
+ whence: From where the offset is measured (see fseek).
+*/
void fz_seek(fz_stream *stm, int offset, int whence);
-int fz_read(fz_stream *stm, unsigned char *buf, int len);
-void fz_read_line(fz_stream *stm, char *buf, int max);
-fz_buffer *fz_read_all(fz_stream *stm, int initial);
+/*
+ fz_read: Read from a stream into a given data block.
-static inline int fz_read_byte(fz_stream *stm)
-{
- if (stm->rp == stm->wp)
- {
- fz_fill_buffer(stm);
- return stm->rp < stm->wp ? *stm->rp++ : EOF;
- }
- return *stm->rp++;
-}
+ stm: The stream to read from.
-static inline int fz_peek_byte(fz_stream *stm)
-{
- if (stm->rp == stm->wp)
- {
- fz_fill_buffer(stm);
- return stm->rp < stm->wp ? *stm->rp : EOF;
- }
- return *stm->rp;
-}
+ data: The data block to read into.
-static inline void fz_unread_byte(fz_stream *stm)
-{
- if (stm->rp > stm->bp)
- stm->rp--;
-}
+ len: The length of the data block (in bytes).
-static inline int fz_is_eof(fz_stream *stm)
-{
- if (stm->rp == stm->wp)
- {
- if (stm->eof)
- return 1;
- return fz_peek_byte(stm) == EOF;
- }
- return 0;
-}
+ Returns the number of bytes read. May throw exceptions.
+*/
+int fz_read(fz_stream *stm, unsigned char *data, int len);
-static inline unsigned int fz_read_bits(fz_stream *stm, int n)
-{
- unsigned int x;
+/*
+ fz_read_all: Read all of a stream into a buffer.
- if (n <= stm->avail)
- {
- stm->avail -= n;
- x = (stm->bits >> stm->avail) & ((1 << n) - 1);
- }
- else
- {
- x = stm->bits & ((1 << stm->avail) - 1);
- n -= stm->avail;
- stm->avail = 0;
+ stm: The stream to read from
- while (n > 8)
- {
- x = (x << 8) | fz_read_byte(stm);
- n -= 8;
- }
+ initial: Suggested initial size for the buffer.
- if (n > 0)
- {
- stm->bits = fz_read_byte(stm);
- stm->avail = 8 - n;
- x = (x << n) | (stm->bits >> stm->avail);
- }
- }
+ Returns a buffer created from reading from the stream. May throw
+ exceptions on failure to allocate.
+*/
+fz_buffer *fz_read_all(fz_stream *stm, int initial);
- return x;
-}
+/*
+ Bitmaps have 1 bit per component. Only used for creating halftoned
+ versions of contone buffers, and saving out. Samples are stored msb
+ first, akin to pbms.
+*/
+typedef struct fz_bitmap_s fz_bitmap;
-static inline void fz_sync_bits(fz_stream *stm)
-{
- stm->avail = 0;
-}
+/*
+ fz_keep_bitmap: Take a reference to a bitmap.
-static inline int fz_is_eof_bits(fz_stream *stm)
-{
- return fz_is_eof(stm) && (stm->avail == 0 || stm->bits == EOF);
-}
+ bit: The bitmap to increment the reference for.
+
+ Returns bit. Does not throw exceptions.
+*/
+fz_bitmap *fz_keep_bitmap(fz_context *ctx, fz_bitmap *bit);
/*
- * Data filters.
- */
+ fz_drop_bitmap: Drop a reference and free a bitmap.
-fz_stream *fz_open_copy(fz_stream *chain);
-fz_stream *fz_open_null(fz_stream *chain, int len);
-fz_stream *fz_open_arc4(fz_stream *chain, unsigned char *key, unsigned keylen);
-fz_stream *fz_open_aesd(fz_stream *chain, unsigned char *key, unsigned keylen);
-fz_stream *fz_open_a85d(fz_stream *chain);
-fz_stream *fz_open_ahxd(fz_stream *chain);
-fz_stream *fz_open_rld(fz_stream *chain);
-fz_stream *fz_open_dctd(fz_stream *chain, int color_transform);
-fz_stream *fz_open_faxd(fz_stream *chain,
- int k, int end_of_line, int encoded_byte_align,
- int columns, int rows, int end_of_block, int black_is_1);
-fz_stream *fz_open_flated(fz_stream *chain);
-fz_stream *fz_open_lzwd(fz_stream *chain, int early_change);
-fz_stream *fz_open_predict(fz_stream *chain, int predictor, int columns, int colors, int bpc);
-fz_stream *fz_open_jbig2d(fz_stream *chain, fz_buffer *global);
-
-/*
- * Resources and other graphics related objects.
- */
+ Decrement the reference count for the bitmap. When no
+ references remain the pixmap will be freed.
-enum { FZ_MAX_COLORS = 32 };
+ Does not throw exceptions.
+*/
+void fz_drop_bitmap(fz_context *ctx, fz_bitmap *bit);
-int fz_find_blendmode(char *name);
-char *fz_blendmode_name(int blendmode);
+/*
+ An fz_colorspace object represents an abstract colorspace. While
+ this should be treated as a black box by callers of the library at
+ this stage, know that it encapsulates knowledge of how to convert
+ colors to and from the colorspace, any lookup tables generated, the
+ number of components in the colorspace etc.
+*/
+typedef struct fz_colorspace_s fz_colorspace;
/*
- * Pixmaps have n components per pixel. the last is always alpha.
- * premultiplied alpha when rendering, but non-premultiplied for colorspace
- * conversions and rescaling.
- */
+ fz_find_device_colorspace: Find a standard colorspace based upon
+ it's name.
+*/
+fz_colorspace *fz_find_device_colorspace(fz_context *ctx, char *name);
+/*
+ fz_device_gray: Abstract colorspace representing device specific
+ gray.
+*/
+extern fz_colorspace *fz_device_gray;
+
+/*
+ fz_device_rgb: Abstract colorspace representing device specific
+ rgb.
+*/
+extern fz_colorspace *fz_device_rgb;
+
+/*
+ fz_device_bgr: Abstract colorspace representing device specific
+ bgr.
+*/
+extern fz_colorspace *fz_device_bgr;
+
+/*
+ fz_device_cmyk: Abstract colorspace representing device specific
+ CMYK.
+*/
+extern fz_colorspace *fz_device_cmyk;
+
+/*
+ Pixmaps represent a set of pixels for a 2 dimensional region of a
+ plane. Each pixel has n components per pixel, the last of which is
+ always alpha. The data is in premultiplied alpha when rendering, but
+ non-premultiplied for colorspace conversions and rescaling.
+*/
typedef struct fz_pixmap_s fz_pixmap;
-typedef struct fz_colorspace_s fz_colorspace;
-struct fz_pixmap_s
-{
- fz_storable storable;
- int x, y, w, h, n;
- fz_pixmap *mask; /* explicit soft/image mask */
- int interpolate;
- int xres, yres;
- fz_colorspace *colorspace;
- unsigned char *samples;
- int free_samples;
-};
+/*
+ fz_pixmap_bbox: Return a bounding box for a pixmap.
-fz_bbox fz_bound_pixmap(fz_pixmap *pix);
+ Returns an exact bounding box for the supplied pixmap.
+*/
+fz_bbox fz_pixmap_bbox(fz_context *ctx, fz_pixmap *pix);
-fz_pixmap *fz_new_pixmap_with_data(fz_context *ctx, fz_colorspace *colorspace, int w, int h, unsigned char *samples);
-fz_pixmap *fz_new_pixmap_with_rect(fz_context *ctx, fz_colorspace *, fz_bbox bbox);
-fz_pixmap *fz_new_pixmap_with_rect_and_data(fz_context *ctx, fz_colorspace *, fz_bbox bbox, unsigned char *samples);
-fz_pixmap *fz_new_pixmap(fz_context *ctx, fz_colorspace *, int w, int h);
-fz_pixmap *fz_keep_pixmap(fz_context *ctx, fz_pixmap *pix);
-void fz_drop_pixmap(fz_context *ctx, fz_pixmap *pix);
-void fz_free_pixmap_imp(fz_context *ctx, fz_storable *pix);
-void fz_clear_pixmap(fz_context *ctx, fz_pixmap *pix);
-void fz_clear_pixmap_with_value(fz_context *ctx, fz_pixmap *pix, int value);
-void fz_clear_pixmap_rect_with_value(fz_context *ctx, fz_pixmap *pix, int value, fz_bbox r);
-void fz_copy_pixmap_rect(fz_context *ctx, fz_pixmap *dest, fz_pixmap *src, fz_bbox r);
-void fz_premultiply_pixmap(fz_context *ctx, fz_pixmap *pix);
-void fz_unmultiply_pixmap(fz_context *ctx, fz_pixmap *pix);
-fz_pixmap *fz_alpha_from_gray(fz_context *ctx, fz_pixmap *gray, int luminosity);
-void fz_invert_pixmap(fz_context *ctx, fz_pixmap *pix);
-void fz_gamma_pixmap(fz_context *ctx, fz_pixmap *pix, float gamma);
-unsigned int fz_pixmap_size(fz_context *ctx, fz_pixmap *pix);
+/*
+ fz_pixmap_width: Return the width of the pixmap in pixels.
+*/
+int fz_pixmap_width(fz_context *ctx, fz_pixmap *pix);
-fz_pixmap *fz_scale_pixmap(fz_context *ctx, fz_pixmap *src, float x, float y, float w, float h, fz_bbox *clip);
+/*
+ fz_pixmap_height: Return the height of the pixmap in pixels.
+*/
+int fz_pixmap_height(fz_context *ctx, fz_pixmap *pix);
-void fz_write_pnm(fz_context *ctx, fz_pixmap *pixmap, char *filename);
-void fz_write_pam(fz_context *ctx, fz_pixmap *pixmap, char *filename, int savealpha);
-void fz_write_png(fz_context *ctx, fz_pixmap *pixmap, char *filename, int savealpha);
+/*
+ fz_new_pixmap: Create a new pixmap, with it's origin at (0,0)
+
+ cs: The colorspace to use for the pixmap, or NULL for an alpha
+ plane/mask.
-fz_pixmap *fz_load_jpx(fz_context *ctx, unsigned char *data, int size, fz_colorspace *cs);
-fz_pixmap *fz_load_jpeg(fz_context *doc, unsigned char *data, int size);
-fz_pixmap *fz_load_png(fz_context *doc, unsigned char *data, int size);
-fz_pixmap *fz_load_tiff(fz_context *doc, unsigned char *data, int size);
+ w: The width of the pixmap (in pixels)
+
+ h: The height of the pixmap (in pixels)
+
+ Returns a pointer to the new pixmap. Throws exception on failure to
+ allocate.
+*/
+fz_pixmap *fz_new_pixmap(fz_context *ctx, fz_colorspace *cs, int w, int h);
/*
- * Bitmaps have 1 component per bit. Only used for creating halftoned versions
- * of contone buffers, and saving out. Samples are stored msb first, akin to
- * pbms.
- */
+ fz_new_pixmap_with_bbox: Create a pixmap of a given size,
+ location and pixel format.
-typedef struct fz_bitmap_s fz_bitmap;
+ The bounding box specifies the size of the created pixmap and
+ where it will be located. The colorspace determines the number
+ of components per pixel. Alpha is always present. Pixmaps are
+ reference counted, so drop references using fz_drop_pixmap.
-struct fz_bitmap_s
-{
- int refs;
- int w, h, stride, n;
- unsigned char *samples;
-};
+ colorspace: Colorspace format used for the created pixmap. The
+ pixmap will keep a reference to the colorspace.
-fz_bitmap *fz_new_bitmap(fz_context *ctx, int w, int h, int n);
-fz_bitmap *fz_keep_bitmap(fz_context *ctx, fz_bitmap *bit);
-void fz_clear_bitmap(fz_context *ctx, fz_bitmap *bit);
-void fz_drop_bitmap(fz_context *ctx, fz_bitmap *bit);
+ bbox: Bounding box specifying location/size of created pixmap.
-void fz_write_pbm(fz_context *ctx, fz_bitmap *bitmap, char *filename);
+ Returns a pointer to the new pixmap. Throws exception on failure to
+ allocate.
+*/
+fz_pixmap *fz_new_pixmap_with_bbox(fz_context *ctx, fz_colorspace *colorspace, fz_bbox bbox);
/*
- * A halftone is a set of threshold tiles, one per component. Each threshold
- * tile is a pixmap, possibly of varying sizes and phases.
- */
+ fz_new_pixmap_with_data: Create a new pixmap, with it's origin at
+ (0,0) using the supplied data block.
-typedef struct fz_halftone_s fz_halftone;
+ cs: The colorspace to use for the pixmap, or NULL for an alpha
+ plane/mask.
-struct fz_halftone_s
-{
- int refs;
- int n;
- fz_pixmap *comp[1];
-};
+ w: The width of the pixmap (in pixels)
-fz_halftone *fz_new_halftone(fz_context *ctx, int num_comps);
-fz_halftone *fz_get_default_halftone(fz_context *ctx, int num_comps);
-fz_halftone *fz_keep_halftone(fz_context *ctx, fz_halftone *half);
-void fz_drop_halftone(fz_context *ctx, fz_halftone *half);
+ h: The height of the pixmap (in pixels)
-fz_bitmap *fz_halftone_pixmap(fz_context *ctx, fz_pixmap *pix, fz_halftone *ht);
+ samples: The data block to keep the samples in.
+
+ Returns a pointer to the new pixmap. Throws exception on failure to
+ allocate.
+*/
+fz_pixmap *fz_new_pixmap_with_data(fz_context *ctx, fz_colorspace *colorspace, int w, int h, unsigned char *samples);
/*
- * Colorspace resources.
- */
+ fz_new_pixmap_with_bbox_and_data: Create a pixmap of a given size,
+ location and pixel format, using the supplied data block.
-extern fz_colorspace *fz_device_gray;
-extern fz_colorspace *fz_device_rgb;
-extern fz_colorspace *fz_device_bgr;
-extern fz_colorspace *fz_device_cmyk;
+ The bounding box specifies the size of the created pixmap and
+ where it will be located. The colorspace determines the number
+ of components per pixel. Alpha is always present. Pixmaps are
+ reference counted, so drop references using fz_drop_pixmap.
-struct fz_colorspace_s
-{
- fz_storable storable;
- unsigned int size;
- char name[16];
- int n;
- void (*to_rgb)(fz_context *ctx, fz_colorspace *, float *src, float *rgb);
- void (*from_rgb)(fz_context *ctx, fz_colorspace *, float *rgb, float *dst);
- void (*free_data)(fz_context *Ctx, fz_colorspace *);
- void *data;
-};
+ colorspace: Colorspace format used for the created pixmap. The
+ pixmap will keep a reference to the colorspace.
-fz_colorspace *fz_new_colorspace(fz_context *ctx, char *name, int n);
-fz_colorspace *fz_keep_colorspace(fz_context *ctx, fz_colorspace *colorspace);
-void fz_drop_colorspace(fz_context *ctx, fz_colorspace *colorspace);
-void fz_free_colorspace_imp(fz_context *ctx, fz_storable *colorspace);
+ bbox: Bounding box specifying location/size of created pixmap.
-void fz_convert_color(fz_context *ctx, fz_colorspace *srcs, float *srcv, fz_colorspace *dsts, float *dstv);
-void fz_convert_pixmap(fz_context *ctx, fz_pixmap *src, fz_pixmap *dst);
+ samples: The data block to keep the samples in.
-fz_colorspace *fz_find_device_colorspace(char *name);
+ Returns a pointer to the new pixmap. Throws exception on failure to
+ allocate.
+*/
+fz_pixmap *fz_new_pixmap_with_bbox_and_data(fz_context *ctx, fz_colorspace *colorspace, fz_bbox bbox, unsigned char *samples);
/*
- * Fonts come in two variants:
- * Regular fonts are handled by FreeType.
- * Type 3 fonts have callbacks to the interpreter.
- */
+ fz_keep_pixmap: Take a reference to a pixmap.
-typedef struct fz_device_s fz_device;
+ pix: The pixmap to increment the reference for.
-typedef struct fz_font_s fz_font;
-char *ft_error_string(int err);
+ Returns pix. Does not throw exceptions.
+*/
+fz_pixmap *fz_keep_pixmap(fz_context *ctx, fz_pixmap *pix);
-struct fz_font_s
-{
- int refs;
- char name[32];
-
- void *ft_face; /* has an FT_Face if used */
- int ft_substitute; /* ... substitute metrics */
- int ft_bold; /* ... synthesize bold */
- int ft_italic; /* ... synthesize italic */
- int ft_hint; /* ... force hinting for DynaLab fonts */
-
- /* origin of font data */
- char *ft_file;
- unsigned char *ft_data;
- int ft_size;
-
- fz_matrix t3matrix;
- fz_obj *t3resources;
- fz_buffer **t3procs; /* has 256 entries if used */
- float *t3widths; /* has 256 entries if used */
- char *t3flags; /* has 256 entries if used */
- void *t3doc; /* a pdf_document for the callback */
- void (*t3run)(void *doc, fz_obj *resources, fz_buffer *contents, fz_device *dev, fz_matrix ctm, void *gstate);
-
- fz_rect bbox; /* font bbox is used only for t3 fonts */
-
- /* per glyph bounding box cache */
- int use_glyph_bbox;
- int bbox_count;
- fz_rect *bbox_table;
-
- /* substitute metrics */
- int width_count;
- int *width_table; /* in 1000 units */
-};
+/*
+ fz_drop_pixmap: Drop a reference and free a pixmap.
-void fz_new_font_context(fz_context *ctx);
-fz_font_context *fz_keep_font_context(fz_context *ctx);
-void fz_drop_font_context(fz_context *ctx);
+ Decrement the reference count for the pixmap. When no
+ references remain the pixmap will be freed.
-fz_font *fz_new_type3_font(fz_context *ctx, char *name, fz_matrix matrix);
+ Does not throw exceptions.
+*/
+void fz_drop_pixmap(fz_context *ctx, fz_pixmap *pix);
-fz_font *fz_new_font_from_memory(fz_context *ctx, unsigned char *data, int len, int index, int use_glyph_bbox);
-fz_font *fz_new_font_from_file(fz_context *ctx, char *path, int index, int use_glyph_bbox);
+/*
+ fz_pixmap_colorspace: Return the colorspace of a pixmap
-fz_font *fz_keep_font(fz_context *ctx, fz_font *font);
-void fz_drop_font(fz_context *ctx, fz_font *font);
+ Returns colorspace. Does not throw exceptions.
+*/
+fz_colorspace *fz_pixmap_colorspace(fz_context *ctx, fz_pixmap *pix);
-void fz_debug_font(fz_context *ctx, fz_font *font);
+/*
+ fz_pixmap_components: Return the number of components in a pixmap.
-void fz_set_font_bbox(fz_context *ctx, fz_font *font, float xmin, float ymin, float xmax, float ymax);
-fz_rect fz_bound_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix trm);
-int fz_glyph_cacheable(fz_context *ctx, fz_font *font, int gid);
+ Returns the number of components. Does not throw exceptions.
+*/
+int fz_pixmap_components(fz_context *ctx, fz_pixmap *pix);
/*
- * Vector path buffer.
- * It can be stroked and dashed, or be filled.
- * It has a fill rule (nonzero or even_odd).
- *
- * When rendering, they are flattened, stroked and dashed straight
- * into the Global Edge List.
- */
+ fz_pixmap_samples: Returns a pointer to the pixel data of a pixmap.
-typedef struct fz_path_s fz_path;
-typedef struct fz_stroke_state_s fz_stroke_state;
+ Returns the pointer. Does not throw exceptions.
+*/
+unsigned char *fz_pixmap_samples(fz_context *ctx, fz_pixmap *pix);
-typedef union fz_path_item_s fz_path_item;
+/*
+ fz_clear_pixmap_with_value: Clears a pixmap with the given value.
-typedef enum fz_path_item_kind_e
-{
- FZ_MOVETO,
- FZ_LINETO,
- FZ_CURVETO,
- FZ_CLOSE_PATH
-} fz_path_item_kind;
+ pix: The pixmap to clear.
-typedef enum fz_linecap_e
-{
- FZ_LINECAP_BUTT = 0,
- FZ_LINECAP_ROUND = 1,
- FZ_LINECAP_SQUARE = 2,
- FZ_LINECAP_TRIANGLE = 3
-} fz_linecap;
+ value: Values in the range 0 to 255 are valid. Each component
+ sample for each pixel in the pixmap will be set to this value,
+ while alpha will always be set to 255 (non-transparent).
-typedef enum fz_linejoin_e
-{
- FZ_LINEJOIN_MITER = 0,
- FZ_LINEJOIN_ROUND = 1,
- FZ_LINEJOIN_BEVEL = 2,
- FZ_LINEJOIN_MITER_XPS = 3
-} fz_linejoin;
+ Does not throw exceptions.
+*/
+void fz_clear_pixmap_with_value(fz_context *ctx, fz_pixmap *pix, int value);
-union fz_path_item_s
-{
- fz_path_item_kind k;
- float v;
-};
+/*
+ fz_clear_pixmap_with_value: Sets all components (including alpha) of
+ all pixels in a pixmap to 0.
-struct fz_path_s
-{
- int len, cap;
- fz_path_item *items;
- int last;
-};
+ pix: The pixmap to clear.
-struct fz_stroke_state_s
-{
- fz_linecap start_cap, dash_cap, end_cap;
- fz_linejoin linejoin;
- float linewidth;
- float miterlimit;
- float dash_phase;
- int dash_len;
- float dash_list[32];
-};
+ Does not throw exceptions.
+*/
+void fz_clear_pixmap(fz_context *ctx, fz_pixmap *pix);
-fz_path *fz_new_path(fz_context *ctx);
-void fz_moveto(fz_context*, fz_path*, float x, float y);
-void fz_lineto(fz_context*, fz_path*, float x, float y);
-void fz_curveto(fz_context*,fz_path*, float, float, float, float, float, float);
-void fz_curvetov(fz_context*,fz_path*, float, float, float, float);
-void fz_curvetoy(fz_context*,fz_path*, float, float, float, float);
-void fz_closepath(fz_context*,fz_path*);
-void fz_free_path(fz_context *ctx, fz_path *path);
+/*
+ fz_invert_pixmap: Invert all the pixels in a pixmap. All components
+ of all pixels are inverted (except alpha, which is unchanged).
-void fz_transform_path(fz_context *ctx, fz_path *path, fz_matrix transform);
+ Does not throw exceptions.
+*/
+void fz_invert_pixmap(fz_context *ctx, fz_pixmap *pix);
-fz_path *fz_clone_path(fz_context *ctx, fz_path *old);
+/*
+ fz_invert_pixmap: Invert all the pixels in a given rectangle of a
+ pixmap. All components of all pixels in the rectangle are inverted
+ (except alpha, which is unchanged).
-fz_rect fz_bound_path(fz_context *ctx, fz_path *path, fz_stroke_state *stroke, fz_matrix ctm);
-void fz_debug_path(fz_context *ctx, fz_path *, int indent);
+ Does not throw exceptions.
+*/
+void fz_invert_pixmap_rect(fz_pixmap *image, fz_bbox rect);
/*
- * Glyph cache
- */
+ fz_gamma_pixmap: Apply gamma correction to a pixmap. All components
+ of all pixels are modified (except alpha, which is unchanged).
-void fz_new_glyph_cache_context(fz_context *ctx);
-fz_glyph_cache *fz_keep_glyph_cache(fz_context *ctx);
-void fz_drop_glyph_cache_context(fz_context *ctx);
-void fz_purge_glyph_cache(fz_context *ctx);
-
-fz_pixmap *fz_render_ft_glyph(fz_context *ctx, fz_font *font, int cid, fz_matrix trm);
-fz_pixmap *fz_render_t3_glyph(fz_context *ctx, fz_font *font, int cid, fz_matrix trm, fz_colorspace *model);
-fz_pixmap *fz_render_ft_stroked_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix trm, fz_matrix ctm, fz_stroke_state *state);
-fz_pixmap *fz_render_glyph(fz_context *ctx, fz_font*, int, fz_matrix, fz_colorspace *model);
-fz_pixmap *fz_render_stroked_glyph(fz_context *ctx, fz_font*, int, fz_matrix, fz_matrix, fz_stroke_state *stroke);
-void fz_render_t3_glyph_direct(fz_context *ctx, fz_device *dev, fz_font *font, int gid, fz_matrix trm, void *gstate);
-
-/*
- * Text buffer.
- *
- * The trm field contains the a, b, c and d coefficients.
- * The e and f coefficients come from the individual elements,
- * together they form the transform matrix for the glyph.
- *
- * Glyphs are referenced by glyph ID.
- * The Unicode text equivalent is kept in a separate array
- * with indexes into the glyph array.
- */
+ gamma: The gamma value to apply; 1.0 for no change.
-typedef struct fz_text_s fz_text;
-typedef struct fz_text_item_s fz_text_item;
+ Does not throw exceptions.
+*/
+void fz_gamma_pixmap(fz_context *ctx, fz_pixmap *pix, float gamma);
-struct fz_text_item_s
-{
- float x, y;
- int gid; /* -1 for one gid to many ucs mappings */
- int ucs; /* -1 for one ucs to many gid mappings */
-};
+/*
+ fz_unmultiply_pixmap: Convert a pixmap from premultiplied to
+ non-premultiplied format.
-struct fz_text_s
-{
- fz_font *font;
- fz_matrix trm;
- int wmode;
- int len, cap;
- fz_text_item *items;
-};
+ Does not throw exceptions.
+*/
+void fz_unmultiply_pixmap(fz_context *ctx, fz_pixmap *pix);
+
+/*
+ fz_convert_pixmap: Convert from one pixmap to another (assumed to be
+ the same size, but possibly with a different colorspace).
+
+ dst: the source pixmap.
-fz_text *fz_new_text(fz_context *ctx, fz_font *face, fz_matrix trm, int wmode);
-void fz_add_text(fz_context *ctx, fz_text *text, int gid, int ucs, float x, float y);
-void fz_free_text(fz_context *ctx, fz_text *text);
-fz_rect fz_bound_text(fz_context *ctx, fz_text *text, fz_matrix ctm);
-fz_text *fz_clone_text(fz_context *ctx, fz_text *old);
-void fz_debug_text(fz_context *ctx, fz_text*, int indent);
+ src: the destination pixmap.
+*/
+void fz_convert_pixmap(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src);
/*
- * The shading code uses gouraud shaded triangle meshes.
- */
+ fz_write_pixmap: Save a pixmap out.
-enum
-{
- FZ_LINEAR,
- FZ_RADIAL,
- FZ_MESH,
-};
+ name: The prefix for the name of the pixmap. The pixmap will be saved
+ as "name.png" if the pixmap is RGB or Greyscale, "name.pam" otherwise.
-typedef struct fz_shade_s fz_shade;
+ rgb: If non zero, the pixmap is converted to rgb (if possible) before
+ saving.
+*/
+void fz_write_pixmap(fz_context *ctx, fz_pixmap *img, char *name, int rgb);
-struct fz_shade_s
-{
- fz_storable storable;
+/*
+ fz_write_pnm: Save a pixmap as a pnm
- fz_rect bbox; /* can be fz_infinite_rect */
- fz_colorspace *colorspace;
+ filename: The filename to save as (including extension).
+*/
+void fz_write_pnm(fz_context *ctx, fz_pixmap *pixmap, char *filename);
- fz_matrix matrix; /* matrix from pattern dict */
- int use_background; /* background color for fills but not 'sh' */
- float background[FZ_MAX_COLORS];
+/*
+ fz_write_pam: Save a pixmap as a pam
- int use_function;
- float function[256][FZ_MAX_COLORS + 1];
+ filename: The filename to save as (including extension).
+*/
+void fz_write_pam(fz_context *ctx, fz_pixmap *pixmap, char *filename, int savealpha);
- int type; /* linear, radial, mesh */
- int extend[2];
+/*
+ fz_write_png: Save a pixmap as a png
- int mesh_len;
- int mesh_cap;
- float *mesh; /* [x y 0], [x y r], [x y t] or [x y c1 ... cn] */
-};
+ filename: The filename to save as (including extension).
+*/
+void fz_write_png(fz_context *ctx, fz_pixmap *pixmap, char *filename, int savealpha);
+
+/*
+ fz_write_pbm: Save a bitmap as a pbm
+
+ filename: The filename to save as (including extension).
+*/
+void fz_write_pbm(fz_context *ctx, fz_bitmap *bitmap, char *filename);
-fz_shade *fz_keep_shade(fz_context *ctx, fz_shade *shade);
-void fz_drop_shade(fz_context *ctx, fz_shade *shade);
-void fz_free_shade_imp(fz_context *ctx, fz_storable *shade);
-void fz_debug_shade(fz_context *ctx, fz_shade *shade);
+/*
+ fz_md5_pixmap: Return the md5 digest for a pixmap
-fz_rect fz_bound_shade(fz_context *ctx, fz_shade *shade, fz_matrix ctm);
-void fz_paint_shade(fz_context *ctx, fz_shade *shade, fz_matrix ctm, fz_pixmap *dest, fz_bbox bbox);
+ filename: The filename to save as (including extension).
+*/
+void fz_md5_pixmap(fz_pixmap *pixmap, unsigned char digest[16]);
/*
- * Scan converter
+ Images are storable objects from which we can obtain fz_pixmaps.
+ These may be implemented as simple wrappers around a pixmap, or as
+ more complex things that decode at different subsample settings on
+ demand.
*/
+typedef struct fz_image_s fz_image;
-int fz_get_aa_level(fz_context *ctx);
-void fz_set_aa_level(fz_context *ctx, int bits);
+/*
+ fz_image_to_pixmap: Called to get a handle to a pixmap from an image.
-typedef struct fz_gel_s fz_gel;
+ image: The image to retrieve a pixmap from.
-fz_gel *fz_new_gel(fz_context *ctx);
-void fz_insert_gel(fz_gel *gel, float x0, float y0, float x1, float y1);
-void fz_reset_gel(fz_gel *gel, fz_bbox clip);
-void fz_sort_gel(fz_gel *gel);
-fz_bbox fz_bound_gel(fz_gel *gel);
-void fz_free_gel(fz_gel *gel);
-int fz_is_rect_gel(fz_gel *gel);
+ w: The desired width (in pixels). This may be completely ignored, but
+ may serve as an indication of a suitable subsample factor to use for
+ image types that support this.
-void fz_scan_convert(fz_gel *gel, int eofill, fz_bbox clip, fz_pixmap *pix, unsigned char *colorbv);
+ h: The desired height (in pixels). This may be completely ignored, but
+ may serve as an indication of a suitable subsample factor to use for
+ image types that support this.
-void fz_flatten_fill_path(fz_gel *gel, fz_path *path, fz_matrix ctm, float flatness);
-void fz_flatten_stroke_path(fz_gel *gel, fz_path *path, fz_stroke_state *stroke, fz_matrix ctm, float flatness, float linewidth);
-void fz_flatten_dash_path(fz_gel *gel, fz_path *path, fz_stroke_state *stroke, fz_matrix ctm, float flatness, float linewidth);
+ Returns a non NULL pixmap pointer. May throw exceptions.
+*/
+fz_pixmap *fz_image_to_pixmap(fz_context *ctx, fz_image *image, int w, int h);
/*
- * The device interface.
- */
+ fz_drop_image: Drop a reference to an image.
-enum
-{
- /* Hints */
- FZ_IGNORE_IMAGE = 1,
- FZ_IGNORE_SHADE = 2,
-
- /* Flags */
- FZ_DEVFLAG_MASK = 1,
- FZ_DEVFLAG_COLOR = 2,
- FZ_DEVFLAG_UNCACHEABLE = 4,
- FZ_DEVFLAG_FILLCOLOR_UNDEFINED = 8,
- FZ_DEVFLAG_STROKECOLOR_UNDEFINED = 16,
- FZ_DEVFLAG_STARTCAP_UNDEFINED = 32,
- FZ_DEVFLAG_DASHCAP_UNDEFINED = 64,
- FZ_DEVFLAG_ENDCAP_UNDEFINED = 128,
- FZ_DEVFLAG_LINEJOIN_UNDEFINED = 256,
- FZ_DEVFLAG_MITERLIMIT_UNDEFINED = 512,
- FZ_DEVFLAG_LINEWIDTH_UNDEFINED = 1024,
- /* Arguably we should have a bit for the dash pattern itself being
- * undefined, but that causes problems; do we assume that it should
- * always be set to non-dashing at the start of every glyph? */
-};
+ image: The image to drop a reference to.
+*/
+void fz_drop_image(fz_context *ctx, fz_image *image);
-struct fz_device_s
-{
- int hints;
- int flags;
+/*
+ fz_keep_image: Increment the reference count of an image.
- void *user;
- void (*free_user)(fz_device *);
- fz_context *ctx;
-
- void (*fill_path)(fz_device *, fz_path *, int even_odd, fz_matrix, fz_colorspace *, float *color, float alpha);
- void (*stroke_path)(fz_device *, fz_path *, fz_stroke_state *, fz_matrix, fz_colorspace *, float *color, float alpha);
- void (*clip_path)(fz_device *, fz_path *, fz_rect *rect, int even_odd, fz_matrix);
- void (*clip_stroke_path)(fz_device *, fz_path *, fz_rect *rect, fz_stroke_state *, fz_matrix);
-
- void (*fill_text)(fz_device *, fz_text *, fz_matrix, fz_colorspace *, float *color, float alpha);
- void (*stroke_text)(fz_device *, fz_text *, fz_stroke_state *, fz_matrix, fz_colorspace *, float *color, float alpha);
- void (*clip_text)(fz_device *, fz_text *, fz_matrix, int accumulate);
- void (*clip_stroke_text)(fz_device *, fz_text *, fz_stroke_state *, fz_matrix);
- void (*ignore_text)(fz_device *, fz_text *, fz_matrix);
-
- void (*fill_shade)(fz_device *, fz_shade *shd, fz_matrix ctm, float alpha);
- void (*fill_image)(fz_device *, fz_pixmap *img, fz_matrix ctm, float alpha);
- void (*fill_image_mask)(fz_device *, fz_pixmap *img, fz_matrix ctm, fz_colorspace *, float *color, float alpha);
- void (*clip_image_mask)(fz_device *, fz_pixmap *img, fz_rect *rect, fz_matrix ctm);
-
- void (*pop_clip)(fz_device *);
-
- void (*begin_mask)(fz_device *, fz_rect, int luminosity, fz_colorspace *, float *bc);
- void (*end_mask)(fz_device *);
- void (*begin_group)(fz_device *, fz_rect, int isolated, int knockout, int blendmode, float alpha);
- void (*end_group)(fz_device *);
-
- void (*begin_tile)(fz_device *, fz_rect area, fz_rect view, float xstep, float ystep, fz_matrix ctm);
- void (*end_tile)(fz_device *);
-};
+ image: The image to take a reference to.
-void fz_fill_path(fz_device *dev, fz_path *path, int even_odd, fz_matrix ctm, fz_colorspace *colorspace, float *color, float alpha);
-void fz_stroke_path(fz_device *dev, fz_path *path, fz_stroke_state *stroke, fz_matrix ctm, fz_colorspace *colorspace, float *color, float alpha);
-void fz_clip_path(fz_device *dev, fz_path *path, fz_rect *rect, int even_odd, fz_matrix ctm);
-void fz_clip_stroke_path(fz_device *dev, fz_path *path, fz_rect *rect, fz_stroke_state *stroke, fz_matrix ctm);
-void fz_fill_text(fz_device *dev, fz_text *text, fz_matrix ctm, fz_colorspace *colorspace, float *color, float alpha);
-void fz_stroke_text(fz_device *dev, fz_text *text, fz_stroke_state *stroke, fz_matrix ctm, fz_colorspace *colorspace, float *color, float alpha);
-void fz_clip_text(fz_device *dev, fz_text *text, fz_matrix ctm, int accumulate);
-void fz_clip_stroke_text(fz_device *dev, fz_text *text, fz_stroke_state *stroke, fz_matrix ctm);
-void fz_ignore_text(fz_device *dev, fz_text *text, fz_matrix ctm);
-void fz_pop_clip(fz_device *dev);
-void fz_fill_shade(fz_device *dev, fz_shade *shade, fz_matrix ctm, float alpha);
-void fz_fill_image(fz_device *dev, fz_pixmap *image, fz_matrix ctm, float alpha);
-void fz_fill_image_mask(fz_device *dev, fz_pixmap *image, fz_matrix ctm, fz_colorspace *colorspace, float *color, float alpha);
-void fz_clip_image_mask(fz_device *dev, fz_pixmap *image, fz_rect *rect, fz_matrix ctm);
-void fz_begin_mask(fz_device *dev, fz_rect area, int luminosity, fz_colorspace *colorspace, float *bc);
-void fz_end_mask(fz_device *dev);
-void fz_begin_group(fz_device *dev, fz_rect area, int isolated, int knockout, int blendmode, float alpha);
-void fz_end_group(fz_device *dev);
-void fz_begin_tile(fz_device *dev, fz_rect area, fz_rect view, float xstep, float ystep, fz_matrix ctm);
-void fz_end_tile(fz_device *dev);
-
-fz_device *fz_new_device(fz_context *ctx, void *user);
+ Returns a pointer to the image.
+*/
+fz_image *fz_keep_image(fz_context *ctx, fz_image *image);
+
+/*
+ A halftone is a set of threshold tiles, one per component. Each
+ threshold tile is a pixmap, possibly of varying sizes and phases.
+ Currently, we only provide one 'default' halftone tile for operating
+ on 1 component plus alpha pixmaps (where the alpha is ignored). This
+ is signified by an fz_halftone pointer to NULL.
+*/
+typedef struct fz_halftone_s fz_halftone;
+
+/*
+ fz_halftone_pixmap: Make a bitmap from a pixmap and a halftone.
+
+ pix: The pixmap to generate from. Currently must be a single color
+ component + alpha (where the alpha is assumed to be solid).
+
+ ht: The halftone to use. NULL implies the default halftone.
+
+ Returns the resultant bitmap. Throws exceptions in the case of
+ failure to allocate.
+*/
+fz_bitmap *fz_halftone_pixmap(fz_context *ctx, fz_pixmap *pix, fz_halftone *ht);
+
+/*
+ An abstract font handle. Currently there are no public API functions
+ for handling these.
+*/
+typedef struct fz_font_s fz_font;
+
+/*
+ The different format handlers (pdf, xps etc) interpret pages to a
+ device. These devices can then process the stream of calls they
+ recieve in various ways:
+ The trace device outputs debugging information for the calls.
+ The draw device will render them.
+ The list device stores them in a list to play back later.
+ The text device performs text extraction and searching.
+ The bbox device calculates the bounding box for the page.
+ Other devices can (and will) be written in future.
+*/
+typedef struct fz_device_s fz_device;
+
+/*
+ fz_free_device: Free a devices of any type and its resources.
+*/
void fz_free_device(fz_device *dev);
+/*
+ fz_new_trace_device: Create a device to print a debug trace of
+ all device calls.
+*/
fz_device *fz_new_trace_device(fz_context *ctx);
+
+/*
+ fz_new_bbox_device: Create a device to compute the bounding
+ box of all marks on a page.
+
+ The returned bounding box will be the union of all bounding
+ boxes of all objects on a page.
+*/
fz_device *fz_new_bbox_device(fz_context *ctx, fz_bbox *bboxp);
+
+/*
+ fz_new_draw_device: Create a device to draw on a pixmap.
+
+ dest: Target pixmap for the draw device. See fz_new_pixmap*
+ for how to obtain a pixmap. The pixmap is not cleared by the
+ draw device, see fz_clear_pixmap* for how to clear it prior to
+ calling fz_new_draw_device. Free the device by calling
+ fz_free_device.
+*/
fz_device *fz_new_draw_device(fz_context *ctx, fz_pixmap *dest);
-fz_device *fz_new_draw_device_type3(fz_context *ctx, fz_pixmap *dest);
/*
- * Text extraction device
+ Text extraction device: Used for searching, format conversion etc.
*/
-typedef struct fz_text_span_s fz_text_span;
+typedef struct fz_text_style_s fz_text_style;
typedef struct fz_text_char_s fz_text_char;
+typedef struct fz_text_span_s fz_text_span;
+typedef struct fz_text_line_s fz_text_line;
+typedef struct fz_text_block_s fz_text_block;
+
+typedef struct fz_text_sheet_s fz_text_sheet;
+typedef struct fz_text_page_s fz_text_page;
+
+struct fz_text_style_s
+{
+ int id;
+ fz_font *font;
+ float size;
+ int wmode;
+ int script;
+ /* etc... */
+ fz_text_style *next;
+};
+
+struct fz_text_sheet_s
+{
+ int maxid;
+ fz_text_style *style;
+};
struct fz_text_char_s
{
+ fz_rect bbox;
int c;
- fz_bbox bbox;
};
struct fz_text_span_s
{
- fz_font *font;
- float size;
- int wmode;
+ fz_rect bbox;
int len, cap;
fz_text_char *text;
- fz_text_span *next;
- int eol;
+ fz_text_style *style;
};
-fz_text_span *fz_new_text_span(fz_context *ctx);
-void fz_free_text_span(fz_context *ctx, fz_text_span *line);
-void fz_debug_text_span(fz_text_span *line);
-void fz_debug_text_span_xml(fz_text_span *span);
+struct fz_text_line_s
+{
+ fz_rect bbox;
+ int len, cap;
+ fz_text_span *spans;
+};
-fz_device *fz_new_text_device(fz_context *ctx, fz_text_span *text);
+struct fz_text_block_s
+{
+ fz_rect bbox;
+ int len, cap;
+ fz_text_line *lines;
+};
+
+struct fz_text_page_s
+{
+ fz_rect mediabox;
+ int len, cap;
+ fz_text_block *blocks;
+};
+
+/*
+ fz_new_text_device: Create a device to extract the text on a page.
+
+ Gather and sort the text on a page into spans of uniform style,
+ arranged into lines and blocks by reading order. The reading order
+ is determined by various heuristics, so may not be accurate.
+*/
+fz_device *fz_new_text_device(fz_context *ctx, fz_text_sheet *sheet, fz_text_page *page);
+
+/*
+ fz_new_text_sheet: Create an empty style sheet.
+
+ The style sheet is filled out by the text device, creating
+ one style for each unique font, color, size combination that
+ is used.
+*/
+fz_text_sheet *fz_new_text_sheet(fz_context *ctx);
+void fz_free_text_sheet(fz_context *ctx, fz_text_sheet *sheet);
+
+/*
+ fz_new_text_page: Create an empty text page.
+
+ The text page is filled out by the text device to contain the blocks,
+ lines and spans of text on the page.
+*/
+fz_text_page *fz_new_text_page(fz_context *ctx, fz_rect mediabox);
+void fz_free_text_page(fz_context *ctx, fz_text_page *page);
+
+void fz_print_text_sheet(fz_context *ctx, FILE *out, fz_text_sheet *sheet);
+void fz_print_text_page_html(fz_context *ctx, FILE *out, fz_text_page *page);
+void fz_print_text_page_xml(fz_context *ctx, FILE *out, fz_text_page *page);
+void fz_print_text_page(fz_context *ctx, FILE *out, fz_text_page *page);
/*
* Cookie support - simple communication channel between app/library.
@@ -1494,6 +1583,40 @@ fz_device *fz_new_text_device(fz_context *ctx, fz_text_span *text);
typedef struct fz_cookie_s fz_cookie;
+/*
+ Provide two-way communication between application and library.
+ Intended for multi-threaded applications where one thread is
+ rendering pages and another thread wants read progress
+ feedback or abort a job that takes a long time to finish. The
+ communication is unsynchronized without locking.
+
+ abort: The appliation should set this field to 0 before
+ calling fz_run_page to render a page. At any point when the
+ page is being rendered the application my set this field to 1
+ which will cause the rendering to finish soon. This field is
+ checked periodically when the page is rendered, but exactly
+ when is not known, therefore there is no upper bound on
+ exactly when the the rendering will abort. If the application
+ did not provide a set of locks to fz_new_context, it must also
+ await the completion of fz_run_page before issuing another
+ call to fz_run_page. Note that once the application has set
+ this field to 1 after it called fz_run_page it may not change
+ the value again.
+
+ progress: Communicates rendering progress back to the
+ application and is read only. Increments as a page is being
+ rendered. The value starts out at 0 and is limited to less
+ than or equal to progress_max, unless progress_max is -1.
+
+ progress_max: Communicates the known upper bound of rendering
+ back to the application and is read only. The maximum value
+ that the progress field may take. If there is no known upper
+ bound on how long the rendering may take this value is -1 and
+ progress is not limited. Note that the value of progress_max
+ may change from -1 to a positive value once an upper bound is
+ known, so take this into consideration when comparing the
+ value of progress to that of progress_max.
+*/
struct fz_cookie_s
{
int abort;
@@ -1502,67 +1625,81 @@ struct fz_cookie_s
};
/*
- * Display list device -- record and play back device commands.
- */
+ Display list device -- record and play back device commands.
+*/
+/*
+ fz_display_list is a list containing drawing commands (text,
+ images, etc.). The intent is two-fold: as a caching-mechanism
+ to reduce parsing of a page, and to be used as a data
+ structure in multi-threading where one thread parses the page
+ and another renders pages.
+
+ Create a displaylist with fz_new_display_list, hand it over to
+ fz_new_list_device to have it populated, and later replay the
+ list (once or many times) by calling fz_run_display_list. When
+ the list is no longer needed free it with fz_free_display_list.
+*/
typedef struct fz_display_list_s fz_display_list;
+/*
+ fz_new_display_list: Create an empty display list.
+
+ A display list contains drawing commands (text, images, etc.).
+ Use fz_new_list_device for populating the list.
+*/
fz_display_list *fz_new_display_list(fz_context *ctx);
-void fz_free_display_list(fz_context *ctx, fz_display_list *list);
+
+/*
+ fz_new_list_device: Create a rendering device for a display list.
+
+ When the device is rendering a page it will populate the
+ display list with drawing commsnds (text, images, etc.). The
+ display list can later be reused to render a page many times
+ without having to re-interpret the page from the document file
+ for each rendering. Once the device is no longer needed, free
+ it with fz_free_device.
+
+ list: A display list that the list device takes ownership of.
+*/
fz_device *fz_new_list_device(fz_context *ctx, fz_display_list *list);
-void fz_run_display_list(fz_display_list *list, fz_device *dev, fz_matrix ctm, fz_bbox area, fz_cookie *cookie);
/*
- * Plotting functions.
- */
+ fz_run_display_list: (Re)-run a display list through a device.
-void fz_decode_tile(fz_pixmap *pix, float *decode);
-void fz_decode_indexed_tile(fz_pixmap *pix, float *decode, int maxval);
-void fz_unpack_tile(fz_pixmap *dst, unsigned char * restrict src, int n, int depth, int stride, int scale);
+ list: A display list, created by fz_new_display_list and
+ populated with objects from a page by running fz_run_page on a
+ device obtained from fz_new_list_device.
-void fz_paint_solid_alpha(unsigned char * restrict dp, int w, int alpha);
-void fz_paint_solid_color(unsigned char * restrict dp, int n, int w, unsigned char *color);
+ dev: Device obtained from fz_new_*_device.
-void fz_paint_span(unsigned char * restrict dp, unsigned char * restrict sp, int n, int w, int alpha);
-void fz_paint_span_with_color(unsigned char * restrict dp, unsigned char * restrict mp, int n, int w, unsigned char *color);
+ ctm: Transform to apply to display list contents. May include
+ for example scaling and rotation, see fz_scale, fz_rotate and
+ fz_concat. Set to fz_identity if no transformation is desired.
-void fz_paint_image(fz_pixmap *dst, fz_bbox scissor, fz_pixmap *shape, fz_pixmap *img, fz_matrix ctm, int alpha);
-void fz_paint_image_with_color(fz_pixmap *dst, fz_bbox scissor, fz_pixmap *shape, fz_pixmap *img, fz_matrix ctm, unsigned char *colorbv);
+ area: Only the part of the contents of the display list
+ visible within this area will be considered when the list is
+ run through the device. This does not imply for tile objects
+ contained in the display list.
-void fz_paint_pixmap(fz_pixmap *dst, fz_pixmap *src, int alpha);
-void fz_paint_pixmap_with_mask(fz_pixmap *dst, fz_pixmap *src, fz_pixmap *msk);
-void fz_paint_pixmap_with_rect(fz_pixmap *dst, fz_pixmap *src, int alpha, fz_bbox bbox);
+ cookie: Communication mechanism between caller and library
+ running the page. Intended for multi-threaded applications,
+ while single-threaded applications set cookie to NULL. The
+ caller may abort an ongoing page run. Cookie also communicates
+ progress information back to the caller. The fields inside
+ cookie are continually updated while the page is being run.
+*/
+void fz_run_display_list(fz_display_list *list, fz_device *dev, fz_matrix ctm, fz_bbox area, fz_cookie *cookie);
-void fz_blend_pixmap(fz_pixmap *dst, fz_pixmap *src, int alpha, int blendmode, int isolated, fz_pixmap *shape);
-void fz_blend_pixel(unsigned char dp[3], unsigned char bp[3], unsigned char sp[3], int blendmode);
+/*
+ fz_free_display_list: Frees a display list.
-enum
-{
- /* PDF 1.4 -- standard separable */
- FZ_BLEND_NORMAL,
- FZ_BLEND_MULTIPLY,
- FZ_BLEND_SCREEN,
- FZ_BLEND_OVERLAY,
- FZ_BLEND_DARKEN,
- FZ_BLEND_LIGHTEN,
- FZ_BLEND_COLOR_DODGE,
- FZ_BLEND_COLOR_BURN,
- FZ_BLEND_HARD_LIGHT,
- FZ_BLEND_SOFT_LIGHT,
- FZ_BLEND_DIFFERENCE,
- FZ_BLEND_EXCLUSION,
-
- /* PDF 1.4 -- standard non-separable */
- FZ_BLEND_HUE,
- FZ_BLEND_SATURATION,
- FZ_BLEND_COLOR,
- FZ_BLEND_LUMINOSITY,
-
- /* For packing purposes */
- FZ_BLEND_MODEMASK = 15,
- FZ_BLEND_ISOLATED = 16,
- FZ_BLEND_KNOCKOUT = 32
-};
+ list: Display list to be freed. Any objects put into the
+ display list by a list device will also be freed.
+
+ Does not throw exceptions.
+*/
+void fz_free_display_list(fz_context *ctx, fz_display_list *list);
/* Links */
@@ -1590,6 +1727,35 @@ enum {
fz_link_flag_r_is_zoom = 64 /* rb.x is actually a zoom figure */
};
+/*
+ fz_link_dest: XXX
+
+ kind: Set to one of FZ_LINK_* to tell what what type of link
+ destination this is, and where in the union to look for
+ information. XXX
+
+ gotor.page: Page number, 0 is the first page of the document. XXX
+
+ gotor.flags: A bitfield consisting of fz_link_flag_* telling
+ what parts of gotor.lt and gotor.rb are valid, whether
+ fitting to width/height should be used, or if an arbitrary
+ zoom factor is used. XXX
+
+ gotor.lt: The top left corner of the destination bounding box. XXX
+ gotor.rb: The bottom right corner of the destination bounding box. XXX
+
+ gotor.file_spec: XXX
+
+ gotor.new_window: XXX
+
+ uri.uri: XXX
+ uri.is_map: XXX
+
+ launch.file_spec: XXX
+ launch.new_window: XXX
+
+ named.named: XXX
+*/
struct fz_link_dest_s
{
fz_link_kind kind;
@@ -1626,6 +1792,25 @@ struct fz_link_dest_s
ld;
};
+/*
+ fz_link is a list of interactive links on a page.
+
+ There is no relation between the order of the links in the
+ list and the order they appear on the page. The list of links
+ for a given page can be obtained from fz_load_links.
+
+ A link is reference counted. Dropping a reference to a link is
+ done by calling fz_drop_link.
+
+ rect: The hot zone. The area that can be clicked in
+ untransformed coordinates.
+
+ dest: Link destinations come in two forms: Page and area that
+ an application should display when this link is activated. Or
+ as an URI that can be given to a browser.
+
+ next: A pointer to the next link on the same page.
+*/
struct fz_link_s
{
int refs;
@@ -1636,13 +1821,37 @@ struct fz_link_s
fz_link *fz_new_link(fz_context *ctx, fz_rect bbox, fz_link_dest dest);
fz_link *fz_keep_link(fz_context *ctx, fz_link *link);
+
+/*
+ fz_drop_link: Drop and free a list of links.
+
+ Does not throw exceptions.
+*/
void fz_drop_link(fz_context *ctx, fz_link *link);
+
void fz_free_link_dest(fz_context *ctx, fz_link_dest *dest);
/* Outline */
typedef struct fz_outline_s fz_outline;
+/*
+ fz_outline is a tree of the outline of a document (also known
+ as table of contents).
+
+ title: Title of outline item using UTF-8 encoding. May be NULL
+ if the outline item has no text string.
+
+ dest: Destination in the document to be displayed when this
+ outline item is activated. May be FZ_LINK_NONE if the outline
+ item does not have a destination.
+
+ next: The next outline item at the same level as this outline
+ item. May be NULL if no more outline items exist at this level.
+
+ down: The outline items immediate children in the hierarchy.
+ May be NULL if no children exist.
+*/
struct fz_outline_s
{
char *title;
@@ -1651,43 +1860,155 @@ struct fz_outline_s
fz_outline *down;
};
-void fz_debug_outline_xml(fz_context *ctx, fz_outline *outline, int level);
-void fz_debug_outline(fz_context *ctx, fz_outline *outline, int level);
-void fz_free_outline(fz_context *ctx, fz_outline *outline);
+/*
+ fz_print_outline_xml: Dump the given outlines as (pseudo) XML.
+
+ out: The file handle to output to.
-/* Document interface */
+ outline: The outlines to output.
+*/
+void fz_print_outline_xml(fz_context *ctx, FILE *out, fz_outline *outline);
+/*
+ fz_print_outline: Dump the given outlines to as text.
+
+ out: The file handle to output to.
+
+ outline: The outlines to output.
+*/
+void fz_print_outline(fz_context *ctx, FILE *out, fz_outline *outline);
+
+/*
+ fz_free_outline: Free hierarchical outline.
+
+ Free an outline obtained from fz_load_outline.
+
+ Does not throw exceptions.
+*/
+void fz_free_outline(fz_context *ctx, fz_outline *outline);
+
+/*
+ Document interface
+*/
typedef struct fz_document_s fz_document;
-typedef struct fz_page_s fz_page; /* doesn't have a definition -- always cast to *_page */
+typedef struct fz_page_s fz_page;
-struct fz_document_s
-{
- void (*close)(fz_document *);
- int (*needs_password)(fz_document *doc);
- int (*authenticate_password)(fz_document *doc, char *password);
- fz_outline *(*load_outline)(fz_document *doc);
- int (*count_pages)(fz_document *doc);
- fz_page *(*load_page)(fz_document *doc, int number);
- fz_link *(*load_links)(fz_document *doc, fz_page *page);
- fz_rect (*bound_page)(fz_document *doc, fz_page *page);
- void (*run_page)(fz_document *doc, fz_page *page, fz_device *dev, fz_matrix transform, fz_cookie *cookie);
- void (*free_page)(fz_document *doc, fz_page *page);
-};
+/*
+ fz_open_document: Open a PDF, XPS or CBZ document.
+
+ Open a document file and read its basic structure so pages and
+ objects can be located. MuPDF will try to repair broken
+ documents (without actually changing the file contents).
+ The returned fz_document is used when calling most other
+ document related functions. Note that it wraps the context, so
+ those functions implicitly can access the global state in
+ context.
+
+ filename: a path to a file as it would be given to open(2).
+*/
fz_document *fz_open_document(fz_context *ctx, char *filename);
+/*
+ fz_close_document: Close and free an open document.
+
+ The resource store in the context associated with fz_document
+ is emptied, and any allocations for the document are freed.
+
+ Does not throw exceptions.
+*/
void fz_close_document(fz_document *doc);
+/*
+ fz_needs_password: Check if a document is encrypted with a
+ non-blank password.
+
+ Does not throw exceptions.
+*/
int fz_needs_password(fz_document *doc);
+
+/*
+ fz_authenticate_password: Test if the given password can
+ decrypt the document.
+
+ password: The password string to be checked. Some document
+ specifications do not specify any particular text encoding, so
+ neither do we.
+
+ Does not throw exceptions.
+*/
int fz_authenticate_password(fz_document *doc, char *password);
+/*
+ fz_load_outline: Load the hierarchical document outline.
+
+ Should be freed by fz_free_outline.
+*/
fz_outline *fz_load_outline(fz_document *doc);
+/*
+ fz_count_pages: Return the number of pages in document
+
+ May return 0 for documents with no pages.
+*/
int fz_count_pages(fz_document *doc);
+
+/*
+ fz_load_page: Load a page.
+
+ After fz_load_page is it possible to retrieve the size of the
+ page using fz_bound_page, or to render the page using
+ fz_run_page_*. Free the page by calling fz_free_page.
+
+ number: page number, 0 is the first page of the document.
+*/
fz_page *fz_load_page(fz_document *doc, int number);
+
+/*
+ fz_load_links: Load the list of links for a page.
+
+ Returns a linked list of all the links on the page, each with
+ its clickable region and link destination. Each link is
+ reference counted so drop and free the list of links by
+ calling fz_drop_link on the pointer return from fz_load_links.
+
+ page: Page obtained from fz_load_page.
+*/
fz_link *fz_load_links(fz_document *doc, fz_page *page);
+
+/*
+ fz_bound_page: Determine the size of a page at 72 dpi.
+
+ Does not throw exceptions.
+*/
fz_rect fz_bound_page(fz_document *doc, fz_page *page);
+
+/*
+ fz_run_page: Run a page through a device.
+
+ page: Page obtained from fz_load_page.
+
+ dev: Device obtained from fz_new_*_device.
+
+ transform: Transform to apply to page. May include for example
+ scaling and rotation, see fz_scale, fz_rotate and fz_concat.
+ Set to fz_identity if no transformation is desired.
+
+ cookie: Communication mechanism between caller and library
+ rendering the page. Intended for multi-threaded applications,
+ while single-threaded applications set cookie to NULL. The
+ caller may abort an ongoing rendering of a page. Cookie also
+ communicates progress information back to the caller. The
+ fields inside cookie are continually updated while the page is
+ rendering.
+*/
void fz_run_page(fz_document *doc, fz_page *page, fz_device *dev, fz_matrix transform, fz_cookie *cookie);
+
+/*
+ fz_free_page: Free a loaded page.
+
+ Does not throw exceptions.
+*/
void fz_free_page(fz_document *doc, fz_page *page);
#endif
diff --git a/fitz/image_jpeg.c b/fitz/image_jpeg.c
index f53b6124..2840adbf 100644
--- a/fitz/image_jpeg.c
+++ b/fitz/image_jpeg.c
@@ -1,4 +1,4 @@
-#include "fitz.h"
+#include "fitz-internal.h"
#include <jpeglib.h>
#include <setjmp.h>
@@ -115,6 +115,9 @@ fz_load_jpeg(fz_context *ctx, unsigned char *rbuf, int rlen)
image->yres = cinfo.Y_density * 254 / 100;
}
+ if (image->xres <= 0) image->xres = 72;
+ if (image->yres <= 0) image->yres = 72;
+
fz_clear_pixmap(ctx, image);
row[0] = fz_malloc(ctx, cinfo.output_components * cinfo.output_width);
diff --git a/fitz/image_jpx.c b/fitz/image_jpx.c
index 4d76b4e8..ac1db35a 100644
--- a/fitz/image_jpx.c
+++ b/fitz/image_jpx.c
@@ -1,4 +1,4 @@
-#include "fitz.h"
+#include "fitz-internal.h"
#define OPJ_STATIC
#include <openjpeg.h>
@@ -144,7 +144,7 @@ fz_load_jpx(fz_context *ctx, unsigned char *data, int size, fz_colorspace *defcs
if (n == 4)
{
fz_pixmap *tmp = fz_new_pixmap(ctx, fz_device_rgb, w, h);
- fz_convert_pixmap(ctx, img, tmp);
+ fz_convert_pixmap(ctx, tmp, img);
fz_drop_pixmap(ctx, img);
img = tmp;
}
diff --git a/fitz/image_md5.c b/fitz/image_md5.c
new file mode 100644
index 00000000..86ba0a12
--- /dev/null
+++ b/fitz/image_md5.c
@@ -0,0 +1,11 @@
+#include "fitz-internal.h"
+
+void fz_md5_pixmap(fz_pixmap *pix, unsigned char digest[16])
+{
+ fz_md5 md5;
+
+ fz_md5_init(&md5);
+ if (pix)
+ fz_md5_update(&md5, pix->samples, pix->w * pix->h * pix->n);
+ fz_md5_final(&md5, digest);
+}
diff --git a/fitz/image_png.c b/fitz/image_png.c
index b3fe39cc..e2092c10 100644
--- a/fitz/image_png.c
+++ b/fitz/image_png.c
@@ -1,4 +1,4 @@
-#include "fitz.h"
+#include "fitz-internal.h"
#include <zlib.h>
diff --git a/fitz/image_save.c b/fitz/image_save.c
new file mode 100644
index 00000000..95be1cd3
--- /dev/null
+++ b/fitz/image_save.c
@@ -0,0 +1,32 @@
+#include "fitz-internal.h"
+
+void fz_write_pixmap(fz_context *ctx, fz_pixmap *img, char *file, int rgb)
+{
+ char name[1024];
+ fz_pixmap *converted = NULL;
+
+ if (!img)
+ return;
+
+ if (rgb && img->colorspace && img->colorspace != fz_device_rgb)
+ {
+ converted = fz_new_pixmap_with_bbox(ctx, fz_device_rgb, fz_pixmap_bbox(ctx, img));
+ fz_convert_pixmap(ctx, converted, img);
+ img = converted;
+ }
+
+ if (img->n <= 4)
+ {
+ sprintf(name, "%s.png", file);
+ printf("extracting image %s\n", name);
+ fz_write_png(ctx, img, name, 0);
+ }
+ else
+ {
+ sprintf(name, "%s.pam", file);
+ printf("extracting image %s\n", name);
+ fz_write_pam(ctx, img, name, 0);
+ }
+
+ fz_drop_pixmap(ctx, converted);
+}
diff --git a/fitz/image_tiff.c b/fitz/image_tiff.c
index fff91a9e..ffd0ea88 100644
--- a/fitz/image_tiff.c
+++ b/fitz/image_tiff.c
@@ -1,4 +1,4 @@
-#include "fitz.h"
+#include "fitz-internal.h"
/*
* TIFF image loader. Should be enough to support TIFF files in XPS.
@@ -789,7 +789,7 @@ fz_load_tiff(fz_context *ctx, unsigned char *buf, int len)
if (image->n == 5)
{
fz_pixmap *rgb = fz_new_pixmap(tiff.ctx, fz_device_rgb, image->w, image->h);
- fz_convert_pixmap(tiff.ctx, image, rgb);
+ fz_convert_pixmap(tiff.ctx, rgb, image);
rgb->xres = image->xres;
rgb->yres = image->yres;
fz_drop_pixmap(ctx, image);
diff --git a/fitz/res_bitmap.c b/fitz/res_bitmap.c
index 2aa28b02..1bd2827d 100644
--- a/fitz/res_bitmap.c
+++ b/fitz/res_bitmap.c
@@ -1,4 +1,4 @@
-#include "fitz.h"
+#include "fitz-internal.h"
fz_bitmap *
fz_new_bitmap(fz_context *ctx, int w, int h, int n)
@@ -74,3 +74,48 @@ fz_write_pbm(fz_context *ctx, fz_bitmap *bitmap, char *filename)
fclose(fp);
}
+
+fz_colorspace *fz_pixmap_colorspace(fz_context *ctx, fz_pixmap *pix)
+{
+ if (!pix)
+ return NULL;
+ return pix->colorspace;
+}
+
+int fz_pixmap_components(fz_context *ctx, fz_pixmap *pix)
+{
+ if (!pix)
+ return 0;
+ return pix->n;
+}
+
+unsigned char *fz_pixmap_samples(fz_context *ctx, fz_pixmap *pix)
+{
+ if (!pix)
+ return NULL;
+ return pix->samples;
+}
+
+void fz_bitmap_details(fz_bitmap *bit, int *w, int *h, int *n, int *stride)
+{
+ if (!bit)
+ {
+ if (w)
+ *w = 0;
+ if (h)
+ *h = 0;
+ if (n)
+ *n = 0;
+ if (stride)
+ *stride = 0;
+ return;
+ }
+ if (w)
+ *w = bit->w;
+ if (h)
+ *h = bit->h;
+ if (n)
+ *n = bit->n;
+ if (stride)
+ *w = bit->stride;
+}
diff --git a/fitz/res_colorspace.c b/fitz/res_colorspace.c
index 413da3ae..587db381 100644
--- a/fitz/res_colorspace.c
+++ b/fitz/res_colorspace.c
@@ -1,4 +1,4 @@
-#include "fitz.h"
+#include "fitz-internal.h"
#define SLOWCMYK
@@ -164,7 +164,7 @@ fz_colorspace *fz_device_bgr = &k_device_bgr;
fz_colorspace *fz_device_cmyk = &k_device_cmyk;
fz_colorspace *
-fz_find_device_colorspace(char *name)
+fz_find_device_colorspace(fz_context *ctx, char *name)
{
if (!strcmp(name, "DeviceGray"))
return fz_device_gray;
@@ -180,7 +180,7 @@ fz_find_device_colorspace(char *name)
/* Fast pixmap color conversions */
-static void fast_gray_to_rgb(fz_pixmap *src, fz_pixmap *dst)
+static void fast_gray_to_rgb(fz_pixmap *dst, fz_pixmap *src)
{
unsigned char *s = src->samples;
unsigned char *d = dst->samples;
@@ -196,7 +196,7 @@ static void fast_gray_to_rgb(fz_pixmap *src, fz_pixmap *dst)
}
}
-static void fast_gray_to_cmyk(fz_pixmap *src, fz_pixmap *dst)
+static void fast_gray_to_cmyk(fz_pixmap *dst, fz_pixmap *src)
{
unsigned char *s = src->samples;
unsigned char *d = dst->samples;
@@ -213,7 +213,7 @@ static void fast_gray_to_cmyk(fz_pixmap *src, fz_pixmap *dst)
}
}
-static void fast_rgb_to_gray(fz_pixmap *src, fz_pixmap *dst)
+static void fast_rgb_to_gray(fz_pixmap *dst, fz_pixmap *src)
{
unsigned char *s = src->samples;
unsigned char *d = dst->samples;
@@ -227,7 +227,7 @@ static void fast_rgb_to_gray(fz_pixmap *src, fz_pixmap *dst)
}
}
-static void fast_bgr_to_gray(fz_pixmap *src, fz_pixmap *dst)
+static void fast_bgr_to_gray(fz_pixmap *dst, fz_pixmap *src)
{
unsigned char *s = src->samples;
unsigned char *d = dst->samples;
@@ -241,7 +241,7 @@ static void fast_bgr_to_gray(fz_pixmap *src, fz_pixmap *dst)
}
}
-static void fast_rgb_to_cmyk(fz_pixmap *src, fz_pixmap *dst)
+static void fast_rgb_to_cmyk(fz_pixmap *dst, fz_pixmap *src)
{
unsigned char *s = src->samples;
unsigned char *d = dst->samples;
@@ -262,7 +262,7 @@ static void fast_rgb_to_cmyk(fz_pixmap *src, fz_pixmap *dst)
}
}
-static void fast_bgr_to_cmyk(fz_pixmap *src, fz_pixmap *dst)
+static void fast_bgr_to_cmyk(fz_pixmap *dst, fz_pixmap *src)
{
unsigned char *s = src->samples;
unsigned char *d = dst->samples;
@@ -283,7 +283,7 @@ static void fast_bgr_to_cmyk(fz_pixmap *src, fz_pixmap *dst)
}
}
-static void fast_cmyk_to_gray(fz_pixmap *src, fz_pixmap *dst)
+static void fast_cmyk_to_gray(fz_pixmap *dst, fz_pixmap *src)
{
unsigned char *s = src->samples;
unsigned char *d = dst->samples;
@@ -300,7 +300,7 @@ static void fast_cmyk_to_gray(fz_pixmap *src, fz_pixmap *dst)
}
}
-static void fast_cmyk_to_rgb(fz_context *ctx, fz_pixmap *src, fz_pixmap *dst)
+static void fast_cmyk_to_rgb(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src)
{
unsigned char *s = src->samples;
unsigned char *d = dst->samples;
@@ -328,7 +328,7 @@ static void fast_cmyk_to_rgb(fz_context *ctx, fz_pixmap *src, fz_pixmap *dst)
}
}
-static void fast_cmyk_to_bgr(fz_context *ctx, fz_pixmap *src, fz_pixmap *dst)
+static void fast_cmyk_to_bgr(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src)
{
unsigned char *s = src->samples;
unsigned char *d = dst->samples;
@@ -356,7 +356,7 @@ static void fast_cmyk_to_bgr(fz_context *ctx, fz_pixmap *src, fz_pixmap *dst)
}
}
-static void fast_rgb_to_bgr(fz_pixmap *src, fz_pixmap *dst)
+static void fast_rgb_to_bgr(fz_pixmap *dst, fz_pixmap *src)
{
unsigned char *s = src->samples;
unsigned char *d = dst->samples;
@@ -373,7 +373,7 @@ static void fast_rgb_to_bgr(fz_pixmap *src, fz_pixmap *dst)
}
static void
-fz_std_conv_pixmap(fz_context *ctx, fz_pixmap *src, fz_pixmap *dst)
+fz_std_conv_pixmap(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src)
{
float srcv[FZ_MAX_COLORS];
float dstv[FZ_MAX_COLORS];
@@ -404,7 +404,7 @@ fz_std_conv_pixmap(fz_context *ctx, fz_pixmap *src, fz_pixmap *dst)
srcv[1] = *s++ - 128;
srcv[2] = *s++ - 128;
- fz_convert_color(ctx, ss, srcv, ds, dstv);
+ fz_convert_color(ctx, ds, dstv, ss, srcv);
for (k = 0; k < dstn; k++)
*d++ = dstv[k] * 255;
@@ -424,7 +424,7 @@ fz_std_conv_pixmap(fz_context *ctx, fz_pixmap *src, fz_pixmap *dst)
for (k = 0; k < srcn; k++)
srcv[k] = *s++ / 255.0f;
- fz_convert_color(ctx, ss, srcv, ds, dstv);
+ fz_convert_color(ctx, ds, dstv, ss, srcv);
for (k = 0; k < dstn; k++)
*d++ = dstv[k] * 255;
@@ -442,7 +442,7 @@ fz_std_conv_pixmap(fz_context *ctx, fz_pixmap *src, fz_pixmap *dst)
for (i = 0; i < 256; i++)
{
srcv[0] = i / 255.0f;
- fz_convert_color(ctx, ss, srcv, ds, dstv);
+ fz_convert_color(ctx, ds, dstv, ss, srcv);
for (k = 0; k < dstn; k++)
lookup[i * dstn + k] = dstv[k] * 255;
}
@@ -465,7 +465,7 @@ fz_std_conv_pixmap(fz_context *ctx, fz_pixmap *src, fz_pixmap *dst)
fz_hash_table *lookup;
unsigned char *color;
- lookup = fz_new_hash_table(ctx, 509, srcn);
+ lookup = fz_new_hash_table(ctx, 509, srcn, -1);
for (y = 0; y < src->h; y++)
{
@@ -483,7 +483,7 @@ fz_std_conv_pixmap(fz_context *ctx, fz_pixmap *src, fz_pixmap *dst)
{
for (k = 0; k < srcn; k++)
srcv[k] = *s++ / 255.0f;
- fz_convert_color(ctx, ss, srcv, ds, dstv);
+ fz_convert_color(ctx, ds, dstv, ss, srcv);
for (k = 0; k < dstn; k++)
*d++ = dstv[k] * 255;
@@ -499,50 +499,48 @@ fz_std_conv_pixmap(fz_context *ctx, fz_pixmap *src, fz_pixmap *dst)
}
void
-fz_convert_pixmap(fz_context *ctx, fz_pixmap *sp, fz_pixmap *dp)
+fz_convert_pixmap(fz_context *ctx, fz_pixmap *dp, fz_pixmap *sp)
{
fz_colorspace *ss = sp->colorspace;
fz_colorspace *ds = dp->colorspace;
assert(ss && ds);
- if (sp->mask)
- dp->mask = fz_keep_pixmap(ctx, sp->mask);
dp->interpolate = sp->interpolate;
if (ss == fz_device_gray)
{
- if (ds == fz_device_rgb) fast_gray_to_rgb(sp, dp);
- else if (ds == fz_device_bgr) fast_gray_to_rgb(sp, dp); /* bgr == rgb here */
- else if (ds == fz_device_cmyk) fast_gray_to_cmyk(sp, dp);
- else fz_std_conv_pixmap(ctx, sp, dp);
+ if (ds == fz_device_rgb) fast_gray_to_rgb(dp, sp);
+ else if (ds == fz_device_bgr) fast_gray_to_rgb(dp, sp); /* bgr == rgb here */
+ else if (ds == fz_device_cmyk) fast_gray_to_cmyk(dp, sp);
+ else fz_std_conv_pixmap(ctx, dp, sp);
}
else if (ss == fz_device_rgb)
{
- if (ds == fz_device_gray) fast_rgb_to_gray(sp, dp);
- else if (ds == fz_device_bgr) fast_rgb_to_bgr(sp, dp);
- else if (ds == fz_device_cmyk) fast_rgb_to_cmyk(sp, dp);
- else fz_std_conv_pixmap(ctx, sp, dp);
+ if (ds == fz_device_gray) fast_rgb_to_gray(dp, sp);
+ else if (ds == fz_device_bgr) fast_rgb_to_bgr(dp, sp);
+ else if (ds == fz_device_cmyk) fast_rgb_to_cmyk(dp, sp);
+ else fz_std_conv_pixmap(ctx, dp, sp);
}
else if (ss == fz_device_bgr)
{
- if (ds == fz_device_gray) fast_bgr_to_gray(sp, dp);
- else if (ds == fz_device_rgb) fast_rgb_to_bgr(sp, dp); /* bgr = rgb here */
+ if (ds == fz_device_gray) fast_bgr_to_gray(dp, sp);
+ else if (ds == fz_device_rgb) fast_rgb_to_bgr(dp, sp); /* bgr = rgb here */
else if (ds == fz_device_cmyk) fast_bgr_to_cmyk(sp, dp);
- else fz_std_conv_pixmap(ctx, sp, dp);
+ else fz_std_conv_pixmap(ctx, dp, sp);
}
else if (ss == fz_device_cmyk)
{
- if (ds == fz_device_gray) fast_cmyk_to_gray(sp, dp);
- else if (ds == fz_device_bgr) fast_cmyk_to_bgr(ctx, sp, dp);
- else if (ds == fz_device_rgb) fast_cmyk_to_rgb(ctx, sp, dp);
- else fz_std_conv_pixmap(ctx, sp, dp);
+ if (ds == fz_device_gray) fast_cmyk_to_gray(dp, sp);
+ else if (ds == fz_device_bgr) fast_cmyk_to_bgr(ctx, dp, sp);
+ else if (ds == fz_device_rgb) fast_cmyk_to_rgb(ctx, dp, sp);
+ else fz_std_conv_pixmap(ctx, dp, sp);
}
- else fz_std_conv_pixmap(ctx, sp, dp);
+ else fz_std_conv_pixmap(ctx, dp, sp);
}
/* Convert a single color */
@@ -569,7 +567,7 @@ fz_std_conv_color(fz_context *ctx, fz_colorspace *srcs, float *srcv, fz_colorspa
}
void
-fz_convert_color(fz_context *ctx, fz_colorspace *ss, float *sv, fz_colorspace *ds, float *dv)
+fz_convert_color(fz_context *ctx, fz_colorspace *ds, float *dv, fz_colorspace *ss, float *sv)
{
if (ss == fz_device_gray)
{
diff --git a/fitz/res_font.c b/fitz/res_font.c
index 7a194da6..c1db35d8 100644
--- a/fitz/res_font.c
+++ b/fitz/res_font.c
@@ -1,4 +1,4 @@
-#include "fitz.h"
+#include "fitz-internal.h"
#include <ft2build.h>
#include FT_FREETYPE_H
@@ -93,7 +93,7 @@ fz_drop_font(fz_context *ctx, fz_font *font)
if (font->t3procs)
{
if (font->t3resources)
- fz_drop_obj(font->t3resources);
+ font->t3freeres(font->t3doc, font->t3resources);
for (i = 0; i < 256; i++)
if (font->t3procs[i])
fz_drop_buffer(ctx, font->t3procs[i]);
@@ -387,12 +387,13 @@ fz_copy_ft_bitmap(fz_context *ctx, int left, int top, FT_Bitmap *bitmap)
/* The glyph cache lock is always taken when this is called. */
fz_pixmap *
-fz_render_ft_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix trm)
+fz_render_ft_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix trm, int aa)
{
FT_Face face = font->ft_face;
FT_Matrix m;
FT_Vector v;
FT_Error fterr;
+ fz_pixmap *result;
trm = fz_adjust_ft_glyph_width(ctx, font, gid, trm);
@@ -420,7 +421,7 @@ fz_render_ft_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix trm)
fz_warn(ctx, "freetype setting character size: %s", ft_error_string(fterr));
FT_Set_Transform(face, &m, &v);
- if (fz_get_aa_level(ctx) == 0)
+ if (aa == 0)
{
/* If you really want grid fitting, enable this code. */
float scale = fz_matrix_expansion(trm);
@@ -470,16 +471,17 @@ fz_render_ft_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix trm)
FT_Outline_Translate(&face->glyph->outline, -strength * 32, -strength * 32);
}
- fterr = FT_Render_Glyph(face->glyph, fz_get_aa_level(ctx) > 0 ? FT_RENDER_MODE_NORMAL : FT_RENDER_MODE_MONO);
+ fterr = FT_Render_Glyph(face->glyph, fz_aa_level(ctx) > 0 ? FT_RENDER_MODE_NORMAL : FT_RENDER_MODE_MONO);
if (fterr)
{
fz_warn(ctx, "freetype render glyph (gid %d): %s", gid, ft_error_string(fterr));
fz_unlock(ctx, FZ_LOCK_FREETYPE);
return NULL;
}
- fz_unlock(ctx, FZ_LOCK_FREETYPE);
- return fz_copy_ft_bitmap(ctx, face->glyph->bitmap_left, face->glyph->bitmap_top, &face->glyph->bitmap);
+ result = fz_copy_ft_bitmap(ctx, face->glyph->bitmap_left, face->glyph->bitmap_top, &face->glyph->bitmap);
+ fz_unlock(ctx, FZ_LOCK_FREETYPE);
+ return result;
}
fz_pixmap *
@@ -573,7 +575,7 @@ fz_render_ft_stroked_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix tr
FT_Stroker_Done(stroker);
- fterr = FT_Glyph_To_Bitmap(&glyph, fz_get_aa_level(ctx) > 0 ? FT_RENDER_MODE_NORMAL : FT_RENDER_MODE_MONO, 0, 1);
+ fterr = FT_Glyph_To_Bitmap(&glyph, fz_aa_level(ctx) > 0 ? FT_RENDER_MODE_NORMAL : FT_RENDER_MODE_MONO, 0, 1);
if (fterr)
{
fz_warn(ctx, "FT_Glyph_To_Bitmap: %s", ft_error_string(fterr));
@@ -754,7 +756,7 @@ fz_render_t3_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix trm, fz_co
bbox.x1++;
bbox.y1++;
- glyph = fz_new_pixmap_with_rect(ctx, model ? model : fz_device_gray, bbox);
+ glyph = fz_new_pixmap_with_bbox(ctx, model ? model : fz_device_gray, bbox);
fz_clear_pixmap(ctx, glyph);
ctm = fz_concat(font->t3matrix, trm);
@@ -806,29 +808,29 @@ fz_render_t3_glyph_direct(fz_context *ctx, fz_device *dev, fz_font *font, int gi
}
void
-fz_debug_font(fz_context *ctx, fz_font *font)
+fz_print_font(fz_context *ctx, FILE *out, fz_font *font)
{
- printf("font '%s' {\n", font->name);
+ fprintf(out, "font '%s' {\n", font->name);
if (font->ft_face)
{
- printf("\tfreetype face %p\n", font->ft_face);
+ fprintf(out, "\tfreetype face %p\n", font->ft_face);
if (font->ft_substitute)
- printf("\tsubstitute font\n");
+ fprintf(out, "\tsubstitute font\n");
}
if (font->t3procs)
{
- printf("\ttype3 matrix [%g %g %g %g]\n",
+ fprintf(out, "\ttype3 matrix [%g %g %g %g]\n",
font->t3matrix.a, font->t3matrix.b,
font->t3matrix.c, font->t3matrix.d);
- printf("\ttype3 bbox [%g %g %g %g]\n",
+ fprintf(out, "\ttype3 bbox [%g %g %g %g]\n",
font->bbox.x0, font->bbox.y0,
font->bbox.x1, font->bbox.y1);
}
- printf("}\n");
+ fprintf(out, "}\n");
}
fz_rect
diff --git a/fitz/res_halftone.c b/fitz/res_halftone.c
index 7258ad01..daad6e37 100644
--- a/fitz/res_halftone.c
+++ b/fitz/res_halftone.c
@@ -1,4 +1,4 @@
-#include "fitz.h"
+#include "fitz-internal.h"
fz_halftone *
fz_new_halftone(fz_context *ctx, int comps)
@@ -56,7 +56,7 @@ static unsigned char mono_ht[] =
0xF2, 0x72, 0xD2, 0x52, 0xFA, 0x7A, 0xDA, 0x5A, 0xF0, 0x70, 0xD0, 0x50, 0xF8, 0x78, 0xD8, 0x58
};
-fz_halftone *fz_get_default_halftone(fz_context *ctx, int num_comps)
+fz_halftone *fz_default_halftone(fz_context *ctx, int num_comps)
{
fz_halftone *ht = fz_new_halftone(ctx, num_comps);
assert(num_comps == 1); /* Only support 1 component for now */
@@ -162,13 +162,18 @@ fz_bitmap *fz_halftone_pixmap(fz_context *ctx, fz_pixmap *pix, fz_halftone *ht)
fz_bitmap *out;
unsigned char *ht_line, *o, *p;
int w, h, x, y, n, pstride, ostride;
+ fz_halftone *ht_orig = ht;
- if (!pix || !ht)
+ if (!pix)
return NULL;
assert(pix->n == 2); /* Mono + Alpha */
n = pix->n-1; /* Remove alpha */
+ if (ht == NULL)
+ {
+ ht = fz_default_halftone(ctx, n);
+ }
ht_line = fz_malloc(ctx, pix->w * n);
out = fz_new_bitmap(ctx, pix->w, pix->h, n);
o = out->samples;
@@ -187,5 +192,7 @@ fz_bitmap *fz_halftone_pixmap(fz_context *ctx, fz_pixmap *pix, fz_halftone *ht)
o += ostride;
p += pstride;
}
+ if (!ht_orig)
+ fz_drop_halftone(ctx, ht);
return out;
}
diff --git a/fitz/res_path.c b/fitz/res_path.c
index a645f9d5..45ead677 100644
--- a/fitz/res_path.c
+++ b/fitz/res_path.c
@@ -1,5 +1,5 @@
#include <assert.h>
-#include "fitz.h"
+#include "fitz-internal.h"
fz_path *
fz_new_path(fz_context *ctx)
@@ -316,7 +316,7 @@ fz_transform_path(fz_context *ctx, fz_path *path, fz_matrix ctm)
}
void
-fz_debug_path(fz_context *ctx, fz_path *path, int indent)
+fz_print_path(fz_context *ctx, FILE *out, fz_path *path, int indent)
{
float x, y;
int i = 0;
@@ -324,32 +324,32 @@ fz_debug_path(fz_context *ctx, fz_path *path, int indent)
while (i < path->len)
{
for (n = 0; n < indent; n++)
- putchar(' ');
+ fputc(' ', out);
switch (path->items[i++].k)
{
case FZ_MOVETO:
x = path->items[i++].v;
y = path->items[i++].v;
- printf("%g %g m\n", x, y);
+ fprintf(out, "%g %g m\n", x, y);
break;
case FZ_LINETO:
x = path->items[i++].v;
y = path->items[i++].v;
- printf("%g %g l\n", x, y);
+ fprintf(out, "%g %g l\n", x, y);
break;
case FZ_CURVETO:
x = path->items[i++].v;
y = path->items[i++].v;
- printf("%g %g ", x, y);
+ fprintf(out, "%g %g ", x, y);
x = path->items[i++].v;
y = path->items[i++].v;
- printf("%g %g ", x, y);
+ fprintf(out, "%g %g ", x, y);
x = path->items[i++].v;
y = path->items[i++].v;
- printf("%g %g c\n", x, y);
+ fprintf(out, "%g %g c\n", x, y);
break;
case FZ_CLOSE_PATH:
- printf("h\n");
+ fprintf(out, "h\n");
break;
}
}
diff --git a/fitz/res_pixmap.c b/fitz/res_pixmap.c
index dbed0842..a160b6ca 100644
--- a/fitz/res_pixmap.c
+++ b/fitz/res_pixmap.c
@@ -1,4 +1,4 @@
-#include "fitz.h"
+#include "fitz-internal.h"
fz_pixmap *
fz_keep_pixmap(fz_context *ctx, fz_pixmap *pix)
@@ -17,8 +17,6 @@ fz_free_pixmap_imp(fz_context *ctx, fz_storable *pix_)
{
fz_pixmap *pix = (fz_pixmap *)pix_;
- if (pix->mask)
- fz_drop_pixmap(ctx, pix->mask);
if (pix->colorspace)
fz_drop_colorspace(ctx, pix->colorspace);
if (pix->free_samples)
@@ -37,7 +35,6 @@ fz_new_pixmap_with_data(fz_context *ctx, fz_colorspace *colorspace, int w, int h
pix->y = 0;
pix->w = w;
pix->h = h;
- pix->mask = NULL;
pix->interpolate = 1;
pix->xres = 96;
pix->yres = 96;
@@ -65,6 +62,8 @@ fz_new_pixmap_with_data(fz_context *ctx, fz_colorspace *colorspace, int w, int h
}
fz_catch(ctx)
{
+ if (colorspace)
+ fz_drop_colorspace(ctx, colorspace);
fz_free(ctx, pix);
fz_rethrow(ctx);
}
@@ -81,7 +80,7 @@ fz_new_pixmap(fz_context *ctx, fz_colorspace *colorspace, int w, int h)
}
fz_pixmap *
-fz_new_pixmap_with_rect(fz_context *ctx, fz_colorspace *colorspace, fz_bbox r)
+fz_new_pixmap_with_bbox(fz_context *ctx, fz_colorspace *colorspace, fz_bbox r)
{
fz_pixmap *pixmap;
pixmap = fz_new_pixmap(ctx, colorspace, r.x1 - r.x0, r.y1 - r.y0);
@@ -91,7 +90,7 @@ fz_new_pixmap_with_rect(fz_context *ctx, fz_colorspace *colorspace, fz_bbox r)
}
fz_pixmap *
-fz_new_pixmap_with_rect_and_data(fz_context *ctx, fz_colorspace *colorspace, fz_bbox r, unsigned char *samples)
+fz_new_pixmap_with_bbox_and_data(fz_context *ctx, fz_colorspace *colorspace, fz_bbox r, unsigned char *samples)
{
fz_pixmap *pixmap;
pixmap = fz_new_pixmap_with_data(ctx, colorspace, r.x1 - r.x0, r.y1 - r.y0, samples);
@@ -101,7 +100,7 @@ fz_new_pixmap_with_rect_and_data(fz_context *ctx, fz_colorspace *colorspace, fz_
}
fz_bbox
-fz_bound_pixmap(fz_pixmap *pix)
+fz_pixmap_bbox(fz_context *ctx, fz_pixmap *pix)
{
fz_bbox bbox;
bbox.x0 = pix->x;
@@ -111,6 +110,29 @@ fz_bound_pixmap(fz_pixmap *pix)
return bbox;
}
+fz_bbox
+fz_pixmap_bbox_no_ctx(fz_pixmap *pix)
+{
+ fz_bbox bbox;
+ bbox.x0 = pix->x;
+ bbox.y0 = pix->y;
+ bbox.x1 = pix->x + pix->w;
+ bbox.y1 = pix->y + pix->h;
+ return bbox;
+}
+
+int
+fz_pixmap_width(fz_context *ctx, fz_pixmap *pix)
+{
+ return pix->w;
+}
+
+int
+fz_pixmap_height(fz_context *ctx, fz_pixmap *pix)
+{
+ return pix->h;
+}
+
void
fz_clear_pixmap(fz_context *ctx, fz_pixmap *pix)
{
@@ -145,8 +167,8 @@ fz_copy_pixmap_rect(fz_context *ctx, fz_pixmap *dest, fz_pixmap *src, fz_bbox r)
unsigned char *destp;
int y, w, destspan, srcspan;
- r = fz_intersect_bbox(r, fz_bound_pixmap(dest));
- r = fz_intersect_bbox(r, fz_bound_pixmap(src));
+ r = fz_intersect_bbox(r, fz_pixmap_bbox(ctx, dest));
+ r = fz_intersect_bbox(r, fz_pixmap_bbox(ctx, src));
w = r.x1 - r.x0;
y = r.y1 - r.y0;
if (w <= 0 || y <= 0)
@@ -172,7 +194,7 @@ fz_clear_pixmap_rect_with_value(fz_context *ctx, fz_pixmap *dest, int value, fz_
unsigned char *destp;
int x, y, w, k, destspan;
- r = fz_intersect_bbox(r, fz_bound_pixmap(dest));
+ r = fz_intersect_bbox(r, fz_pixmap_bbox(ctx, dest));
w = r.x1 - r.x0;
y = r.y1 - r.y0;
if (w <= 0 || y <= 0)
@@ -250,7 +272,7 @@ fz_alpha_from_gray(fz_context *ctx, fz_pixmap *gray, int luminosity)
assert(gray->n == 2);
- alpha = fz_new_pixmap_with_rect(ctx, NULL, fz_bound_pixmap(gray));
+ alpha = fz_new_pixmap_with_bbox(ctx, NULL, fz_pixmap_bbox(ctx, gray));
dp = alpha->samples;
sp = gray->samples;
if (!luminosity)
@@ -283,6 +305,27 @@ fz_invert_pixmap(fz_context *ctx, fz_pixmap *pix)
}
}
+void fz_invert_pixmap_rect(fz_pixmap *image, fz_bbox rect)
+{
+ unsigned char *p;
+ int x, y, n;
+
+ int x0 = CLAMP(rect.x0 - image->x, 0, image->w - 1);
+ int x1 = CLAMP(rect.x1 - image->x, 0, image->w - 1);
+ int y0 = CLAMP(rect.y0 - image->y, 0, image->h - 1);
+ int y1 = CLAMP(rect.y1 - image->y, 0, image->h - 1);
+
+ for (y = y0; y < y1; y++)
+ {
+ p = image->samples + (y * image->w + x0) * image->n;
+ for (x = x0; x < x1; x++)
+ {
+ for (n = image->n; n > 0; n--, p++)
+ *p = 255 - *p;
+ }
+ }
+}
+
void
fz_gamma_pixmap(fz_context *ctx, fz_pixmap *pix, float gamma)
{
@@ -549,3 +592,23 @@ fz_pixmap_size(fz_context *ctx, fz_pixmap * pix)
return 0;
return sizeof(*pix) + pix->n * pix->w * pix->h;
}
+
+fz_pixmap *
+fz_image_to_pixmap(fz_context *ctx, fz_image *image, int w, int h)
+{
+ if (image == NULL)
+ return NULL;
+ return image->get_pixmap(ctx, image, w, h);
+}
+
+fz_image *
+fz_keep_image(fz_context *ctx, fz_image *image)
+{
+ return (fz_image *)fz_keep_storable(ctx, &image->storable);
+}
+
+void
+fz_drop_image(fz_context *ctx, fz_image *image)
+{
+ fz_drop_storable(ctx, &image->storable);
+}
diff --git a/fitz/res_shade.c b/fitz/res_shade.c
index 3fdf2e15..d2b2f44b 100644
--- a/fitz/res_shade.c
+++ b/fitz/res_shade.c
@@ -1,4 +1,4 @@
-#include "fitz.h"
+#include "fitz-internal.h"
fz_shade *
fz_keep_shade(fz_context *ctx, fz_shade *shade)
@@ -68,59 +68,59 @@ fz_bound_shade(fz_context *ctx, fz_shade *shade, fz_matrix ctm)
}
void
-fz_debug_shade(fz_context *ctx, fz_shade *shade)
+fz_print_shade(fz_context *ctx, FILE *out, fz_shade *shade)
{
int i, j, n;
float *vertex;
int triangle;
- printf("shading {\n");
+ fprintf(out, "shading {\n");
switch (shade->type)
{
- case FZ_LINEAR: printf("\ttype linear\n"); break;
- case FZ_RADIAL: printf("\ttype radial\n"); break;
- case FZ_MESH: printf("\ttype mesh\n"); break;
+ case FZ_LINEAR: fprintf(out, "\ttype linear\n"); break;
+ case FZ_RADIAL: fprintf(out, "\ttype radial\n"); break;
+ case FZ_MESH: fprintf(out, "\ttype mesh\n"); break;
}
- printf("\tbbox [%g %g %g %g]\n",
+ fprintf(out, "\tbbox [%g %g %g %g]\n",
shade->bbox.x0, shade->bbox.y0,
shade->bbox.x1, shade->bbox.y1);
- printf("\tcolorspace %s\n", shade->colorspace->name);
+ fprintf(out, "\tcolorspace %s\n", shade->colorspace->name);
- printf("\tmatrix [%g %g %g %g %g %g]\n",
+ fprintf(out, "\tmatrix [%g %g %g %g %g %g]\n",
shade->matrix.a, shade->matrix.b, shade->matrix.c,
shade->matrix.d, shade->matrix.e, shade->matrix.f);
if (shade->use_background)
{
- printf("\tbackground [");
+ fprintf(out, "\tbackground [");
for (i = 0; i < shade->colorspace->n; i++)
- printf("%s%g", i == 0 ? "" : " ", shade->background[i]);
- printf("]\n");
+ fprintf(out, "%s%g", i == 0 ? "" : " ", shade->background[i]);
+ fprintf(out, "]\n");
}
if (shade->use_function)
{
- printf("\tfunction\n");
+ fprintf(out, "\tfunction\n");
n = 3;
}
else
n = 2 + shade->colorspace->n;
- printf("\tvertices: %d\n", shade->mesh_len);
+ fprintf(out, "\tvertices: %d\n", shade->mesh_len);
vertex = shade->mesh;
triangle = 0;
i = 0;
while (i < shade->mesh_len)
{
- printf("\t%d:(%g, %g): ", triangle, vertex[0], vertex[1]);
+ fprintf(out, "\t%d:(%g, %g): ", triangle, vertex[0], vertex[1]);
for (j = 2; j < n; j++)
- printf("%s%g", j == 2 ? "" : " ", vertex[j]);
- printf("\n");
+ fprintf(out, "%s%g", j == 2 ? "" : " ", vertex[j]);
+ fprintf(out, "\n");
vertex += n;
i++;
@@ -128,5 +128,5 @@ fz_debug_shade(fz_context *ctx, fz_shade *shade)
triangle++;
}
- printf("}\n");
+ fprintf(out, "}\n");
}
diff --git a/fitz/res_store.c b/fitz/res_store.c
index 5eec1f0d..8e5375d6 100644
--- a/fitz/res_store.c
+++ b/fitz/res_store.c
@@ -1,21 +1,16 @@
-#include "fitz.h"
-#include "mupdf.h"
+#include "fitz-internal.h"
+
+typedef struct fz_item_s fz_item;
struct fz_item_s
{
- fz_obj *key;
+ void *key;
fz_storable *val;
unsigned int size;
fz_item *next;
fz_item *prev;
fz_store *store;
-};
-
-struct refkey
-{
- fz_store_free_fn *free;
- int num;
- int gen;
+ fz_store_type *type;
};
struct fz_store_s
@@ -43,7 +38,7 @@ fz_new_store_context(fz_context *ctx, unsigned int max)
store = fz_malloc_struct(ctx, fz_store);
fz_try(ctx)
{
- store->hash = fz_new_hash_table(ctx, 4096, sizeof(struct refkey));
+ store->hash = fz_new_hash_table(ctx, 4096, sizeof(fz_store_hash), FZ_LOCK_ALLOC);
}
fz_catch(ctx)
{
@@ -114,20 +109,19 @@ evict(fz_context *ctx, fz_item *item)
store->head = item->next;
/* Drop a reference to the value (freeing if required) */
drop = (item->val->refs > 0 && --item->val->refs == 0);
- fz_unlock(ctx, FZ_LOCK_ALLOC);
/* Remove from the hash table */
- if (fz_is_indirect(item->key))
+ if (item->type->make_hash_key)
{
- struct refkey refkey;
- refkey.free = item->val->free;
- refkey.num = fz_to_num(item->key);
- refkey.gen = fz_to_gen(item->key);
- fz_hash_remove(ctx, store->hash, &refkey);
+ fz_store_hash hash = { NULL };
+ hash.free = item->val->free;
+ if (item->type->make_hash_key(&hash, item->key))
+ fz_hash_remove(ctx, store->hash, &hash);
}
+ fz_unlock(ctx, FZ_LOCK_ALLOC);
if (drop)
item->val->free(ctx, item->val);
/* Always drops the key and free the item */
- fz_drop_obj(item->key);
+ item->type->drop_key(ctx, item->key);
fz_free(ctx, item);
fz_lock(ctx, FZ_LOCK_ALLOC);
}
@@ -194,30 +188,21 @@ ensure_space(fz_context *ctx, unsigned int tofree)
return count;
}
-void
-fz_store_item(fz_context *ctx, fz_obj *key, void *val_, unsigned int itemsize)
+void *
+fz_store_item(fz_context *ctx, void *key, void *val_, unsigned int itemsize, fz_store_type *type)
{
fz_item *item = NULL;
unsigned int size;
fz_storable *val = (fz_storable *)val_;
fz_store *store = ctx->store;
- int indirect;
- struct refkey refkey;
+ fz_store_hash hash = { NULL };
+ int use_hash = 0;
if (!store)
- return;
+ return NULL;
fz_var(item);
- /* Form the key before we take the lock */
- indirect = fz_is_indirect(key);
- if (indirect)
- {
- refkey.free = val->free;
- refkey.num = fz_to_num(key);
- refkey.gen = fz_to_gen(key);
- }
-
/* If we fail for any reason, we swallow the exception and continue.
* All that the above program will see is that we failed to store
* the item. */
@@ -227,9 +212,16 @@ fz_store_item(fz_context *ctx, fz_obj *key, void *val_, unsigned int itemsize)
}
fz_catch(ctx)
{
- return;
+ return NULL;
}
+ if (type->make_hash_key)
+ {
+ hash.free = val->free;
+ use_hash = type->make_hash_key(&hash, key);
+ }
+
+ type->keep_key(ctx, key);
fz_lock(ctx, FZ_LOCK_ALLOC);
if (store->max != FZ_STORE_UNLIMITED)
{
@@ -242,34 +234,44 @@ fz_store_item(fz_context *ctx, fz_obj *key, void *val_, unsigned int itemsize)
/* Failed to free any space */
fz_unlock(ctx, FZ_LOCK_ALLOC);
fz_free(ctx, item);
- return;
+ type->drop_key(ctx, key);
+ return NULL;
}
}
}
store->size += itemsize;
- item->key = fz_keep_obj(key);
+ item->key = key;
item->val = val;
item->size = itemsize;
item->next = NULL;
+ item->type = type;
/* If we can index it fast, put it into the hash table */
- if (indirect)
+ if (use_hash)
{
- fz_unlock(ctx, FZ_LOCK_ALLOC);
+ fz_item *existing;
+
fz_try(ctx)
{
- fz_hash_insert(ctx, store->hash, &refkey, item);
+ /* May drop and retake the lock */
+ existing = fz_hash_insert(ctx, store->hash, &hash, item);
}
fz_catch(ctx)
{
- fz_free(ctx, item);
- fz_lock(ctx, FZ_LOCK_ALLOC);
store->size -= itemsize;
fz_unlock(ctx, FZ_LOCK_ALLOC);
- return;
+ fz_free(ctx, item);
+ return NULL;
+ }
+ if (existing)
+ {
+ /* Take a new reference */
+ existing->val->refs++;
+ fz_unlock(ctx, FZ_LOCK_ALLOC);
+ fz_free(ctx, item);
+ return existing->val;
}
- fz_lock(ctx, FZ_LOCK_ALLOC);
}
/* Now we can never fail, bump the ref */
if (val->refs > 0)
@@ -283,15 +285,17 @@ fz_store_item(fz_context *ctx, fz_obj *key, void *val_, unsigned int itemsize)
store->head = item;
item->prev = NULL;
fz_unlock(ctx, FZ_LOCK_ALLOC);
+
+ return NULL;
}
void *
-fz_find_item(fz_context *ctx, fz_store_free_fn *free, fz_obj *key)
+fz_find_item(fz_context *ctx, fz_store_free_fn *free, void *key, fz_store_type *type)
{
- struct refkey refkey;
fz_item *item;
fz_store *store = ctx->store;
- int indirect;
+ fz_store_hash hash = { NULL };
+ int use_hash = 0;
if (!store)
return NULL;
@@ -299,27 +303,24 @@ fz_find_item(fz_context *ctx, fz_store_free_fn *free, fz_obj *key)
if (!key)
return NULL;
- /* Form the key before we take the lock */
- indirect = fz_is_indirect(key);
- if (indirect)
+ if (type->make_hash_key)
{
- refkey.free = free;
- refkey.num = fz_to_num(key);
- refkey.gen = fz_to_gen(key);
+ hash.free = free;
+ use_hash = type->make_hash_key(&hash, key);
}
fz_lock(ctx, FZ_LOCK_ALLOC);
- if (indirect)
+ if (use_hash)
{
/* We can find objects keyed on indirected objects quickly */
- item = fz_hash_find(ctx, store->hash, &refkey);
+ item = fz_hash_find(ctx, store->hash, &hash);
}
else
{
/* Others we have to hunt for slowly */
for (item = store->head; item; item = item->next)
{
- if (item->val->free == free && !fz_objcmp(item->key, key))
+ if (item->val->free == free && !type->cmp_key(item->key, key))
break;
}
}
@@ -355,35 +356,33 @@ fz_find_item(fz_context *ctx, fz_store_free_fn *free, fz_obj *key)
}
void
-fz_remove_item(fz_context *ctx, fz_store_free_fn *free, fz_obj *key)
+fz_remove_item(fz_context *ctx, fz_store_free_fn *free, void *key, fz_store_type *type)
{
- struct refkey refkey;
fz_item *item;
fz_store *store = ctx->store;
- int drop, indirect;
+ int drop;
+ fz_store_hash hash;
+ int use_hash = 0;
- /* Form the key before we take the lock */
- indirect = fz_is_indirect(key);
- if (indirect)
+ if (type->make_hash_key)
{
- refkey.free = free;
- refkey.num = fz_to_num(key);
- refkey.gen = fz_to_gen(key);
+ hash.free = free;
+ use_hash = type->make_hash_key(&hash, key);
}
fz_lock(ctx, FZ_LOCK_ALLOC);
- if (indirect)
+ if (use_hash)
{
/* We can find objects keyed on indirect objects quickly */
- item = fz_hash_find(ctx, store->hash, &refkey);
+ item = fz_hash_find(ctx, store->hash, &hash);
if (item)
- fz_hash_remove(ctx, store->hash, &refkey);
+ fz_hash_remove(ctx, store->hash, &hash);
}
else
{
/* Others we have to hunt for slowly */
for (item = store->head; item; item = item->next)
- if (item->val->free == free && !fz_objcmp(item->key, key))
+ if (item->val->free == free && !type->cmp_key(item->key, key))
break;
}
if (item)
@@ -400,7 +399,7 @@ fz_remove_item(fz_context *ctx, fz_store_free_fn *free, fz_obj *key)
fz_unlock(ctx, FZ_LOCK_ALLOC);
if (drop)
item->val->free(ctx, item->val);
- fz_drop_obj(item->key);
+ type->drop_key(ctx, item->key);
fz_free(ctx, item);
}
else
@@ -425,7 +424,7 @@ fz_empty_store(fz_context *ctx)
}
fz_store *
-fz_store_keep(fz_context *ctx)
+fz_keep_store_context(fz_context *ctx)
{
if (ctx == NULL || ctx->store == NULL)
return NULL;
@@ -454,28 +453,26 @@ fz_drop_store_context(fz_context *ctx)
}
void
-fz_debug_store(fz_context *ctx)
+fz_print_store(fz_context *ctx, FILE *out)
{
fz_item *item, *next;
fz_store *store = ctx->store;
- printf("-- resource store contents --\n");
+ fprintf(out, "-- resource store contents --\n");
fz_lock(ctx, FZ_LOCK_ALLOC);
for (item = store->head; item; item = next)
{
next = item->next;
- next->val->refs++;
- printf("store[*][refs=%d][size=%d] ", item->val->refs, item->size);
+ if (next)
+ next->val->refs++;
+ fprintf(out, "store[*][refs=%d][size=%d] ", item->val->refs, item->size);
fz_unlock(ctx, FZ_LOCK_ALLOC);
- if (fz_is_indirect(item->key))
- {
- printf("(%d %d R) ", fz_to_num(item->key), fz_to_gen(item->key));
- } else
- fz_debug_obj(item->key);
- printf(" = %p\n", item->val);
+ item->type->debug(item->key);
+ fprintf(out, " = %p\n", item->val);
fz_lock(ctx, FZ_LOCK_ALLOC);
- next->val->refs--;
+ if (next)
+ next->val->refs--;
}
fz_unlock(ctx, FZ_LOCK_ALLOC);
}
@@ -524,7 +521,7 @@ int fz_store_scavenge(fz_context *ctx, unsigned int size, int *phase)
#ifdef DEBUG_SCAVENGING
printf("Scavenging: store=%d size=%d phase=%d\n", store->size, size, *phase);
- fz_debug_store(ctx);
+ fz_print_store(ctx, stderr);
Memento_stats();
#endif
do
@@ -552,7 +549,7 @@ int fz_store_scavenge(fz_context *ctx, unsigned int size, int *phase)
{
#ifdef DEBUG_SCAVENGING
printf("scavenged: store=%d\n", store->size);
- fz_debug_store(ctx);
+ fz_print_store(ctx, stderr);
Memento_stats();
#endif
return 1;
@@ -562,7 +559,7 @@ int fz_store_scavenge(fz_context *ctx, unsigned int size, int *phase)
#ifdef DEBUG_SCAVENGING
printf("scavenging failed\n");
- fz_debug_store(ctx);
+ fz_print_store(ctx, stderr);
Memento_listBlocks();
#endif
return 0;
diff --git a/fitz/res_text.c b/fitz/res_text.c
index cdfaaa98..643b4c9f 100644
--- a/fitz/res_text.c
+++ b/fitz/res_text.c
@@ -1,4 +1,4 @@
-#include "fitz.h"
+#include "fitz-internal.h"
fz_text *
fz_new_text(fz_context *ctx, fz_font *font, fz_matrix trm, int wmode)
@@ -118,23 +118,30 @@ fz_add_text(fz_context *ctx, fz_text *text, int gid, int ucs, float x, float y)
text->len++;
}
-static int isxmlmeta(int c)
+static int
+isxmlmeta(int c)
{
return c < 32 || c >= 128 || c == '&' || c == '<' || c == '>' || c == '\'' || c == '"';
}
-void fz_debug_text(fz_context *ctx, fz_text *text, int indent)
+static void
+do_print_text(FILE *out, fz_text *text, int indent)
{
int i, n;
for (i = 0; i < text->len; i++)
{
for (n = 0; n < indent; n++)
- putchar(' ');
+ fputc(' ', out);
if (!isxmlmeta(text->items[i].ucs))
- printf("<g ucs=\"%c\" gid=\"%d\" x=\"%g\" y=\"%g\" />\n",
+ fprintf(out, "<g ucs=\"%c\" gid=\"%d\" x=\"%g\" y=\"%g\" />\n",
text->items[i].ucs, text->items[i].gid, text->items[i].x, text->items[i].y);
else
- printf("<g ucs=\"U+%04X\" gid=\"%d\" x=\"%g\" y=\"%g\" />\n",
+ fprintf(out, "<g ucs=\"U+%04X\" gid=\"%d\" x=\"%g\" y=\"%g\" />\n",
text->items[i].ucs, text->items[i].gid, text->items[i].x, text->items[i].y);
}
}
+
+void fz_print_text(fz_context *ctx, FILE *out, fz_text *text)
+{
+ do_print_text(out, text, 0);
+}
diff --git a/fitz/stm_buffer.c b/fitz/stm_buffer.c
index 7f9d521d..4be0165a 100644
--- a/fitz/stm_buffer.c
+++ b/fitz/stm_buffer.c
@@ -1,4 +1,4 @@
-#include "fitz.h"
+#include "fitz-internal.h"
fz_buffer *
fz_new_buffer(fz_context *ctx, int size)
@@ -28,7 +28,12 @@ fz_buffer *
fz_keep_buffer(fz_context *ctx, fz_buffer *buf)
{
if (buf)
+ {
+ if (buf->refs == 1 && buf->cap > buf->len+1)
+ fz_resize_buffer(ctx, buf, buf->len);
buf->refs ++;
+ }
+
return buf;
}
@@ -58,3 +63,18 @@ fz_grow_buffer(fz_context *ctx, fz_buffer *buf)
{
fz_resize_buffer(ctx, buf, (buf->cap * 3) / 2);
}
+
+void
+fz_trim_buffer(fz_context *ctx, fz_buffer *buf)
+{
+ if (buf->cap > buf->len+1)
+ fz_resize_buffer(ctx, buf, buf->len);
+}
+
+int
+fz_buffer_storage(fz_context *ctx, fz_buffer *buf, unsigned char **datap)
+{
+ if (datap)
+ *datap = (buf ? buf->data : NULL);
+ return (buf ? buf->len : 0);
+}
diff --git a/fitz/stm_open.c b/fitz/stm_open.c
index e634f729..1e303825 100644
--- a/fitz/stm_open.c
+++ b/fitz/stm_open.c
@@ -1,4 +1,4 @@
-#include "fitz.h"
+#include "fitz-internal.h"
fz_stream *
fz_new_stream(fz_context *ctx, void *state,
diff --git a/fitz/stm_read.c b/fitz/stm_read.c
index 2066b14c..216d2207 100644
--- a/fitz/stm_read.c
+++ b/fitz/stm_read.c
@@ -1,4 +1,6 @@
-#include "fitz.h"
+#include "fitz-internal.h"
+
+#define MIN_BOMB (100 << 20)
int
fz_read(fz_stream *stm, unsigned char *buf, int len)
@@ -101,16 +103,15 @@ fz_read_all(fz_stream *stm, int initial)
if (initial < 1024)
initial = 1024;
- buf = fz_new_buffer(ctx, initial);
+ buf = fz_new_buffer(ctx, initial+1);
while (1)
{
if (buf->len == buf->cap)
fz_grow_buffer(ctx, buf);
- if (buf->len / 200 > initial)
+ if (buf->len >= MIN_BOMB && buf->len / 200 > initial)
{
- fz_drop_buffer(ctx, buf);
fz_throw(ctx, "compression bomb detected");
}
@@ -126,6 +127,7 @@ fz_read_all(fz_stream *stm, int initial)
fz_drop_buffer(ctx, buf);
fz_rethrow(ctx);
}
+ fz_trim_buffer(ctx, buf);
return buf;
}