From 0a927854a10e1e6b9770a81e2e1d9f3093631757 Mon Sep 17 00:00:00 2001 From: Tor Andersson Date: Wed, 19 Jun 2013 15:29:44 +0200 Subject: Rearrange source files. --- fitz/base_context.c | 210 ------- fitz/base_error.c | 155 ----- fitz/base_geometry.c | 483 ---------------- fitz/base_getopt.c | 66 --- fitz/base_hash.c | 357 ------------ fitz/base_memory.c | 402 ------------- fitz/base_string.c | 264 --------- fitz/base_time.c | 144 ----- fitz/base_trans.c | 165 ------ fitz/base_xml.c | 460 --------------- fitz/crypt_aes.c | 569 ------------------ fitz/crypt_arc4.c | 98 ---- fitz/crypt_md5.c | 272 --------- fitz/crypt_pkcs7.c | 400 ------------- fitz/crypt_sha2.c | 393 ------------- fitz/dev_bbox.c | 231 -------- fitz/dev_list.c | 851 --------------------------- fitz/dev_null.c | 388 ------------- fitz/dev_svg.c | 619 -------------------- fitz/dev_trace.c | 339 ----------- fitz/doc_document.c | 274 --------- fitz/doc_link.c | 65 --- fitz/doc_outline.c | 62 -- fitz/filt_basic.c | 662 --------------------- fitz/filt_dctd.c | 256 --------- fitz/filt_faxd.c | 776 ------------------------- fitz/filt_flate.c | 117 ---- fitz/filt_jbig2d.c | 108 ---- fitz/filt_lzwd.c | 224 -------- fitz/filt_predict.c | 256 --------- fitz/image_jpeg.c | 111 ---- fitz/image_jpx.c | 253 -------- fitz/image_png.c | 599 ------------------- fitz/image_tiff.c | 867 ---------------------------- fitz/memento.c | 1535 ------------------------------------------------- fitz/res_bitmap.c | 123 ---- fitz/res_colorspace.c | 1277 ---------------------------------------- fitz/res_font.c | 1094 ----------------------------------- fitz/res_func.c | 48 -- fitz/res_halftone.c | 202 ------- fitz/res_image.c | 493 ---------------- fitz/res_path.c | 507 ---------------- fitz/res_pcl.c | 856 --------------------------- fitz/res_pixmap.c | 1062 ---------------------------------- fitz/res_pwg.c | 318 ---------- fitz/res_shade.c | 1096 ----------------------------------- fitz/res_store.c | 638 -------------------- fitz/res_text.c | 154 ----- fitz/stm_buffer.c | 390 ------------- fitz/stm_comp_buf.c | 75 --- fitz/stm_open.c | 210 ------- fitz/stm_output.c | 100 ---- fitz/stm_read.c | 219 ------- fitz/text_extract.c | 1027 --------------------------------- fitz/text_output.c | 400 ------------- fitz/text_paragraph.c | 1500 ----------------------------------------------- fitz/text_search.c | 279 --------- 57 files changed, 25099 deletions(-) delete mode 100644 fitz/base_context.c delete mode 100644 fitz/base_error.c delete mode 100644 fitz/base_geometry.c delete mode 100644 fitz/base_getopt.c delete mode 100644 fitz/base_hash.c delete mode 100644 fitz/base_memory.c delete mode 100644 fitz/base_string.c delete mode 100644 fitz/base_time.c delete mode 100644 fitz/base_trans.c delete mode 100644 fitz/base_xml.c delete mode 100644 fitz/crypt_aes.c delete mode 100644 fitz/crypt_arc4.c delete mode 100644 fitz/crypt_md5.c delete mode 100644 fitz/crypt_pkcs7.c delete mode 100644 fitz/crypt_sha2.c delete mode 100644 fitz/dev_bbox.c delete mode 100644 fitz/dev_list.c delete mode 100644 fitz/dev_null.c delete mode 100644 fitz/dev_svg.c delete mode 100644 fitz/dev_trace.c delete mode 100644 fitz/doc_document.c delete mode 100644 fitz/doc_link.c delete mode 100644 fitz/doc_outline.c delete mode 100644 fitz/filt_basic.c delete mode 100644 fitz/filt_dctd.c delete mode 100644 fitz/filt_faxd.c delete mode 100644 fitz/filt_flate.c delete mode 100644 fitz/filt_jbig2d.c delete mode 100644 fitz/filt_lzwd.c delete mode 100644 fitz/filt_predict.c delete mode 100644 fitz/image_jpeg.c delete mode 100644 fitz/image_jpx.c delete mode 100644 fitz/image_png.c delete mode 100644 fitz/image_tiff.c delete mode 100644 fitz/memento.c delete mode 100644 fitz/res_bitmap.c delete mode 100644 fitz/res_colorspace.c delete mode 100644 fitz/res_font.c delete mode 100644 fitz/res_func.c delete mode 100644 fitz/res_halftone.c delete mode 100644 fitz/res_image.c delete mode 100644 fitz/res_path.c delete mode 100644 fitz/res_pcl.c delete mode 100644 fitz/res_pixmap.c delete mode 100644 fitz/res_pwg.c delete mode 100644 fitz/res_shade.c delete mode 100644 fitz/res_store.c delete mode 100644 fitz/res_text.c delete mode 100644 fitz/stm_buffer.c delete mode 100644 fitz/stm_comp_buf.c delete mode 100644 fitz/stm_open.c delete mode 100644 fitz/stm_output.c delete mode 100644 fitz/stm_read.c delete mode 100644 fitz/text_extract.c delete mode 100644 fitz/text_output.c delete mode 100644 fitz/text_paragraph.c delete mode 100644 fitz/text_search.c (limited to 'fitz') diff --git a/fitz/base_context.c b/fitz/base_context.c deleted file mode 100644 index c65377a8..00000000 --- a/fitz/base_context.c +++ /dev/null @@ -1,210 +0,0 @@ -#include "mupdf/fitz.h" - -struct fz_id_context_s -{ - int refs; - int id; -}; - -static void -fz_drop_id_context(fz_context *ctx) -{ - int refs; - fz_id_context *id = ctx->id; - - if (id == NULL) - return; - fz_lock(ctx, FZ_LOCK_ALLOC); - refs = --id->refs; - fz_unlock(ctx, FZ_LOCK_ALLOC); - if (refs == 0) - fz_free(ctx, id); -} - -static void -fz_new_id_context(fz_context *ctx) -{ - ctx->id = fz_malloc_struct(ctx, fz_id_context); - ctx->id->refs = 1; - ctx->id->id = 0; -} - -static fz_id_context * -fz_keep_id_context(fz_context *ctx) -{ - fz_id_context *id = ctx->id; - - if (id == NULL) - return NULL; - fz_lock(ctx, FZ_LOCK_ALLOC); - ++id->refs; - fz_unlock(ctx, FZ_LOCK_ALLOC); - return id; -} - -void -fz_free_context(fz_context *ctx) -{ - if (!ctx) - return; - - /* Other finalisation calls go here (in reverse order) */ - fz_drop_glyph_cache_context(ctx); - fz_drop_store_context(ctx); - fz_free_aa_context(ctx); - fz_drop_colorspace_context(ctx); - fz_drop_font_context(ctx); - fz_drop_id_context(ctx); - - if (ctx->warn) - { - fz_flush_warnings(ctx); - fz_free(ctx, ctx->warn); - } - - if (ctx->error) - { - assert(ctx->error->top == -1); - fz_free(ctx, ctx->error); - } - - /* Free the context itself */ - ctx->alloc->free(ctx->alloc->user, ctx); -} - -/* Allocate new context structure, and initialise allocator, and sections - * that aren't shared between contexts. - */ -static fz_context * -new_context_phase1(fz_alloc_context *alloc, fz_locks_context *locks) -{ - fz_context *ctx; - - ctx = alloc->malloc(alloc->user, sizeof(fz_context)); - if (!ctx) - return NULL; - memset(ctx, 0, sizeof *ctx); - ctx->alloc = alloc; - ctx->locks = locks; - - ctx->glyph_cache = NULL; - - ctx->error = fz_malloc_no_throw(ctx, sizeof(fz_error_context)); - if (!ctx->error) - goto cleanup; - ctx->error->top = -1; - ctx->error->errcode = FZ_ERROR_NONE; - ctx->error->message[0] = 0; - - ctx->warn = fz_malloc_no_throw(ctx, sizeof(fz_warn_context)); - if (!ctx->warn) - goto cleanup; - ctx->warn->message[0] = 0; - ctx->warn->count = 0; - - /* New initialisation calls for context entries go here */ - fz_try(ctx) - { - fz_new_aa_context(ctx); - } - fz_catch(ctx) - { - goto cleanup; - } - - return ctx; - -cleanup: - fprintf(stderr, "cannot create context (phase 1)\n"); - fz_free_context(ctx); - return NULL; -} - -fz_context * -fz_new_context(fz_alloc_context *alloc, fz_locks_context *locks, unsigned int max_store) -{ - fz_context *ctx; - - if (!alloc) - alloc = &fz_alloc_default; - - if (!locks) - locks = &fz_locks_default; - - ctx = new_context_phase1(alloc, locks); - if (!ctx) - return NULL; - - /* Now initialise sections that are shared */ - fz_try(ctx) - { - fz_new_store_context(ctx, max_store); - fz_new_glyph_cache_context(ctx); - fz_new_colorspace_context(ctx); - fz_new_font_context(ctx); - fz_new_id_context(ctx); - } - fz_catch(ctx) - { - fprintf(stderr, "cannot create context (phase 2)\n"); - fz_free_context(ctx); - return NULL; - } - return ctx; -} - -fz_context * -fz_clone_context(fz_context *ctx) -{ - /* We cannot safely clone the context without having locking/ - * unlocking functions. */ - if (ctx == NULL || ctx->locks == &fz_locks_default) - return NULL; - return fz_clone_context_internal(ctx); -} - -fz_context * -fz_clone_context_internal(fz_context *ctx) -{ - fz_context *new_ctx; - - if (ctx == NULL || ctx->alloc == NULL) - return NULL; - - new_ctx = new_context_phase1(ctx->alloc, ctx->locks); - if (!new_ctx) - return NULL; - - /* Inherit AA defaults from old context. */ - fz_copy_aa_context(new_ctx, ctx); - - /* Keep thread lock checking happy by copying pointers first and locking under new context */ - new_ctx->store = ctx->store; - new_ctx->store = fz_keep_store_context(new_ctx); - new_ctx->glyph_cache = ctx->glyph_cache; - new_ctx->glyph_cache = fz_keep_glyph_cache(new_ctx); - new_ctx->colorspace = ctx->colorspace; - new_ctx->colorspace = fz_keep_colorspace_context(new_ctx); - new_ctx->font = ctx->font; - new_ctx->font = fz_keep_font_context(new_ctx); - new_ctx->id = ctx->id; - new_ctx->id = fz_keep_id_context(new_ctx); - - return new_ctx; -} - -int -fz_gen_id(fz_context *ctx) -{ - int id; - fz_lock(ctx, FZ_LOCK_ALLOC); - /* We'll never wrap around in normal use, but if we *do*, then avoid - * 0. */ - do - { - id = ++ctx->id->id; - } - while (id == 0); - fz_unlock(ctx, FZ_LOCK_ALLOC); - return id; -} diff --git a/fitz/base_error.c b/fitz/base_error.c deleted file mode 100644 index 50b3c5aa..00000000 --- a/fitz/base_error.c +++ /dev/null @@ -1,155 +0,0 @@ -#include "mupdf/fitz.h" - -/* Warning context */ - -void fz_var_imp(void *var) -{ - UNUSED(var); /* Do nothing */ -} - -void fz_flush_warnings(fz_context *ctx) -{ - if (ctx->warn->count > 1) - { - fprintf(stderr, "warning: ... repeated %d times ...\n", ctx->warn->count); - LOGE("warning: ... repeated %d times ...\n", ctx->warn->count); - } - ctx->warn->message[0] = 0; - ctx->warn->count = 0; -} - -void fz_warn(fz_context *ctx, const char *fmt, ...) -{ - va_list ap; - char buf[sizeof ctx->warn->message]; - - va_start(ap, fmt); - vsnprintf(buf, sizeof buf, fmt, ap); - va_end(ap); - - if (!strcmp(buf, ctx->warn->message)) - { - ctx->warn->count++; - } - else - { - fz_flush_warnings(ctx); - fprintf(stderr, "warning: %s\n", buf); - LOGE("warning: %s\n", buf); - fz_strlcpy(ctx->warn->message, buf, sizeof ctx->warn->message); - ctx->warn->count = 1; - } -} - -/* Error context */ - -/* When we first setjmp, code is set to 0. Whenever we throw, we add 2 to - * this code. Whenever we enter the always block, we add 1. - * - * fz_push_try sets code to 0. - * If (fz_throw called within fz_try) - * fz_throw makes code = 2. - * If (no always block present) - * enter catch region with code = 2. OK. - * else - * fz_always entered as code < 3; Makes code = 3; - * if (fz_throw called within fz_always) - * fz_throw makes code = 5 - * fz_always is not reentered. - * catch region entered with code = 5. OK. - * else - * catch region entered with code = 3. OK - * else - * if (no always block present) - * catch region not entered as code = 0. OK. - * else - * fz_always entered as code < 3. makes code = 1 - * if (fz_throw called within fz_always) - * fz_throw makes code = 3; - * fz_always NOT entered as code >= 3 - * catch region entered with code = 3. OK. - * else - * catch region entered with code = 1. - */ - -static void throw(fz_error_context *ex) FZ_NORETURN; - -static void throw(fz_error_context *ex) -{ - if (ex->top >= 0) { - fz_longjmp(ex->stack[ex->top].buffer, ex->stack[ex->top].code + 2); - } else { - fprintf(stderr, "uncaught exception: %s\n", ex->message); - LOGE("uncaught exception: %s\n", ex->message); - exit(EXIT_FAILURE); - } -} - -int fz_push_try(fz_error_context *ex) -{ - assert(ex); - ex->top++; - /* Normal case, get out of here quick */ - if (ex->top < nelem(ex->stack)-1) - return 1; /* We exit here, and the setjmp sets the code to 0 */ - /* We reserve the top slot on the exception stack purely to cope with - * the case when we overflow. If we DO hit this, then we 'throw' - * immediately - returning 0 stops the setjmp happening and takes us - * direct to the always/catch clauses. */ - assert(ex->top == nelem(ex->stack)-1); - strcpy(ex->message, "exception stack overflow!"); - ex->stack[ex->top].code = 2; - fprintf(stderr, "error: %s\n", ex->message); - LOGE("error: %s\n", ex->message); - return 0; -} - -int fz_caught(fz_context *ctx) -{ - assert(ctx && ctx->error && ctx->error->errcode >= FZ_ERROR_NONE); - return ctx->error->errcode; -} - -const char *fz_caught_message(fz_context *ctx) -{ - assert(ctx && ctx->error && ctx->error->errcode >= FZ_ERROR_NONE); - return ctx->error->message; -} - -void fz_throw(fz_context *ctx, int code, const char *fmt, ...) -{ - va_list args; - ctx->error->errcode = code; - va_start(args, fmt); - vsnprintf(ctx->error->message, sizeof ctx->error->message, fmt, args); - va_end(args); - - fz_flush_warnings(ctx); - fprintf(stderr, "error: %s\n", ctx->error->message); - LOGE("error: %s\n", ctx->error->message); - - throw(ctx->error); -} - -void fz_rethrow(fz_context *ctx) -{ - assert(ctx && ctx->error && ctx->error->errcode >= FZ_ERROR_NONE); - throw(ctx->error); -} - -void fz_rethrow_message(fz_context *ctx, const char *fmt, ...) -{ - va_list args; - - assert(ctx && ctx->error && ctx->error->errcode >= FZ_ERROR_NONE); - - va_start(args, fmt); - vsnprintf(ctx->error->message, sizeof ctx->error->message, fmt, args); - va_end(args); - - fz_flush_warnings(ctx); - fprintf(stderr, "error: %s\n", ctx->error->message); - LOGE("error: %s\n", ctx->error->message); - - throw(ctx->error); -} diff --git a/fitz/base_geometry.c b/fitz/base_geometry.c deleted file mode 100644 index 81450246..00000000 --- a/fitz/base_geometry.c +++ /dev/null @@ -1,483 +0,0 @@ -#include "mupdf/fitz.h" - -#define MAX4(a,b,c,d) fz_max(fz_max(a,b), fz_max(c,d)) -#define MIN4(a,b,c,d) fz_min(fz_min(a,b), fz_min(c,d)) - -/* A useful macro to add with overflow detection and clamping. - - We want to do "b = a + x", but to allow for overflow. Consider the - top bits, and the cases in which overflow occurs: - - overflow a x b ~a^x a^b (~a^x)&(a^b) - no 0 0 0 1 0 0 - yes 0 0 1 1 1 1 - no 0 1 0 0 0 0 - no 0 1 1 0 1 0 - no 1 0 0 0 1 0 - no 1 0 1 0 0 0 - yes 1 1 0 1 1 1 - no 1 1 1 1 0 0 -*/ -#define ADD_WITH_SAT(b,a,x) \ - ((b) = (a) + (x), (b) = (((~(a)^(x))&((a)^(b))) < 0 ? ((x) < 0 ? INT_MIN : INT_MAX) : (b))) - -/* Matrices, points and affine transformations */ - -const fz_matrix fz_identity = { 1, 0, 0, 1, 0, 0 }; - -fz_matrix * -fz_concat(fz_matrix *dst, const fz_matrix *one, const fz_matrix *two) -{ - fz_matrix dst2; - dst2.a = one->a * two->a + one->b * two->c; - dst2.b = one->a * two->b + one->b * two->d; - dst2.c = one->c * two->a + one->d * two->c; - dst2.d = one->c * two->b + one->d * two->d; - dst2.e = one->e * two->a + one->f * two->c + two->e; - dst2.f = one->e * two->b + one->f * two->d + two->f; - *dst = dst2; - return dst; -} - -fz_matrix * -fz_scale(fz_matrix *m, float sx, float sy) -{ - m->a = sx; m->b = 0; - m->c = 0; m->d = sy; - m->e = 0; m->f = 0; - return m; -} - -fz_matrix * -fz_pre_scale(fz_matrix *mat, float sx, float sy) -{ - mat->a *= sx; - mat->b *= sx; - mat->c *= sy; - mat->d *= sy; - return mat; -} - -fz_matrix * -fz_shear(fz_matrix *mat, float h, float v) -{ - mat->a = 1; mat->b = v; - mat->c = h; mat->d = 1; - mat->e = 0; mat->f = 0; - return mat; -} - -fz_matrix * -fz_pre_shear(fz_matrix *mat, float h, float v) -{ - float a = mat->a; - float b = mat->b; - mat->a += v * mat->c; - mat->b += v * mat->d; - mat->c += h * a; - mat->d += h * b; - return mat; -} - -fz_matrix * -fz_rotate(fz_matrix *m, float theta) -{ - float s; - float c; - - while (theta < 0) - theta += 360; - while (theta >= 360) - theta -= 360; - - if (fabsf(0 - theta) < FLT_EPSILON) - { - s = 0; - c = 1; - } - else if (fabsf(90.0f - theta) < FLT_EPSILON) - { - s = 1; - c = 0; - } - else if (fabsf(180.0f - theta) < FLT_EPSILON) - { - s = 0; - c = -1; - } - else if (fabsf(270.0f - theta) < FLT_EPSILON) - { - s = -1; - c = 0; - } - else - { - s = sinf(theta * (float)M_PI / 180); - c = cosf(theta * (float)M_PI / 180); - } - - m->a = c; m->b = s; - m->c = -s; m->d = c; - m->e = 0; m->f = 0; - return m; -} - -fz_matrix * -fz_pre_rotate(fz_matrix *m, float theta) -{ - while (theta < 0) - theta += 360; - while (theta >= 360) - theta -= 360; - - if (fabsf(0 - theta) < FLT_EPSILON) - { - /* Nothing to do */ - } - else if (fabsf(90.0f - theta) < FLT_EPSILON) - { - float a = m->a; - float b = m->b; - m->a = m->c; - m->b = m->d; - m->c = -a; - m->d = -b; - } - else if (fabsf(180.0f - theta) < FLT_EPSILON) - { - m->a = -m->a; - m->b = -m->b; - m->c = -m->c; - m->d = -m->d; - } - else if (fabsf(270.0f - theta) < FLT_EPSILON) - { - float a = m->a; - float b = m->b; - m->a = -m->c; - m->b = -m->d; - m->c = a; - m->d = b; - } - else - { - float s = sinf(theta * (float)M_PI / 180); - float c = cosf(theta * (float)M_PI / 180); - float a = m->a; - float b = m->b; - m->a = c * a + s * m->c; - m->b = c * b + s * m->d; - m->c =-s * a + c * m->c; - m->d =-s * b + c * m->d; - } - - return m; -} - -fz_matrix * -fz_translate(fz_matrix *m, float tx, float ty) -{ - m->a = 1; m->b = 0; - m->c = 0; m->d = 1; - m->e = tx; m->f = ty; - return m; -} - -fz_matrix * -fz_pre_translate(fz_matrix *mat, float tx, float ty) -{ - mat->e += tx * mat->a + ty * mat->c; - mat->f += tx * mat->b + ty * mat->d; - return mat; -} - -fz_matrix * -fz_invert_matrix(fz_matrix *dst, const fz_matrix *src) -{ - /* Be careful to cope with dst == src */ - float a = src->a; - float det = a * src->d - src->b * src->c; - if (det < -FLT_EPSILON || det > FLT_EPSILON) - { - float rdet = 1 / det; - dst->a = src->d * rdet; - dst->b = -src->b * rdet; - dst->c = -src->c * rdet; - dst->d = a * rdet; - a = -src->e * dst->a - src->f * dst->c; - dst->f = -src->e * dst->b - src->f * dst->d; - dst->e = a; - } - else - *dst = *src; - return dst; -} - -int -fz_is_rectilinear(const fz_matrix *m) -{ - return (fabsf(m->b) < FLT_EPSILON && fabsf(m->c) < FLT_EPSILON) || - (fabsf(m->a) < FLT_EPSILON && fabsf(m->d) < FLT_EPSILON); -} - -float -fz_matrix_expansion(const fz_matrix *m) -{ - return sqrtf(fabsf(m->a * m->d - m->b * m->c)); -} - -float -fz_matrix_max_expansion(const fz_matrix *m) -{ - float max = fabsf(m->a); - float x = fabsf(m->b); - if (max < x) - max = x; - x = fabsf(m->c); - if (max < x) - max = x; - x = fabsf(m->d); - if (max < x) - max = x; - return max; -} - -fz_point * -fz_transform_point(fz_point *restrict p, const fz_matrix *restrict m) -{ - float x = p->x; - p->x = x * m->a + p->y * m->c + m->e; - p->y = x * m->b + p->y * m->d + m->f; - return p; -} - -fz_point * -fz_transform_vector(fz_point *restrict p, const fz_matrix *restrict m) -{ - float x = p->x; - p->x = x * m->a + p->y * m->c; - p->y = x * m->b + p->y * m->d; - return p; -} - -void -fz_normalize_vector(fz_point *p) -{ - float len = p->x * p->x + p->y * p->y; - if (len != 0) - { - len = sqrtf(len); - p->x /= len; - p->y /= len; - } -} - -/* Rectangles and bounding boxes */ - -/* biggest and smallest integers that a float can represent perfectly (i.e. 24 bits) */ -#define MAX_SAFE_INT 16777216 -#define MIN_SAFE_INT -16777216 - -const fz_rect fz_infinite_rect = { 1, 1, -1, -1 }; -const fz_rect fz_empty_rect = { 0, 0, 0, 0 }; -const fz_rect fz_unit_rect = { 0, 0, 1, 1 }; - -const fz_irect fz_infinite_irect = { 1, 1, -1, -1 }; -const fz_irect fz_empty_irect = { 0, 0, 0, 0 }; -const fz_irect fz_unit_bbox = { 0, 0, 1, 1 }; - -fz_irect * -fz_irect_from_rect(fz_irect *restrict b, const fz_rect *restrict r) -{ - b->x0 = fz_clamp(floorf(r->x0), MIN_SAFE_INT, MAX_SAFE_INT); - b->y0 = fz_clamp(floorf(r->y0), MIN_SAFE_INT, MAX_SAFE_INT); - b->x1 = fz_clamp(ceilf(r->x1), MIN_SAFE_INT, MAX_SAFE_INT); - b->y1 = fz_clamp(ceilf(r->y1), MIN_SAFE_INT, MAX_SAFE_INT); - return b; -} - -fz_rect * -fz_rect_from_irect(fz_rect *restrict r, const fz_irect *restrict a) -{ - r->x0 = a->x0; - r->y0 = a->y0; - r->x1 = a->x1; - r->y1 = a->y1; - return r; -} - -fz_irect * -fz_round_rect(fz_irect * restrict b, const fz_rect *restrict r) -{ - int i; - - i = floorf(r->x0 + 0.001); - b->x0 = fz_clamp(i, MIN_SAFE_INT, MAX_SAFE_INT); - i = floorf(r->y0 + 0.001); - b->y0 = fz_clamp(i, MIN_SAFE_INT, MAX_SAFE_INT); - i = ceilf(r->x1 - 0.001); - b->x1 = fz_clamp(i, MIN_SAFE_INT, MAX_SAFE_INT); - i = ceilf(r->y1 - 0.001); - b->y1 = fz_clamp(i, MIN_SAFE_INT, MAX_SAFE_INT); - - return b; -} - -fz_rect * -fz_intersect_rect(fz_rect *restrict a, const fz_rect *restrict b) -{ - /* Check for empty box before infinite box */ - if (fz_is_empty_rect(a)) return a; - if (fz_is_empty_rect(b)) { - *a = fz_empty_rect; - return a; - } - if (fz_is_infinite_rect(b)) return a; - if (fz_is_infinite_rect(a)) { - *a = *b; - return a; - } - if (a->x0 < b->x0) - a->x0 = b->x0; - if (a->y0 < b->y0) - a->y0 = b->y0; - if (a->x1 > b->x1) - a->x1 = b->x1; - if (a->y1 > b->y1) - a->y1 = b->y1; - if (a->x1 < a->x0 || a->y1 < a->y0) - *a = fz_empty_rect; - return a; -} - -fz_irect * -fz_intersect_irect(fz_irect *restrict a, const fz_irect *restrict b) -{ - /* Check for empty box before infinite box */ - if (fz_is_empty_irect(a)) return a; - if (fz_is_empty_irect(b)) - { - *a = fz_empty_irect; - return a; - } - if (fz_is_infinite_irect(b)) return a; - if (fz_is_infinite_irect(a)) - { - *a = *b; - return a; - } - if (a->x0 < b->x0) - a->x0 = b->x0; - if (a->y0 < b->y0) - a->y0 = b->y0; - if (a->x1 > b->x1) - a->x1 = b->x1; - if (a->y1 > b->y1) - a->y1 = b->y1; - if (a->x1 < a->x0 || a->y1 < a->y0) - *a = fz_empty_irect; - return a; -} - -fz_rect * -fz_union_rect(fz_rect *restrict a, const fz_rect *restrict b) -{ - /* Check for empty box before infinite box */ - if (fz_is_empty_rect(b)) return a; - if (fz_is_empty_rect(a)) { - *a = *b; - return a; - } - if (fz_is_infinite_rect(a)) return a; - if (fz_is_infinite_rect(b)) { - *a = *b; - return a; - } - if (a->x0 > b->x0) - a->x0 = b->x0; - if (a->y0 > b->y0) - a->y0 = b->y0; - if (a->x1 < b->x1) - a->x1 = b->x1; - if (a->y1 < b->y1) - a->y1 = b->y1; - return a; -} - -fz_irect * -fz_translate_irect(fz_irect *a, int xoff, int yoff) -{ - int t; - - if (fz_is_empty_irect(a)) return a; - if (fz_is_infinite_irect(a)) return a; - a->x0 = ADD_WITH_SAT(t, a->x0, xoff); - a->y0 = ADD_WITH_SAT(t, a->y0, yoff); - a->x1 = ADD_WITH_SAT(t, a->x1, xoff); - a->y1 = ADD_WITH_SAT(t, a->y1, yoff); - return a; -} - -fz_rect * -fz_transform_rect(fz_rect *restrict r, const fz_matrix *restrict m) -{ - fz_point s, t, u, v; - - if (fz_is_infinite_rect(r)) - return r; - - if (fabsf(m->b) < FLT_EPSILON && fabsf(m->c) < FLT_EPSILON) - { - if (m->a < 0) - { - float f = r->x0; - r->x0 = r->x1; - r->x1 = f; - } - if (m->d < 0) - { - float f = r->y0; - r->y0 = r->y1; - r->y1 = f; - } - fz_transform_point(fz_rect_min(r), m); - fz_transform_point(fz_rect_max(r), m); - return r; - } - - s.x = r->x0; s.y = r->y0; - t.x = r->x0; t.y = r->y1; - u.x = r->x1; u.y = r->y1; - v.x = r->x1; v.y = r->y0; - fz_transform_point(&s, m); - fz_transform_point(&t, m); - fz_transform_point(&u, m); - fz_transform_point(&v, m); - r->x0 = MIN4(s.x, t.x, u.x, v.x); - r->y0 = MIN4(s.y, t.y, u.y, v.y); - r->x1 = MAX4(s.x, t.x, u.x, v.x); - r->y1 = MAX4(s.y, t.y, u.y, v.y); - return r; -} - -fz_rect * -fz_expand_rect(fz_rect *a, float expand) -{ - if (fz_is_empty_rect(a)) return a; - if (fz_is_infinite_rect(a)) return a; - a->x0 -= expand; - a->y0 -= expand; - a->x1 += expand; - a->y1 += expand; - return a; -} - -fz_rect *fz_include_point_in_rect(fz_rect *r, const fz_point *p) -{ - if (p->x < r->x0) r->x0 = p->x; - if (p->x > r->x1) r->x1 = p->x; - if (p->y < r->y0) r->y0 = p->y; - if (p->y > r->y1) r->y1 = p->y; - - return r; -} diff --git a/fitz/base_getopt.c b/fitz/base_getopt.c deleted file mode 100644 index 2a6e5ac4..00000000 --- a/fitz/base_getopt.c +++ /dev/null @@ -1,66 +0,0 @@ -/* - * This is a version of the public domain getopt implementation by - * Henry Spencer originally posted to net.sources. - * - * This file is in the public domain. - */ - -#include -#include - -#define getopt fz_getopt -#define optarg fz_optarg -#define optind fz_optind - -char *optarg; /* Global argument pointer. */ -int optind = 0; /* Global argv index. */ - -static char *scan = NULL; /* Private scan pointer. */ - -int -getopt(int argc, char *argv[], char *optstring) -{ - char c; - char *place; - - optarg = NULL; - - if (!scan || *scan == '\0') { - if (optind == 0) - optind++; - - if (optind >= argc || argv[optind][0] != '-' || argv[optind][1] == '\0') - return EOF; - if (argv[optind][1] == '-' && argv[optind][2] == '\0') { - optind++; - return EOF; - } - - scan = argv[optind]+1; - optind++; - } - - c = *scan++; - place = strchr(optstring, c); - - if (!place || c == ':') { - fprintf(stderr, "%s: unknown option -%c\n", argv[0], c); - return '?'; - } - - place++; - if (*place == ':') { - if (*scan != '\0') { - optarg = scan; - scan = NULL; - } else if( optind < argc ) { - optarg = argv[optind]; - optind++; - } else { - fprintf(stderr, "%s: option requires argument -%c\n", argv[0], c); - return ':'; - } - } - - return c; -} diff --git a/fitz/base_hash.c b/fitz/base_hash.c deleted file mode 100644 index 624cc305..00000000 --- a/fitz/base_hash.c +++ /dev/null @@ -1,357 +0,0 @@ -#include "mupdf/fitz.h" - -/* -Simple hashtable with open addressing linear probe. -Unlike text book examples, removing entries works -correctly in this implementation, so it wont start -exhibiting bad behaviour if entries are inserted -and removed frequently. -*/ - -enum { MAX_KEY_LEN = 48 }; -typedef struct fz_hash_entry_s fz_hash_entry; - -struct fz_hash_entry_s -{ - unsigned char key[MAX_KEY_LEN]; - void *val; -}; - -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; -}; - -static unsigned hash(unsigned char *s, int len) -{ - unsigned val = 0; - int i; - for (i = 0; i < len; i++) - { - val += s[i]; - val += (val << 10); - val ^= (val >> 6); - } - val += (val << 3); - val ^= (val >> 11); - val += (val << 15); - return val; -} - -fz_hash_table * -fz_new_hash_table(fz_context *ctx, int initialsize, int keylen, int lock) -{ - fz_hash_table *table; - - assert(keylen <= MAX_KEY_LEN); - - table = fz_malloc_struct(ctx, fz_hash_table); - 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)); - memset(table->ents, 0, sizeof(fz_hash_entry) * table->size); - } - fz_catch(ctx) - { - fz_free(ctx, table); - fz_rethrow(ctx); - } - - return table; -} - -void -fz_empty_hash(fz_context *ctx, fz_hash_table *table) -{ - table->load = 0; - memset(table->ents, 0, sizeof(fz_hash_entry) * table->size); -} - -int -fz_hash_len(fz_context *ctx, fz_hash_table *table) -{ - return table->size; -} - -void * -fz_hash_get_key(fz_context *ctx, fz_hash_table *table, int idx) -{ - return table->ents[idx].key; -} - -void * -fz_hash_get_val(fz_context *ctx, fz_hash_table *table, int idx) -{ - return table->ents[idx].val; -} - -void -fz_free_hash(fz_context *ctx, fz_hash_table *table) -{ - fz_free(ctx, table->ents); - fz_free(ctx, table); -} - -static void * -do_hash_insert(fz_context *ctx, fz_hash_table *table, void *key, void *val, unsigned *pos_ptr) -{ - 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 ++; - if (pos_ptr) - *pos_ptr = pos; - return NULL; - } - - if (memcmp(key, ents[pos].key, table->keylen) == 0) - { - /* This is legal, but should happen rarely in the non - * pos_ptr case. */ - if (pos_ptr) - *pos_ptr = pos; - else - fz_warn(ctx, "assert: overwrite hash slot"); - return ents[pos].val; - } - - pos = (pos + 1) % size; - } -} - -/* Entered with the lock taken, held throughout and at exit, UNLESS the lock - * is the alloc lock in which case it may be momentarily dropped. */ -static void -fz_resize_hash(fz_context *ctx, fz_hash_table *table, int newsize) -{ - fz_hash_entry *oldents = table->ents; - fz_hash_entry *newents; - int oldsize = table->size; - int oldload = table->load; - int i; - - if (newsize < oldload * 8 / 10) - { - fz_warn(ctx, "assert: resize hash too small"); - return; - } - - if (table->lock == FZ_LOCK_ALLOC) - fz_unlock(ctx, FZ_LOCK_ALLOC); - newents = fz_malloc_array_no_throw(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! */ - if (table->lock == FZ_LOCK_ALLOC) - fz_unlock(ctx, table->lock); - fz_free(ctx, newents); - if (table->lock == FZ_LOCK_ALLOC) - fz_lock(ctx, table->lock); - return; - } - } - if (newents == NULL) - fz_throw(ctx, FZ_ERROR_GENERIC, "hash table resize failed; out of memory (%d entries)", newsize); - table->ents = newents; - memset(table->ents, 0, sizeof(fz_hash_entry) * newsize); - table->size = newsize; - table->load = 0; - - for (i = 0; i < oldsize; i++) - { - if (oldents[i].val) - { - do_hash_insert(ctx, table, oldents[i].key, oldents[i].val, NULL); - } - } - - 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 * -fz_hash_find(fz_context *ctx, fz_hash_table *table, void *key) -{ - fz_hash_entry *ents = table->ents; - 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) - return NULL; - - if (memcmp(key, ents[pos].key, table->keylen) == 0) - return ents[pos].val; - - pos = (pos + 1) % size; - } -} - -void * -fz_hash_insert(fz_context *ctx, fz_hash_table *table, void *key, void *val) -{ - if (table->load > table->size * 8 / 10) - { - fz_resize_hash(ctx, table, table->size * 2); - } - - return do_hash_insert(ctx, table, key, val, NULL); -} - -void * -fz_hash_insert_with_pos(fz_context *ctx, fz_hash_table *table, void *key, void *val, unsigned *pos) -{ - if (table->load > table->size * 8 / 10) - { - fz_resize_hash(ctx, table, table->size * 2); - } - - return do_hash_insert(ctx, table, key, val, pos); -} - -static void -do_removal(fz_context *ctx, fz_hash_table *table, void *key, unsigned hole) -{ - fz_hash_entry *ents = table->ents; - unsigned size = table->size; - unsigned look, code; - - if (table->lock >= 0) - fz_assert_lock_held(ctx, table->lock); - - ents[hole].val = NULL; - - look = hole + 1; - if (look == size) - look = 0; - - while (ents[look].val) - { - code = hash(ents[look].key, table->keylen) % size; - if ((code <= hole && hole < look) || - (look < code && code <= hole) || - (hole < look && look < code)) - { - ents[hole] = ents[look]; - ents[look].val = NULL; - hole = look; - } - - look++; - if (look == size) - look = 0; - } - - table->load --; -} - -void -fz_hash_remove(fz_context *ctx, fz_hash_table *table, void *key) -{ - fz_hash_entry *ents = table->ents; - 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) - { - fz_warn(ctx, "assert: remove non-existent hash entry"); - return; - } - - if (memcmp(key, ents[pos].key, table->keylen) == 0) - { - do_removal(ctx, table, key, pos); - return; - } - - pos++; - if (pos == size) - pos = 0; - } -} - -void -fz_hash_remove_fast(fz_context *ctx, fz_hash_table *table, void *key, unsigned pos) -{ - fz_hash_entry *ents = table->ents; - - if (ents[pos].val == NULL || memcmp(key, ents[pos].key, table->keylen) != 0) - { - /* The value isn't there, or the key didn't match! The table - * must have been rebuilt (or the contents moved) in the - * meantime. Do the removal the slow way. */ - fz_hash_remove(ctx, table, key); - } - else - do_removal(ctx, table, key, pos); -} - -#ifndef NDEBUG -void -fz_print_hash(fz_context *ctx, FILE *out, fz_hash_table *table) -{ - fz_print_hash_details(ctx, out, table, NULL); -} - -void -fz_print_hash_details(fz_context *ctx, FILE *out, fz_hash_table *table, void (*details)(FILE *,void*)) -{ - int i, k; - - fprintf(out, "cache load %d / %d\n", table->load, table->size); - - for (i = 0; i < table->size; i++) - { - if (!table->ents[i].val) - fprintf(out, "table % 4d: empty\n", i); - else - { - fprintf(out, "table % 4d: key=", i); - for (k = 0; k < MAX_KEY_LEN; k++) - fprintf(out, "%02x", ((char*)table->ents[i].key)[k]); - if (details) - details(out, table->ents[i].val); - else - fprintf(out, " val=$%p\n", table->ents[i].val); - } - } -} -#endif diff --git a/fitz/base_memory.c b/fitz/base_memory.c deleted file mode 100644 index f9e7b4f6..00000000 --- a/fitz/base_memory.c +++ /dev/null @@ -1,402 +0,0 @@ -#include "mupdf/fitz.h" - -/* Enable FITZ_DEBUG_LOCKING_TIMES below if you want to check the times - * for which locks are held too. */ -#ifdef FITZ_DEBUG_LOCKING -#undef FITZ_DEBUG_LOCKING_TIMES -#endif - -static void * -do_scavenging_malloc(fz_context *ctx, unsigned int size) -{ - void *p; - int phase = 0; - - fz_lock(ctx, FZ_LOCK_ALLOC); - do { - p = ctx->alloc->malloc(ctx->alloc->user, size); - if (p != NULL) - { - fz_unlock(ctx, FZ_LOCK_ALLOC); - return p; - } - } while (fz_store_scavenge(ctx, size, &phase)); - fz_unlock(ctx, FZ_LOCK_ALLOC); - - return NULL; -} - -static void * -do_scavenging_realloc(fz_context *ctx, void *p, unsigned int size) -{ - void *q; - int phase = 0; - - fz_lock(ctx, FZ_LOCK_ALLOC); - do { - q = ctx->alloc->realloc(ctx->alloc->user, p, size); - if (q != NULL) - { - fz_unlock(ctx, FZ_LOCK_ALLOC); - return q; - } - } while (fz_store_scavenge(ctx, size, &phase)); - fz_unlock(ctx, FZ_LOCK_ALLOC); - - return NULL; -} - -void * -fz_malloc(fz_context *ctx, unsigned int size) -{ - void *p; - - if (size == 0) - return NULL; - - p = do_scavenging_malloc(ctx, size); - if (!p) - fz_throw(ctx, FZ_ERROR_GENERIC, "malloc of %d bytes failed", size); - return p; -} - -void * -fz_malloc_no_throw(fz_context *ctx, unsigned int size) -{ - return do_scavenging_malloc(ctx, size); -} - -void * -fz_malloc_array(fz_context *ctx, unsigned int count, unsigned int size) -{ - void *p; - - if (count == 0 || size == 0) - return 0; - - if (count > UINT_MAX / size) - fz_throw(ctx, FZ_ERROR_GENERIC, "malloc of array (%d x %d bytes) failed (integer overflow)", count, size); - - p = do_scavenging_malloc(ctx, count * size); - if (!p) - fz_throw(ctx, FZ_ERROR_GENERIC, "malloc of array (%d x %d bytes) failed", count, size); - return p; -} - -void * -fz_malloc_array_no_throw(fz_context *ctx, unsigned int count, unsigned int size) -{ - if (count == 0 || size == 0) - return 0; - - if (count > UINT_MAX / size) - { - fprintf(stderr, "error: malloc of array (%d x %d bytes) failed (integer overflow)", count, size); - return NULL; - } - - return do_scavenging_malloc(ctx, count * size); -} - -void * -fz_calloc(fz_context *ctx, unsigned int count, unsigned int size) -{ - void *p; - - if (count == 0 || size == 0) - return 0; - - if (count > UINT_MAX / size) - { - fz_throw(ctx, FZ_ERROR_GENERIC, "calloc (%d x %d bytes) failed (integer overflow)", count, size); - } - - p = do_scavenging_malloc(ctx, count * size); - if (!p) - { - fz_throw(ctx, FZ_ERROR_GENERIC, "calloc (%d x %d bytes) failed", count, size); - } - memset(p, 0, count*size); - return p; -} - -void * -fz_calloc_no_throw(fz_context *ctx, unsigned int count, unsigned int size) -{ - void *p; - - if (count == 0 || size == 0) - return 0; - - if (count > UINT_MAX / size) - { - fprintf(stderr, "error: calloc (%d x %d bytes) failed (integer overflow)\n", count, size); - return NULL; - } - - p = do_scavenging_malloc(ctx, count * size); - if (p) - { - memset(p, 0, count*size); - } - return p; -} - -void * -fz_resize_array(fz_context *ctx, void *p, unsigned int count, unsigned int size) -{ - void *np; - - if (count == 0 || size == 0) - { - fz_free(ctx, p); - return 0; - } - - if (count > UINT_MAX / size) - fz_throw(ctx, FZ_ERROR_GENERIC, "resize array (%d x %d bytes) failed (integer overflow)", count, size); - - np = do_scavenging_realloc(ctx, p, count * size); - if (!np) - fz_throw(ctx, FZ_ERROR_GENERIC, "resize array (%d x %d bytes) failed", count, size); - return np; -} - -void * -fz_resize_array_no_throw(fz_context *ctx, void *p, unsigned int count, unsigned int size) -{ - if (count == 0 || size == 0) - { - fz_free(ctx, p); - return 0; - } - - if (count > UINT_MAX / size) - { - fprintf(stderr, "error: resize array (%d x %d bytes) failed (integer overflow)\n", count, size); - return NULL; - } - - return do_scavenging_realloc(ctx, p, count * size); -} - -void -fz_free(fz_context *ctx, void *p) -{ - fz_lock(ctx, FZ_LOCK_ALLOC); - ctx->alloc->free(ctx->alloc->user, p); - fz_unlock(ctx, FZ_LOCK_ALLOC); -} - -char * -fz_strdup(fz_context *ctx, const char *s) -{ - int len = strlen(s) + 1; - char *ns = fz_malloc(ctx, len); - memcpy(ns, s, len); - return ns; -} - -char * -fz_strdup_no_throw(fz_context *ctx, const char *s) -{ - int len = strlen(s) + 1; - char *ns = fz_malloc_no_throw(ctx, len); - if (ns) - memcpy(ns, s, len); - return ns; -} - -static void * -fz_malloc_default(void *opaque, unsigned int size) -{ - return malloc(size); -} - -static void * -fz_realloc_default(void *opaque, void *old, unsigned int size) -{ - return realloc(old, size); -} - -static void -fz_free_default(void *opaque, void *ptr) -{ - free(ptr); -} - -fz_alloc_context fz_alloc_default = -{ - NULL, - fz_malloc_default, - fz_realloc_default, - fz_free_default -}; - -static void -fz_lock_default(void *user, int lock) -{ -} - -static void -fz_unlock_default(void *user, int lock) -{ -} - -fz_locks_context fz_locks_default = -{ - NULL, - fz_lock_default, - fz_unlock_default -}; - -#ifdef FITZ_DEBUG_LOCKING - -enum -{ - FZ_LOCK_DEBUG_CONTEXT_MAX = 100 -}; - -fz_context *fz_lock_debug_contexts[FZ_LOCK_DEBUG_CONTEXT_MAX]; -int fz_locks_debug[FZ_LOCK_DEBUG_CONTEXT_MAX][FZ_LOCK_MAX]; -#ifdef FITZ_DEBUG_LOCKING_TIMES -int fz_debug_locking_inited = 0; -int fz_lock_program_start; -int fz_lock_time[FZ_LOCK_DEBUG_CONTEXT_MAX][FZ_LOCK_MAX] = { { 0 } }; -int fz_lock_taken[FZ_LOCK_DEBUG_CONTEXT_MAX][FZ_LOCK_MAX] = { { 0 } }; - -/* We implement our own millisecond clock, as clock() cannot be trusted - * when threads are involved. */ -static int ms_clock(void) -{ -#ifdef _WIN32 - return (int)GetTickCount(); -#else - struct timeval tp; - gettimeofday(&tp, NULL); - return (tp.tv_sec*1000) + (tp.tv_usec/1000); -#endif -} - -static void dump_lock_times(void) -{ - int i, j; - int prog_time = ms_clock() - fz_lock_program_start; - - for (j = 0; j < FZ_LOCK_MAX; j++) - { - int total = 0; - for (i = 0; i < FZ_LOCK_DEBUG_CONTEXT_MAX; i++) - { - total += fz_lock_time[i][j]; - } - printf("Lock %d held for %g seconds (%g%%)\n", j, ((double)total)/1000, 100.0*total/prog_time); - } - printf("Total program time %g seconds\n", ((double)prog_time)/1000); -} - -#endif - -static int find_context(fz_context *ctx) -{ - int i; - - for (i = 0; i < FZ_LOCK_DEBUG_CONTEXT_MAX; i++) - { - if (fz_lock_debug_contexts[i] == ctx) - return i; - if (fz_lock_debug_contexts[i] == NULL) - { - int gottit = 0; - /* We've not locked on this context before, so use - * this one for this new context. We might have other - * threads trying here too though so, so claim it - * atomically. No one has locked on this context - * before, so we are safe to take the ALLOC lock. */ - ctx->locks->lock(ctx->locks->user, FZ_LOCK_ALLOC); - /* If it's still free, then claim it as ours, - * otherwise we'll keep hunting. */ - if (fz_lock_debug_contexts[i] == NULL) - { - gottit = 1; - fz_lock_debug_contexts[i] = ctx; -#ifdef FITZ_DEBUG_LOCKING_TIMES - if (fz_debug_locking_inited == 0) - { - fz_debug_locking_inited = 1; - fz_lock_program_start = ms_clock(); - atexit(dump_lock_times); - } -#endif - } - ctx->locks->unlock(ctx->locks->user, FZ_LOCK_ALLOC); - if (gottit) - return i; - } - } - return -1; -} - -void -fz_assert_lock_held(fz_context *ctx, int lock) -{ - int idx = find_context(ctx); - if (idx < 0) - return; - - if (fz_locks_debug[idx][lock] == 0) - fprintf(stderr, "Lock %d not held when expected\n", lock); -} - -void -fz_assert_lock_not_held(fz_context *ctx, int lock) -{ - int idx = find_context(ctx); - if (idx < 0) - return; - - if (fz_locks_debug[idx][lock] != 0) - fprintf(stderr, "Lock %d held when not expected\n", lock); -} - -void fz_lock_debug_lock(fz_context *ctx, int lock) -{ - int i; - int idx = find_context(ctx); - if (idx < 0) - return; - - if (fz_locks_debug[idx][lock] != 0) - { - fprintf(stderr, "Attempt to take lock %d when held already!\n", lock); - } - for (i = lock-1; i >= 0; i--) - { - if (fz_locks_debug[idx][i] != 0) - { - fprintf(stderr, "Lock ordering violation: Attempt to take lock %d when %d held already!\n", lock, i); - } - } - fz_locks_debug[idx][lock] = 1; -#ifdef FITZ_DEBUG_LOCKING_TIMES - fz_lock_taken[idx][lock] = clock(); -#endif -} - -void fz_lock_debug_unlock(fz_context *ctx, int lock) -{ - int idx = find_context(ctx); - if (idx < 0) - return; - - if (fz_locks_debug[idx][lock] == 0) - { - fprintf(stderr, "Attempt to release lock %d when not held!\n", lock); - } - fz_locks_debug[idx][lock] = 0; -#ifdef FITZ_DEBUG_LOCKING_TIMES - fz_lock_time[idx][lock] += clock() - fz_lock_taken[idx][lock]; -#endif -} - -#endif diff --git a/fitz/base_string.c b/fitz/base_string.c deleted file mode 100644 index b29cdbdc..00000000 --- a/fitz/base_string.c +++ /dev/null @@ -1,264 +0,0 @@ -#include "mupdf/fitz.h" - -char * -fz_strsep(char **stringp, const char *delim) -{ - char *ret = *stringp; - if (!ret) return NULL; - if ((*stringp = strpbrk(*stringp, delim))) - *((*stringp)++) = '\0'; - return ret; -} - -int -fz_strlcpy(char *dst, const char *src, int siz) -{ - register char *d = dst; - register const char *s = src; - register int n = siz; - - /* Copy as many bytes as will fit */ - if (n != 0 && --n != 0) { - do { - if ((*d++ = *s++) == 0) - break; - } while (--n != 0); - } - - /* Not enough room in dst, add NUL and traverse rest of src */ - if (n == 0) { - if (siz != 0) - *d = '\0'; /* NUL-terminate dst */ - while (*s++) - ; - } - - return(s - src - 1); /* count does not include NUL */ -} - -int -fz_strlcat(char *dst, const char *src, int siz) -{ - register char *d = dst; - register const char *s = src; - register int n = siz; - int dlen; - - /* Find the end of dst and adjust bytes left but don't go past end */ - while (*d != '\0' && n-- != 0) - d++; - dlen = d - dst; - n = siz - dlen; - - if (n == 0) - return dlen + strlen(s); - while (*s != '\0') { - if (n != 1) { - *d++ = *s; - n--; - } - s++; - } - *d = '\0'; - - return dlen + (s - src); /* count does not include NUL */ -} - -enum -{ - UTFmax = 4, /* maximum bytes per rune */ - Runesync = 0x80, /* cannot represent part of a UTF sequence (<) */ - Runeself = 0x80, /* rune and UTF sequences are the same (<) */ - Runeerror = 0xFFFD, /* decoding error in UTF */ - Runemax = 0x10FFFF, /* maximum rune value */ -}; - -enum -{ - Bit1 = 7, - Bitx = 6, - Bit2 = 5, - Bit3 = 4, - Bit4 = 3, - Bit5 = 2, - - T1 = ((1<<(Bit1+1))-1) ^ 0xFF, /* 0000 0000 */ - Tx = ((1<<(Bitx+1))-1) ^ 0xFF, /* 1000 0000 */ - T2 = ((1<<(Bit2+1))-1) ^ 0xFF, /* 1100 0000 */ - T3 = ((1<<(Bit3+1))-1) ^ 0xFF, /* 1110 0000 */ - T4 = ((1<<(Bit4+1))-1) ^ 0xFF, /* 1111 0000 */ - T5 = ((1<<(Bit5+1))-1) ^ 0xFF, /* 1111 1000 */ - - Rune1 = (1<<(Bit1+0*Bitx))-1, /* 0000 0000 0111 1111 */ - Rune2 = (1<<(Bit2+1*Bitx))-1, /* 0000 0111 1111 1111 */ - Rune3 = (1<<(Bit3+2*Bitx))-1, /* 1111 1111 1111 1111 */ - Rune4 = (1<<(Bit4+3*Bitx))-1, /* 0001 1111 1111 1111 1111 1111 */ - - Maskx = (1< T1 - */ - c = *(const unsigned char*)str; - if(c < Tx) { - *rune = c; - return 1; - } - - /* - * two character sequence - * 0080-07FF => T2 Tx - */ - c1 = *(const unsigned char*)(str+1) ^ Tx; - if(c1 & Testx) - goto bad; - if(c < T3) { - if(c < T2) - goto bad; - l = ((c << Bitx) | c1) & Rune2; - if(l <= Rune1) - goto bad; - *rune = l; - return 2; - } - - /* - * three character sequence - * 0800-FFFF => T3 Tx Tx - */ - c2 = *(const unsigned char*)(str+2) ^ Tx; - if(c2 & Testx) - goto bad; - if(c < T4) { - l = ((((c << Bitx) | c1) << Bitx) | c2) & Rune3; - if(l <= Rune2) - goto bad; - *rune = l; - return 3; - } - - /* - * four character sequence (21-bit value) - * 10000-1FFFFF => T4 Tx Tx Tx - */ - c3 = *(const unsigned char*)(str+3) ^ Tx; - if (c3 & Testx) - goto bad; - if (c < T5) { - l = ((((((c << Bitx) | c1) << Bitx) | c2) << Bitx) | c3) & Rune4; - if (l <= Rune3) - goto bad; - *rune = l; - return 4; - } - /* - * Support for 5-byte or longer UTF-8 would go here, but - * since we don't have that, we'll just fall through to bad. - */ - - /* - * bad decoding - */ -bad: - *rune = Bad; - return 1; -} - -int -fz_runetochar(char *str, int rune) -{ - /* Runes are signed, so convert to unsigned for range check. */ - unsigned long c = (unsigned long)rune; - - /* - * one character sequence - * 00000-0007F => 00-7F - */ - if(c <= Rune1) { - str[0] = c; - return 1; - } - - /* - * two character sequence - * 0080-07FF => T2 Tx - */ - if(c <= Rune2) { - str[0] = T2 | (c >> 1*Bitx); - str[1] = Tx | (c & Maskx); - return 2; - } - - /* - * If the Rune is out of range, convert it to the error rune. - * Do this test here because the error rune encodes to three bytes. - * Doing it earlier would duplicate work, since an out of range - * Rune wouldn't have fit in one or two bytes. - */ - if (c > Runemax) - c = Runeerror; - - /* - * three character sequence - * 0800-FFFF => T3 Tx Tx - */ - if (c <= Rune3) { - str[0] = T3 | (c >> 2*Bitx); - str[1] = Tx | ((c >> 1*Bitx) & Maskx); - str[2] = Tx | (c & Maskx); - return 3; - } - - /* - * four character sequence (21-bit value) - * 10000-1FFFFF => T4 Tx Tx Tx - */ - str[0] = T4 | (c >> 3*Bitx); - str[1] = Tx | ((c >> 2*Bitx) & Maskx); - str[2] = Tx | ((c >> 1*Bitx) & Maskx); - str[3] = Tx | (c & Maskx); - return 4; -} - -int -fz_runelen(int c) -{ - char str[10]; - return fz_runetochar(str, c); -} - -float fz_atof(const char *s) -{ - double d; - - /* The errno voodoo here checks for us reading numbers that are too - * big to fit into a double. The checks for FLT_MAX ensure that we - * don't read a number that's OK as a double and then become invalid - * as we convert to a float. */ - errno = 0; - d = strtod(s, NULL); - if (errno == ERANGE || isnan(d)) { - /* Return 1.0, as it's a small known value that won't cause a divide by 0. */ - return 1.0; - } - d = fz_clampd(d, -FLT_MAX, FLT_MAX); - return (float)d; -} - -int fz_atoi(const char *s) -{ - if (s == NULL) - return 0; - return atoi(s); -} diff --git a/fitz/base_time.c b/fitz/base_time.c deleted file mode 100644 index 0e3d21b5..00000000 --- a/fitz/base_time.c +++ /dev/null @@ -1,144 +0,0 @@ -#ifdef _MSC_VER - -#include "mupdf/fitz.h" - -#include -#include - -#ifndef _WINRT - -#define DELTA_EPOCH_IN_MICROSECS 11644473600000000Ui64 - -struct timeval; -struct timezone; - -int gettimeofday(struct timeval *tv, struct timezone *tz) -{ - FILETIME ft; - unsigned __int64 tmpres = 0; - - if (tv) - { - GetSystemTimeAsFileTime(&ft); - - tmpres |= ft.dwHighDateTime; - tmpres <<= 32; - tmpres |= ft.dwLowDateTime; - - tmpres /= 10; /*convert into microseconds*/ - /*converting file time to unix epoch*/ - tmpres -= DELTA_EPOCH_IN_MICROSECS; - tv->tv_sec = (long)(tmpres / 1000000UL); - tv->tv_usec = (long)(tmpres % 1000000UL); - } - - return 0; -} - -#endif /* !_WINRT */ - -char * -fz_utf8_from_wchar(const wchar_t *s) -{ - const wchar_t *src = s; - char *d; - char *dst; - int len = 1; - - while (*src) - { - len += fz_runelen(*src++); - } - - d = malloc(len); - if (d != NULL) - { - dst = d; - src = s; - while (*src) - { - dst += fz_runetochar(dst, *src++); - } - *dst = 0; - } - return d; -} - -wchar_t * -fz_wchar_from_utf8(const char *s) -{ - wchar_t *d, *r; - int c; - r = d = malloc((strlen(s) + 1) * sizeof(wchar_t)); - if (!r) - return NULL; - while (*s) { - s += fz_chartorune(&c, s); - *d++ = c; - } - *d = 0; - return r; -} - -FILE * -fz_fopen_utf8(const char *name, const char *mode) -{ - wchar_t *wname, *wmode; - FILE *file; - - wname = fz_wchar_from_utf8(name); - if (wname == NULL) - { - return NULL; - } - - wmode = fz_wchar_from_utf8(mode); - if (wmode == NULL) - { - free(wname); - return NULL; - } - - file = _wfopen(wname, wmode); - - free(wname); - free(wmode); - return file; -} - -char ** -fz_argv_from_wargv(int argc, wchar_t **wargv) -{ - char **argv; - int i; - - argv = calloc(argc, sizeof(char *)); - if (argv == NULL) - { - fprintf(stderr, "Out of memory while processing command line args!\n"); - exit(1); - } - - for (i = 0; i < argc; i++) - { - argv[i] = fz_utf8_from_wchar(wargv[i]); - if (argv[i] == NULL) - { - fprintf(stderr, "Out of memory while processing command line args!\n"); - exit(1); - } - } - - return argv; -} - -void -fz_free_argv(int argc, char **argv) -{ - int i; - for (i = 0; i < argc; i++) - free(argv[i]); - free(argv); -} - -#endif /* _MSC_VER */ diff --git a/fitz/base_trans.c b/fitz/base_trans.c deleted file mode 100644 index 92582253..00000000 --- a/fitz/base_trans.c +++ /dev/null @@ -1,165 +0,0 @@ -#include "mupdf/fitz.h" - -static int -fade(fz_pixmap *tpix, fz_pixmap *opix, fz_pixmap *npix, int time) -{ - unsigned char *t, *o, *n; - int size; - - if (!tpix || !opix || !npix || tpix->w != opix->w || opix->w != npix->w || tpix->h != opix->h || opix->h != npix->h || tpix->n != opix->n || opix->n != npix->n) - return 0; - size = tpix->w * tpix->h * tpix->n; - t = tpix->samples; - o = opix->samples; - n = npix->samples; - while (size-- > 0) - { - int op = *o++; - int np = *n++; - *t++ = ((op<<8) + ((np-op) * time) + 0x80)>>8; - } - return 1; -} - -static int -blind_horiz(fz_pixmap *tpix, fz_pixmap *opix, fz_pixmap *npix, int time) -{ - unsigned char *t, *o, *n; - int blind_height, span, position, y; - - if (!tpix || !opix || !npix || tpix->w != opix->w || opix->w != npix->w || tpix->h != opix->h || opix->h != npix->h || tpix->n != opix->n || opix->n != npix->n) - return 0; - span = tpix->w * tpix->n; - blind_height = (tpix->h+7) / 8; - position = blind_height * time / 256; - t = tpix->samples; - o = opix->samples; - n = npix->samples; - for (y = 0; y < tpix->h; y++) - { - memcpy(t, ((y % blind_height) <= position ? n : o), span); - t += span; - o += span; - n += span; - } - return 1; -} - -static int -blind_vertical(fz_pixmap *tpix, fz_pixmap *opix, fz_pixmap *npix, int time) -{ - unsigned char *t, *o, *n; - int blind_width, span, position, y; - - if (!tpix || !opix || !npix || tpix->w != opix->w || opix->w != npix->w || tpix->h != opix->h || opix->h != npix->h || tpix->n != opix->n || opix->n != npix->n) - return 0; - span = tpix->w * tpix->n; - blind_width = (tpix->w+7) / 8; - position = blind_width * time / 256; - blind_width *= tpix->n; - position *= tpix->n; - t = tpix->samples; - o = opix->samples; - n = npix->samples; - for (y = 0; y < tpix->h; y++) - { - int w, x; - x = 0; - while ((w = span - x) > 0) - { - int p; - if (w > blind_width) - w = blind_width; - p = position; - if (p > w) - p = w; - memcpy(t, n, p); - memcpy(t+position, o+position, w - p); - x += blind_width; - t += w; - o += w; - n += w; - } - } - return 1; -} - -static int -wipe_tb(fz_pixmap *tpix, fz_pixmap *opix, fz_pixmap *npix, int time) -{ - unsigned char *t, *o, *n; - int span, position, y; - - if (!tpix || !opix || !npix || tpix->w != opix->w || opix->w != npix->w || tpix->h != opix->h || opix->h != npix->h || tpix->n != opix->n || opix->n != npix->n) - return 0; - span = tpix->w * tpix->n; - position = tpix->h * time / 256; - t = tpix->samples; - o = opix->samples; - n = npix->samples; - for (y = 0; y < position; y++) - { - memcpy(t, n, span); - t += span; - o += span; - n += span; - } - for (; y < tpix->h; y++) - { - memcpy(t, o, span); - t += span; - o += span; - n += span; - } - return 1; -} - -static int -wipe_lr(fz_pixmap *tpix, fz_pixmap *opix, fz_pixmap *npix, int time) -{ - unsigned char *t, *o, *n; - int span, position, y; - - if (!tpix || !opix || !npix || tpix->w != opix->w || opix->w != npix->w || tpix->h != opix->h || opix->h != npix->h || tpix->n != opix->n || opix->n != npix->n) - return 0; - span = tpix->w * tpix->n; - position = tpix->w * time / 256; - position *= tpix->n; - t = tpix->samples; - o = opix->samples + position; - n = npix->samples; - for (y = 0; y < tpix->h; y++) - { - memcpy(t, n, position); - memcpy(t+position, o, span-position); - t += span; - o += span; - n += span; - } - return 1; -} - -int fz_generate_transition(fz_pixmap *tpix, fz_pixmap *opix, fz_pixmap *npix, int time, fz_transition *trans) -{ - switch (trans->type) - { - default: - case FZ_TRANSITION_FADE: - return fade(tpix, opix, npix, time); - case FZ_TRANSITION_BLINDS: - if (trans->vertical) - return blind_vertical(tpix, opix, npix, time); - else - return blind_horiz(tpix, opix, npix, time); - case FZ_TRANSITION_WIPE: - switch (((trans->direction + 45 + 360) % 360) / 90) - { - default: - case 0: return wipe_lr(tpix, opix, npix, time); - case 1: return wipe_tb(tpix, npix, opix, 256-time); - case 2: return wipe_lr(tpix, npix, opix, 256-time); - case 3: return wipe_tb(tpix, opix, npix, time); - } - } - return 0; -} diff --git a/fitz/base_xml.c b/fitz/base_xml.c deleted file mode 100644 index 8c97562c..00000000 --- a/fitz/base_xml.c +++ /dev/null @@ -1,460 +0,0 @@ -#include "mupdf/fitz.h" - -struct parser -{ - fz_xml *head; - fz_context *ctx; -}; - -struct attribute -{ - char name[40]; - char *value; - struct attribute *next; -}; - -struct fz_xml_s -{ - char name[40]; - char *text; - struct attribute *atts; - fz_xml *up, *down, *next; -}; - -static inline void indent(int n) -{ - while (n--) putchar(' '); -} - -void fz_debug_xml(fz_xml *item, int level) -{ - while (item) { - if (item->text) { - printf("%s\n", item->text); - } else { - struct attribute *att; - indent(level); - printf("<%s", item->name); - for (att = item->atts; att; att = att->next) - printf(" %s=\"%s\"", att->name, att->value); - if (item->down) { - printf(">\n"); - fz_debug_xml(item->down, level + 1); - indent(level); - printf("\n", item->name); - } - else { - printf("/>\n"); - } - } - item = item->next; - } -} - -fz_xml *fz_xml_next(fz_xml *item) -{ - return item->next; -} - -fz_xml *fz_xml_down(fz_xml *item) -{ - return item->down; -} - -char *fz_xml_text(fz_xml *item) -{ - return item->text; -} - -char *fz_xml_tag(fz_xml *item) -{ - return item->name; -} - -char *fz_xml_att(fz_xml *item, const char *name) -{ - struct attribute *att; - for (att = item->atts; att; att = att->next) - if (!strcmp(att->name, name)) - return att->value; - return NULL; -} - -static void xml_free_attribute(fz_context *ctx, struct attribute *att) -{ - while (att) { - struct attribute *next = att->next; - if (att->value) - fz_free(ctx, att->value); - fz_free(ctx, att); - att = next; - } -} - -void fz_free_xml(fz_context *ctx, fz_xml *item) -{ - while (item) - { - fz_xml *next = item->next; - if (item->text) - fz_free(ctx, item->text); - if (item->atts) - xml_free_attribute(ctx, item->atts); - if (item->down) - fz_free_xml(ctx, item->down); - fz_free(ctx, item); - item = next; - } -} - -void fz_detach_xml(fz_xml *node) -{ - if (node->up) - node->up->down = NULL; -} - -static int xml_parse_entity(int *c, char *a) -{ - char *b; - if (a[1] == '#') { - if (a[2] == 'x') - *c = strtol(a + 3, &b, 16); - else - *c = strtol(a + 2, &b, 10); - if (*b == ';') - return b - a + 1; - } - else if (a[1] == 'l' && a[2] == 't' && a[3] == ';') { - *c = '<'; - return 4; - } - else if (a[1] == 'g' && a[2] == 't' && a[3] == ';') { - *c = '>'; - return 4; - } - else if (a[1] == 'a' && a[2] == 'm' && a[3] == 'p' && a[4] == ';') { - *c = '&'; - return 5; - } - else if (a[1] == 'a' && a[2] == 'p' && a[3] == 'o' && a[4] == 's' && a[5] == ';') { - *c = '\''; - return 6; - } - else if (a[1] == 'q' && a[2] == 'u' && a[3] == 'o' && a[4] == 't' && a[5] == ';') { - *c = '"'; - return 6; - } - *c = *a++; - return 1; -} - -static inline int isname(int c) -{ - return c == '.' || c == '-' || c == '_' || c == ':' || - (c >= '0' && c <= '9') || - (c >= 'A' && c <= 'Z') || - (c >= 'a' && c <= 'z'); -} - -static inline int iswhite(int c) -{ - return c == ' ' || c == '\r' || c == '\n' || c == '\t'; -} - -static void xml_emit_open_tag(struct parser *parser, char *a, char *b) -{ - fz_xml *head, *tail; - - head = fz_malloc_struct(parser->ctx, fz_xml); - if (b - a > sizeof(head->name) - 1) - b = a + sizeof(head->name) - 1; - memcpy(head->name, a, b - a); - head->name[b - a] = 0; - - head->atts = NULL; - head->text = NULL; - head->up = parser->head; - head->down = NULL; - head->next = NULL; - - if (!parser->head->down) { - parser->head->down = head; - } - else { - tail = parser->head->down; - while (tail->next) - tail = tail->next; - tail->next = head; - } - - parser->head = head; -} - -static void xml_emit_att_name(struct parser *parser, char *a, char *b) -{ - fz_xml *head = parser->head; - struct attribute *att; - - att = fz_malloc_struct(parser->ctx, struct attribute); - if (b - a > sizeof(att->name) - 1) - b = a + sizeof(att->name) - 1; - memcpy(att->name, a, b - a); - att->name[b - a] = 0; - att->value = NULL; - att->next = head->atts; - head->atts = att; -} - -static void xml_emit_att_value(struct parser *parser, char *a, char *b) -{ - fz_xml *head = parser->head; - struct attribute *att = head->atts; - char *s; - int c; - - /* entities are all longer than UTFmax so runetochar is safe */ - s = att->value = fz_malloc(parser->ctx, b - a + 1); - while (a < b) { - if (*a == '&') { - a += xml_parse_entity(&c, a); - s += fz_runetochar(s, c); - } - else { - *s++ = *a++; - } - } - *s = 0; -} - -static void xml_emit_close_tag(struct parser *parser) -{ - if (parser->head->up) - parser->head = parser->head->up; -} - -static void xml_emit_text(struct parser *parser, char *a, char *b) -{ - static char *empty = ""; - fz_xml *head; - char *s; - int c; - - /* Skip all-whitespace text nodes */ - for (s = a; s < b; s++) - if (!iswhite(*s)) - break; - if (s == b) - return; - - xml_emit_open_tag(parser, empty, empty); - head = parser->head; - - /* entities are all longer than UTFmax so runetochar is safe */ - s = head->text = fz_malloc(parser->ctx, b - a + 1); - while (a < b) { - if (*a == '&') { - a += xml_parse_entity(&c, a); - s += fz_runetochar(s, c); - } - else { - *s++ = *a++; - } - } - *s = 0; - - xml_emit_close_tag(parser); -} - -static char *xml_parse_document_imp(struct parser *x, char *p) -{ - char *mark; - int quote; - -parse_text: - mark = p; - while (*p && *p != '<') ++p; - xml_emit_text(x, mark, p); - if (*p == '<') { ++p; goto parse_element; } - return NULL; - -parse_element: - if (*p == '/') { ++p; goto parse_closing_element; } - if (*p == '!') { ++p; goto parse_comment; } - if (*p == '?') { ++p; goto parse_processing_instruction; } - while (iswhite(*p)) ++p; - if (isname(*p)) - goto parse_element_name; - return "syntax error in element"; - -parse_comment: - if (*p == '[') goto parse_cdata; - if (*p++ != '-') return "syntax error in comment (') { - p += 3; - goto parse_text; - } - ++p; - } - return "end of data in comment"; - -parse_cdata: - if (p[1] != 'C' || p[2] != 'D' || p[3] != 'A' || p[4] != 'T' || p[5] != 'A' || p[6] != '[') - return "syntax error in CDATA section"; - p += 7; - mark = p; - while (*p) { - if (p[0] == ']' && p[1] == ']' && p[2] == '>') { - p += 3; - goto parse_text; - } - ++p; - } - return "end of data in CDATA section"; - -parse_processing_instruction: - while (*p) { - if (p[0] == '?' && p[1] == '>') { - p += 2; - goto parse_text; - } - ++p; - } - return "end of data in processing instruction"; - -parse_closing_element: - while (iswhite(*p)) ++p; - mark = p; - while (isname(*p)) ++p; - while (iswhite(*p)) ++p; - if (*p != '>') - return "syntax error in closing element"; - xml_emit_close_tag(x); - ++p; - goto parse_text; - -parse_element_name: - mark = p; - while (isname(*p)) ++p; - xml_emit_open_tag(x, mark, p); - if (*p == '>') { ++p; goto parse_text; } - if (p[0] == '/' && p[1] == '>') { - xml_emit_close_tag(x); - p += 2; - goto parse_text; - } - if (iswhite(*p)) - goto parse_attributes; - return "syntax error after element name"; - -parse_attributes: - while (iswhite(*p)) ++p; - if (isname(*p)) - goto parse_attribute_name; - if (*p == '>') { ++p; goto parse_text; } - if (p[0] == '/' && p[1] == '>') { - xml_emit_close_tag(x); - p += 2; - goto parse_text; - } - return "syntax error in attributes"; - -parse_attribute_name: - mark = p; - while (isname(*p)) ++p; - xml_emit_att_name(x, mark, p); - while (iswhite(*p)) ++p; - if (*p == '=') { ++p; goto parse_attribute_value; } - return "syntax error after attribute name"; - -parse_attribute_value: - while (iswhite(*p)) ++p; - quote = *p++; - if (quote != '"' && quote != '\'') - return "missing quote character"; - mark = p; - while (*p && *p != quote) ++p; - if (*p == quote) { - xml_emit_att_value(x, mark, p++); - goto parse_attributes; - } - return "end of data in attribute value"; -} - -static char *convert_to_utf8(fz_context *doc, unsigned char *s, int n, int *dofree) -{ - unsigned char *e = s + n; - char *dst, *d; - int c; - - if (s[0] == 0xFE && s[1] == 0xFF) { - s += 2; - dst = d = fz_malloc(doc, n * 2); - while (s + 1 < e) { - c = s[0] << 8 | s[1]; - d += fz_runetochar(d, c); - s += 2; - } - *d = 0; - *dofree = 1; - return dst; - } - - if (s[0] == 0xFF && s[1] == 0xFE) { - s += 2; - dst = d = fz_malloc(doc, n * 2); - while (s + 1 < e) { - c = s[0] | s[1] << 8; - d += fz_runetochar(d, c); - s += 2; - } - *d = 0; - *dofree = 1; - return dst; - } - - *dofree = 0; - - if (s[0] == 0xEF && s[1] == 0xBB && s[2] == 0xBF) - return (char*)s+3; - - return (char*)s; -} - -fz_xml * -fz_parse_xml(fz_context *ctx, unsigned char *s, int n) -{ - struct parser parser; - fz_xml root; - char *p, *error; - int dofree; - - /* s is already null-terminated (see xps_new_part) */ - - memset(&root, 0, sizeof(root)); - parser.head = &root; - parser.ctx = ctx; - - p = convert_to_utf8(ctx, s, n, &dofree); - - fz_try(ctx) - { - error = xml_parse_document_imp(&parser, p); - if (error) - fz_throw(ctx, FZ_ERROR_GENERIC, "%s", error); - } - fz_always(ctx) - { - if (dofree) - fz_free(ctx, p); - } - fz_catch(ctx) - { - fz_free_xml(ctx, root.down); - fz_rethrow(ctx); - } - - return root.down; -} diff --git a/fitz/crypt_aes.c b/fitz/crypt_aes.c deleted file mode 100644 index 6ce14903..00000000 --- a/fitz/crypt_aes.c +++ /dev/null @@ -1,569 +0,0 @@ -/* - * FIPS-197 compliant AES implementation - * - * Copyright (C) 2006-2007 Christophe Devine - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code _must_ retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form may or may not reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials provided - * with the distribution. - * * Neither the name of XySSL nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -/* - * The AES block cipher was designed by Vincent Rijmen and Joan Daemen. - * - * http://csrc.nist.gov/encryption/aes/rijndael/Rijndael.pdf - * http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf - */ - -#include "mupdf/fitz.h" - -#define aes_context fz_aes - -/* AES block cipher implementation from XYSSL */ - -/* - * 32-bit integer manipulation macros (little endian) - */ -#ifndef GET_ULONG_LE -#define GET_ULONG_LE(n,b,i) \ -{ \ - (n) = ( (unsigned long) (b)[(i)] ) \ - | ( (unsigned long) (b)[(i) + 1] << 8 ) \ - | ( (unsigned long) (b)[(i) + 2] << 16 ) \ - | ( (unsigned long) (b)[(i) + 3] << 24 ); \ -} -#endif - -#ifndef PUT_ULONG_LE -#define PUT_ULONG_LE(n,b,i) \ -{ \ - (b)[(i) ] = (unsigned char) ( (n) ); \ - (b)[(i) + 1] = (unsigned char) ( (n) >> 8 ); \ - (b)[(i) + 2] = (unsigned char) ( (n) >> 16 ); \ - (b)[(i) + 3] = (unsigned char) ( (n) >> 24 ); \ -} -#endif - -/* - * Forward S-box & tables - */ -static unsigned char FSb[256]; -static unsigned long FT0[256]; -static unsigned long FT1[256]; -static unsigned long FT2[256]; -static unsigned long FT3[256]; - -/* - * Reverse S-box & tables - */ -static unsigned char RSb[256]; -static unsigned long RT0[256]; -static unsigned long RT1[256]; -static unsigned long RT2[256]; -static unsigned long RT3[256]; - -/* - * Round constants - */ -static unsigned long RCON[10]; - -/* - * Tables generation code - */ -#define ROTL8(x) ( ( x << 8 ) & 0xFFFFFFFF ) | ( x >> 24 ) -#define XTIME(x) ( ( x << 1 ) ^ ( ( x & 0x80 ) ? 0x1B : 0x00 ) ) -#define MUL(x,y) ( ( x && y ) ? pow[(log[x]+log[y]) % 255] : 0 ) - -static int aes_init_done = 0; - -static void aes_gen_tables( void ) -{ - int i, x, y, z; - int pow[256]; - int log[256]; - - /* - * compute pow and log tables over GF(2^8) - */ - for( i = 0, x = 1; i < 256; i++ ) - { - pow[i] = x; - log[x] = i; - x = ( x ^ XTIME( x ) ) & 0xFF; - } - - /* - * calculate the round constants - */ - for( i = 0, x = 1; i < 10; i++ ) - { - RCON[i] = (unsigned long) x; - x = XTIME( x ) & 0xFF; - } - - /* - * generate the forward and reverse S-boxes - */ - FSb[0x00] = 0x63; - RSb[0x63] = 0x00; - - for( i = 1; i < 256; i++ ) - { - x = pow[255 - log[i]]; - - y = x; y = ( (y << 1) | (y >> 7) ) & 0xFF; - x ^= y; y = ( (y << 1) | (y >> 7) ) & 0xFF; - x ^= y; y = ( (y << 1) | (y >> 7) ) & 0xFF; - x ^= y; y = ( (y << 1) | (y >> 7) ) & 0xFF; - x ^= y ^ 0x63; - - FSb[i] = (unsigned char) x; - RSb[x] = (unsigned char) i; - } - - /* - * generate the forward and reverse tables - */ - for( i = 0; i < 256; i++ ) - { - x = FSb[i]; - y = XTIME( x ) & 0xFF; - z = ( y ^ x ) & 0xFF; - - FT0[i] = ( (unsigned long) y ) ^ - ( (unsigned long) x << 8 ) ^ - ( (unsigned long) x << 16 ) ^ - ( (unsigned long) z << 24 ); - - FT1[i] = ROTL8( FT0[i] ); - FT2[i] = ROTL8( FT1[i] ); - FT3[i] = ROTL8( FT2[i] ); - - x = RSb[i]; - - RT0[i] = ( (unsigned long) MUL( 0x0E, x ) ) ^ - ( (unsigned long) MUL( 0x09, x ) << 8 ) ^ - ( (unsigned long) MUL( 0x0D, x ) << 16 ) ^ - ( (unsigned long) MUL( 0x0B, x ) << 24 ); - - RT1[i] = ROTL8( RT0[i] ); - RT2[i] = ROTL8( RT1[i] ); - RT3[i] = ROTL8( RT2[i] ); - } -} - -/* - * AES key schedule (encryption) - */ -int aes_setkey_enc( aes_context *ctx, const unsigned char *key, int keysize ) -{ - int i; - unsigned long *RK; - -#if !defined(XYSSL_AES_ROM_TABLES) - if( aes_init_done == 0 ) - { - aes_gen_tables(); - aes_init_done = 1; - } -#endif - - switch( keysize ) - { - case 128: ctx->nr = 10; break; - case 192: ctx->nr = 12; break; - case 256: ctx->nr = 14; break; - default : return 1; - } - -#if defined(PADLOCK_ALIGN16) - ctx->rk = RK = PADLOCK_ALIGN16( ctx->buf ); -#else - ctx->rk = RK = ctx->buf; -#endif - - for( i = 0; i < (keysize >> 5); i++ ) - { - GET_ULONG_LE( RK[i], key, i << 2 ); - } - - switch( ctx->nr ) - { - case 10: - - for( i = 0; i < 10; i++, RK += 4 ) - { - RK[4] = RK[0] ^ RCON[i] ^ - ( FSb[ ( RK[3] >> 8 ) & 0xFF ] ) ^ - ( FSb[ ( RK[3] >> 16 ) & 0xFF ] << 8 ) ^ - ( FSb[ ( RK[3] >> 24 ) & 0xFF ] << 16 ) ^ - ( FSb[ ( RK[3] ) & 0xFF ] << 24 ); - - RK[5] = RK[1] ^ RK[4]; - RK[6] = RK[2] ^ RK[5]; - RK[7] = RK[3] ^ RK[6]; - } - break; - - case 12: - - for( i = 0; i < 8; i++, RK += 6 ) - { - RK[6] = RK[0] ^ RCON[i] ^ - ( FSb[ ( RK[5] >> 8 ) & 0xFF ] ) ^ - ( FSb[ ( RK[5] >> 16 ) & 0xFF ] << 8 ) ^ - ( FSb[ ( RK[5] >> 24 ) & 0xFF ] << 16 ) ^ - ( FSb[ ( RK[5] ) & 0xFF ] << 24 ); - - RK[7] = RK[1] ^ RK[6]; - RK[8] = RK[2] ^ RK[7]; - RK[9] = RK[3] ^ RK[8]; - RK[10] = RK[4] ^ RK[9]; - RK[11] = RK[5] ^ RK[10]; - } - break; - - case 14: - - for( i = 0; i < 7; i++, RK += 8 ) - { - RK[8] = RK[0] ^ RCON[i] ^ - ( FSb[ ( RK[7] >> 8 ) & 0xFF ] ) ^ - ( FSb[ ( RK[7] >> 16 ) & 0xFF ] << 8 ) ^ - ( FSb[ ( RK[7] >> 24 ) & 0xFF ] << 16 ) ^ - ( FSb[ ( RK[7] ) & 0xFF ] << 24 ); - - RK[9] = RK[1] ^ RK[8]; - RK[10] = RK[2] ^ RK[9]; - RK[11] = RK[3] ^ RK[10]; - - RK[12] = RK[4] ^ - ( FSb[ ( RK[11] ) & 0xFF ] ) ^ - ( FSb[ ( RK[11] >> 8 ) & 0xFF ] << 8 ) ^ - ( FSb[ ( RK[11] >> 16 ) & 0xFF ] << 16 ) ^ - ( FSb[ ( RK[11] >> 24 ) & 0xFF ] << 24 ); - - RK[13] = RK[5] ^ RK[12]; - RK[14] = RK[6] ^ RK[13]; - RK[15] = RK[7] ^ RK[14]; - } - break; - - default: - - break; - } - return 0; -} - -/* - * AES key schedule (decryption) - */ -int aes_setkey_dec(aes_context *ctx, const unsigned char *key, int keysize) -{ - int i, j; - aes_context cty; - unsigned long *RK; - unsigned long *SK; - - switch( keysize ) - { - case 128: ctx->nr = 10; break; - case 192: ctx->nr = 12; break; - case 256: ctx->nr = 14; break; - default: return 1; - } - -#if defined(PADLOCK_ALIGN16) - ctx->rk = RK = PADLOCK_ALIGN16( ctx->buf ); -#else - ctx->rk = RK = ctx->buf; -#endif - - i = aes_setkey_enc( &cty, key, keysize ); - if (i) - return i; - SK = cty.rk + cty.nr * 4; - - *RK++ = *SK++; - *RK++ = *SK++; - *RK++ = *SK++; - *RK++ = *SK++; - - for( i = ctx->nr - 1, SK -= 8; i > 0; i--, SK -= 8 ) - { - for( j = 0; j < 4; j++, SK++ ) - { - *RK++ = RT0[ FSb[ ( *SK ) & 0xFF ] ] ^ - RT1[ FSb[ ( *SK >> 8 ) & 0xFF ] ] ^ - RT2[ FSb[ ( *SK >> 16 ) & 0xFF ] ] ^ - RT3[ FSb[ ( *SK >> 24 ) & 0xFF ] ]; - } - } - - *RK++ = *SK++; - *RK++ = *SK++; - *RK++ = *SK++; - *RK++ = *SK++; - - memset( &cty, 0, sizeof( aes_context ) ); - return 0; -} - -#define AES_FROUND(X0,X1,X2,X3,Y0,Y1,Y2,Y3) \ -{ \ - X0 = *RK++ ^ FT0[ ( Y0 ) & 0xFF ] ^ \ - FT1[ ( Y1 >> 8 ) & 0xFF ] ^ \ - FT2[ ( Y2 >> 16 ) & 0xFF ] ^ \ - FT3[ ( Y3 >> 24 ) & 0xFF ]; \ - \ - X1 = *RK++ ^ FT0[ ( Y1 ) & 0xFF ] ^ \ - FT1[ ( Y2 >> 8 ) & 0xFF ] ^ \ - FT2[ ( Y3 >> 16 ) & 0xFF ] ^ \ - FT3[ ( Y0 >> 24 ) & 0xFF ]; \ - \ - X2 = *RK++ ^ FT0[ ( Y2 ) & 0xFF ] ^ \ - FT1[ ( Y3 >> 8 ) & 0xFF ] ^ \ - FT2[ ( Y0 >> 16 ) & 0xFF ] ^ \ - FT3[ ( Y1 >> 24 ) & 0xFF ]; \ - \ - X3 = *RK++ ^ FT0[ ( Y3 ) & 0xFF ] ^ \ - FT1[ ( Y0 >> 8 ) & 0xFF ] ^ \ - FT2[ ( Y1 >> 16 ) & 0xFF ] ^ \ - FT3[ ( Y2 >> 24 ) & 0xFF ]; \ -} - -#define AES_RROUND(X0,X1,X2,X3,Y0,Y1,Y2,Y3) \ -{ \ - X0 = *RK++ ^ RT0[ ( Y0 ) & 0xFF ] ^ \ - RT1[ ( Y3 >> 8 ) & 0xFF ] ^ \ - RT2[ ( Y2 >> 16 ) & 0xFF ] ^ \ - RT3[ ( Y1 >> 24 ) & 0xFF ]; \ - \ - X1 = *RK++ ^ RT0[ ( Y1 ) & 0xFF ] ^ \ - RT1[ ( Y0 >> 8 ) & 0xFF ] ^ \ - RT2[ ( Y3 >> 16 ) & 0xFF ] ^ \ - RT3[ ( Y2 >> 24 ) & 0xFF ]; \ - \ - X2 = *RK++ ^ RT0[ ( Y2 ) & 0xFF ] ^ \ - RT1[ ( Y1 >> 8 ) & 0xFF ] ^ \ - RT2[ ( Y0 >> 16 ) & 0xFF ] ^ \ - RT3[ ( Y3 >> 24 ) & 0xFF ]; \ - \ - X3 = *RK++ ^ RT0[ ( Y3 ) & 0xFF ] ^ \ - RT1[ ( Y2 >> 8 ) & 0xFF ] ^ \ - RT2[ ( Y1 >> 16 ) & 0xFF ] ^ \ - RT3[ ( Y0 >> 24 ) & 0xFF ]; \ -} - -/* - * AES-ECB block encryption/decryption - */ -void aes_crypt_ecb( aes_context *ctx, - int mode, - const unsigned char input[16], - unsigned char output[16] ) -{ - int i; - unsigned long *RK, X0, X1, X2, X3, Y0, Y1, Y2, Y3; - -#if defined(XYSSL_PADLOCK_C) && defined(XYSSL_HAVE_X86) - if( padlock_supports( PADLOCK_ACE ) ) - { - if( padlock_xcryptecb( ctx, mode, input, output ) == 0 ) - return; - } -#endif - - RK = ctx->rk; - - GET_ULONG_LE( X0, input, 0 ); X0 ^= *RK++; - GET_ULONG_LE( X1, input, 4 ); X1 ^= *RK++; - GET_ULONG_LE( X2, input, 8 ); X2 ^= *RK++; - GET_ULONG_LE( X3, input, 12 ); X3 ^= *RK++; - - if( mode == AES_DECRYPT ) - { - for( i = (ctx->nr >> 1) - 1; i > 0; i-- ) - { - AES_RROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); - AES_RROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); - } - - AES_RROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); - - X0 = *RK++ ^ ( RSb[ ( Y0 ) & 0xFF ] ) ^ - ( RSb[ ( Y3 >> 8 ) & 0xFF ] << 8 ) ^ - ( RSb[ ( Y2 >> 16 ) & 0xFF ] << 16 ) ^ - ( RSb[ ( Y1 >> 24 ) & 0xFF ] << 24 ); - - X1 = *RK++ ^ ( RSb[ ( Y1 ) & 0xFF ] ) ^ - ( RSb[ ( Y0 >>8 ) & 0xFF ] << 8 ) ^ - ( RSb[ ( Y3 >> 16 ) & 0xFF ] << 16 ) ^ - ( RSb[ ( Y2 >> 24 ) & 0xFF ] << 24 ); - - X2 = *RK++ ^ ( RSb[ ( Y2 ) & 0xFF ] ) ^ - ( RSb[ ( Y1 >> 8 ) & 0xFF ] << 8 ) ^ - ( RSb[ ( Y0 >> 16 ) & 0xFF ] << 16 ) ^ - ( RSb[ ( Y3 >> 24 ) & 0xFF ] << 24 ); - - X3 = *RK++ ^ ( RSb[ ( Y3 ) & 0xFF ] ) ^ - ( RSb[ ( Y2 >> 8 ) & 0xFF ] << 8 ) ^ - ( RSb[ ( Y1 >> 16 ) & 0xFF ] << 16 ) ^ - ( RSb[ ( Y0 >> 24 ) & 0xFF ] << 24 ); - } - else /* AES_ENCRYPT */ - { - for( i = (ctx->nr >> 1) - 1; i > 0; i-- ) - { - AES_FROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); - AES_FROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); - } - - AES_FROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); - - X0 = *RK++ ^ ( FSb[ ( Y0 ) & 0xFF ] ) ^ - ( FSb[ ( Y1 >> 8 ) & 0xFF ] << 8 ) ^ - ( FSb[ ( Y2 >> 16 ) & 0xFF ] << 16 ) ^ - ( FSb[ ( Y3 >> 24 ) & 0xFF ] << 24 ); - - X1 = *RK++ ^ ( FSb[ ( Y1 ) & 0xFF ] ) ^ - ( FSb[ ( Y2 >> 8 ) & 0xFF ] << 8 ) ^ - ( FSb[ ( Y3 >> 16 ) & 0xFF ] << 16 ) ^ - ( FSb[ ( Y0 >> 24 ) & 0xFF ] << 24 ); - - X2 = *RK++ ^ ( FSb[ ( Y2 ) & 0xFF ] ) ^ - ( FSb[ ( Y3 >> 8 ) & 0xFF ] << 8 ) ^ - ( FSb[ ( Y0 >> 16 ) & 0xFF ] << 16 ) ^ - ( FSb[ ( Y1 >> 24 ) & 0xFF ] << 24 ); - - X3 = *RK++ ^ ( FSb[ ( Y3 ) & 0xFF ] ) ^ - ( FSb[ ( Y0 >> 8 ) & 0xFF ] << 8 ) ^ - ( FSb[ ( Y1 >> 16 ) & 0xFF ] << 16 ) ^ - ( FSb[ ( Y2 >> 24 ) & 0xFF ] << 24 ); - } - - PUT_ULONG_LE( X0, output, 0 ); - PUT_ULONG_LE( X1, output, 4 ); - PUT_ULONG_LE( X2, output, 8 ); - PUT_ULONG_LE( X3, output, 12 ); -} - -/* - * AES-CBC buffer encryption/decryption - */ -void aes_crypt_cbc( aes_context *ctx, - int mode, - int length, - unsigned char iv[16], - const unsigned char *input, - unsigned char *output ) -{ - int i; - unsigned char temp[16]; - -#if defined(XYSSL_PADLOCK_C) && defined(XYSSL_HAVE_X86) - if( padlock_supports( PADLOCK_ACE ) ) - { - if( padlock_xcryptcbc( ctx, mode, length, iv, input, output ) == 0 ) - return; - } -#endif - - if( mode == AES_DECRYPT ) - { - while( length > 0 ) - { - memcpy( temp, input, 16 ); - aes_crypt_ecb( ctx, mode, input, output ); - - for( i = 0; i < 16; i++ ) - output[i] = (unsigned char)( output[i] ^ iv[i] ); - - memcpy( iv, temp, 16 ); - - input += 16; - output += 16; - length -= 16; - } - } - else - { - while( length > 0 ) - { - for( i = 0; i < 16; i++ ) - output[i] = (unsigned char)( input[i] ^ iv[i] ); - - aes_crypt_ecb( ctx, mode, output, output ); - memcpy( iv, output, 16 ); - - input += 16; - output += 16; - length -= 16; - } - } -} - -/* - * AES-CFB buffer encryption/decryption - */ -void aes_crypt_cfb( aes_context *ctx, - int mode, - int length, - int *iv_off, - unsigned char iv[16], - const unsigned char *input, - unsigned char *output ) -{ - int c, n = *iv_off; - - if( mode == AES_DECRYPT ) - { - while( length-- ) - { - if( n == 0 ) - aes_crypt_ecb( ctx, AES_ENCRYPT, iv, iv ); - - c = *input++; - *output++ = (unsigned char)( c ^ iv[n] ); - iv[n] = (unsigned char) c; - - n = (n + 1) & 0x0F; - } - } - else - { - while( length-- ) - { - if( n == 0 ) - aes_crypt_ecb( ctx, AES_ENCRYPT, iv, iv ); - - iv[n] = *output++ = (unsigned char)( iv[n] ^ *input++ ); - - n = (n + 1) & 0x0F; - } - } - - *iv_off = n; -} diff --git a/fitz/crypt_arc4.c b/fitz/crypt_arc4.c deleted file mode 100644 index 9c54fbae..00000000 --- a/fitz/crypt_arc4.c +++ /dev/null @@ -1,98 +0,0 @@ -/* This code illustrates a sample implementation - * of the Arcfour algorithm - * Copyright (c) April 29, 1997 Kalle Kaukonen. - * All Rights Reserved. - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that this copyright - * notice and disclaimer are retained. - * - * THIS SOFTWARE IS PROVIDED BY KALLE KAUKONEN AND CONTRIBUTORS ``AS - * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KALLE - * KAUKONEN OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "mupdf/fitz.h" - -void -fz_arc4_init(fz_arc4 *arc4, const unsigned char *key, unsigned keylen) -{ - unsigned int t, u; - unsigned int keyindex; - unsigned int stateindex; - unsigned char *state; - unsigned int counter; - - state = arc4->state; - - arc4->x = 0; - arc4->y = 0; - - for (counter = 0; counter < 256; counter++) - { - state[counter] = counter; - } - - keyindex = 0; - stateindex = 0; - - for (counter = 0; counter < 256; counter++) - { - t = state[counter]; - stateindex = (stateindex + key[keyindex] + t) & 0xff; - u = state[stateindex]; - - state[stateindex] = t; - state[counter] = u; - - if (++keyindex >= keylen) - { - keyindex = 0; - } - } -} - -static unsigned char -fz_arc4_next(fz_arc4 *arc4) -{ - unsigned int x; - unsigned int y; - unsigned int sx, sy; - unsigned char *state; - - state = arc4->state; - - x = (arc4->x + 1) & 0xff; - sx = state[x]; - y = (sx + arc4->y) & 0xff; - sy = state[y]; - - arc4->x = x; - arc4->y = y; - - state[y] = sx; - state[x] = sy; - - return state[(sx + sy) & 0xff]; -} - -void -fz_arc4_encrypt(fz_arc4 *arc4, unsigned char *dest, const unsigned char *src, unsigned len) -{ - unsigned int i; - for (i = 0; i < len; i++) - { - unsigned char x; - x = fz_arc4_next(arc4); - dest[i] = src[i] ^ x; - } -} diff --git a/fitz/crypt_md5.c b/fitz/crypt_md5.c deleted file mode 100644 index 7490c0bc..00000000 --- a/fitz/crypt_md5.c +++ /dev/null @@ -1,272 +0,0 @@ -/* -MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm - -Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. -All rights reserved. - -License to copy and use this software is granted provided that it -is identified as the "RSA Data Security, Inc. MD5 Message-Digest -Algorithm" in all material mentioning or referencing this software -or this function. - -License is also granted to make and use derivative works provided -that such works are identified as "derived from the RSA Data -Security, Inc. MD5 Message-Digest Algorithm" in all material -mentioning or referencing the derived work. - -RSA Data Security, Inc. makes no representations concerning either -the merchantability of this software or the suitability of this -software for any particular purpose. It is provided "as is" -without express or implied warranty of any kind. - -These notices must be retained in any copies of any part of this -documentation and/or software. -*/ - -#include "mupdf/fitz.h" - -/* Constants for MD5Transform routine */ -enum -{ - S11 = 7, S12 = 12, S13 = 17, S14 = 22, - S21 = 5, S22 = 9, S23 = 14, S24 = 20, - S31 = 4, S32 = 11, S33 = 16, S34 = 23, - S41 = 6, S42 = 10, S43 = 15, S44 = 21 -}; - -static void encode(unsigned char *, const unsigned int *, const unsigned); -static void decode(unsigned int *, const unsigned char *, const unsigned); -static void transform(unsigned int state[4], const unsigned char block[64]); - -static unsigned char padding[64] = -{ - 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 -}; - -/* F, G, H and I are basic MD5 functions */ -#define F(x, y, z) (((x) & (y)) | ((~x) & (z))) -#define G(x, y, z) (((x) & (z)) | ((y) & (~z))) -#define H(x, y, z) ((x) ^ (y) ^ (z)) -#define I(x, y, z) ((y) ^ ((x) | (~z))) - -/* ROTATE rotates x left n bits */ -#define ROTATE(x, n) (((x) << (n)) | ((x) >> (32-(n)))) - -/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. - * Rotation is separate from addition to prevent recomputation. - */ -#define FF(a, b, c, d, x, s, ac) { \ - (a) += F ((b), (c), (d)) + (x) + (unsigned int)(ac); \ - (a) = ROTATE ((a), (s)); \ - (a) += (b); \ - } -#define GG(a, b, c, d, x, s, ac) { \ - (a) += G ((b), (c), (d)) + (x) + (unsigned int)(ac); \ - (a) = ROTATE ((a), (s)); \ - (a) += (b); \ - } -#define HH(a, b, c, d, x, s, ac) { \ - (a) += H ((b), (c), (d)) + (x) + (unsigned int)(ac); \ - (a) = ROTATE ((a), (s)); \ - (a) += (b); \ - } -#define II(a, b, c, d, x, s, ac) { \ - (a) += I ((b), (c), (d)) + (x) + (unsigned int)(ac); \ - (a) = ROTATE ((a), (s)); \ - (a) += (b); \ - } - -static void encode(unsigned char *output, const unsigned int *input, const unsigned len) -{ - unsigned i, j; - - for (i = 0, j = 0; j < len; i++, j += 4) - { - output[j] = (unsigned char)(input[i] & 0xff); - output[j+1] = (unsigned char)((input[i] >> 8) & 0xff); - output[j+2] = (unsigned char)((input[i] >> 16) & 0xff); - output[j+3] = (unsigned char)((input[i] >> 24) & 0xff); - } -} - -static void decode(unsigned int *output, const unsigned char *input, const unsigned len) -{ - unsigned i, j; - - for (i = 0, j = 0; j < len; i++, j += 4) - { - output[i] = ((unsigned int)input[j]) | - (((unsigned int)input[j+1]) << 8) | - (((unsigned int)input[j+2]) << 16) | - (((unsigned int)input[j+3]) << 24); - } -} - -static void transform(unsigned int state[4], const unsigned char block[64]) -{ - unsigned int a = state[0]; - unsigned int b = state[1]; - unsigned int c = state[2]; - unsigned int d = state[3]; - unsigned int x[16]; - - decode(x, block, 64); - - /* Round 1 */ - FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */ - FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */ - FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */ - FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */ - FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */ - FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */ - FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */ - FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */ - FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */ - FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */ - FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */ - FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */ - FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */ - FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */ - FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */ - FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */ - - /* Round 2 */ - GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */ - GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */ - GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */ - GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */ - GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */ - GG (d, a, b, c, x[10], S22, 0x02441453); /* 22 */ - GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */ - GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */ - GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */ - GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */ - GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */ - GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */ - GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */ - GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */ - GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */ - GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */ - - /* Round 3 */ - HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */ - HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */ - HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */ - HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */ - HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */ - HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */ - HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */ - HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */ - HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */ - HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */ - HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */ - HH (b, c, d, a, x[ 6], S34, 0x04881d05); /* 44 */ - HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */ - HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */ - HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */ - HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */ - - /* Round 4 */ - II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */ - II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */ - II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */ - II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */ - II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */ - II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */ - II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */ - II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */ - II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */ - II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */ - II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */ - II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */ - II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */ - II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */ - II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */ - II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */ - - state[0] += a; - state[1] += b; - state[2] += c; - state[3] += d; - - /* Zeroize sensitive information */ - memset(x, 0, sizeof (x)); -} - -/* MD5 initialization. Begins an MD5 operation, writing a new context. */ -void fz_md5_init(fz_md5 *context) -{ - context->count[0] = context->count[1] = 0; - - /* Load magic initialization constants */ - context->state[0] = 0x67452301; - context->state[1] = 0xefcdab89; - context->state[2] = 0x98badcfe; - context->state[3] = 0x10325476; -} - -/* MD5 block update operation. Continues an MD5 message-digest operation, - * processing another message block, and updating the context. - */ -void fz_md5_update(fz_md5 *context, const unsigned char *input, unsigned inlen) -{ - unsigned i, index, partlen; - - /* Compute number of bytes mod 64 */ - index = (unsigned)((context->count[0] >> 3) & 0x3F); - - /* Update number of bits */ - context->count[0] += (unsigned int) inlen << 3; - if (context->count[0] < (unsigned int) inlen << 3) - context->count[1] ++; - context->count[1] += (unsigned int) inlen >> 29; - - partlen = 64 - index; - - /* Transform as many times as possible. */ - if (inlen >= partlen) - { - memcpy(context->buffer + index, input, partlen); - transform(context->state, context->buffer); - - for (i = partlen; i + 63 < inlen; i += 64) - transform(context->state, input + i); - - index = 0; - } - else - { - i = 0; - } - - /* Buffer remaining input */ - memcpy(context->buffer + index, input + i, inlen - i); -} - -/* MD5 finalization. Ends an MD5 message-digest operation, writing the - * the message digest and zeroizing the context. - */ -void fz_md5_final(fz_md5 *context, unsigned char digest[16]) -{ - unsigned char bits[8]; - unsigned index, padlen; - - /* Save number of bits */ - encode(bits, context->count, 8); - - /* Pad out to 56 mod 64 */ - index = (unsigned)((context->count[0] >> 3) & 0x3f); - padlen = index < 56 ? 56 - index : 120 - index; - fz_md5_update(context, padding, padlen); - - /* Append length (before padding) */ - fz_md5_update(context, bits, 8); - - /* Store state in digest */ - encode(digest, context->state, 16); - - /* Zeroize sensitive information */ - memset(context, 0, sizeof(fz_md5)); -} diff --git a/fitz/crypt_pkcs7.c b/fitz/crypt_pkcs7.c deleted file mode 100644 index 1bc50b6e..00000000 --- a/fitz/crypt_pkcs7.c +++ /dev/null @@ -1,400 +0,0 @@ -#include "mupdf/pdf.h" // TODO: move this file to pdf module - -#ifdef HAVE_OPENSSL - -#include "openssl/err.h" -#include "openssl/bio.h" -#include "openssl/asn1.h" -#include "openssl/x509.h" -#include "openssl/err.h" -#include "openssl/objects.h" -#include "openssl/pem.h" -#include "openssl/pkcs7.h" - -enum -{ - SEG_START = 0, - SEG_SIZE = 1 -}; - -typedef struct bsegs_struct -{ - int (*seg)[2]; - int nsegs; - int current_seg; - int seg_pos; -} BIO_SEGS_CTX; - -static int bsegs_read(BIO *b, char *buf, int size) -{ - BIO_SEGS_CTX *ctx = (BIO_SEGS_CTX *)b->ptr; - int read = 0; - - while (size > 0 && ctx->current_seg < ctx->nsegs) - { - int nb = ctx->seg[ctx->current_seg][SEG_SIZE] - ctx->seg_pos; - - if (nb > size) - nb = size; - - if (nb > 0) - { - if (ctx->seg_pos == 0) - (void)BIO_seek(b->next_bio, ctx->seg[ctx->current_seg][SEG_START]); - - (void)BIO_read(b->next_bio, buf, nb); - ctx->seg_pos += nb; - read += nb; - buf += nb; - size -= nb; - } - else - { - ctx->current_seg++; - - if (ctx->current_seg < ctx->nsegs) - ctx->seg_pos = 0; - } - } - - return read; -} - -static long bsegs_ctrl(BIO *b, int cmd, long arg1, void *arg2) -{ - return BIO_ctrl(b->next_bio, cmd, arg1, arg2); -} - -static int bsegs_new(BIO *b) -{ - BIO_SEGS_CTX *ctx; - - ctx = (BIO_SEGS_CTX *)malloc(sizeof(BIO_SEGS_CTX)); - if (ctx == NULL) - return 0; - - ctx->current_seg = 0; - ctx->seg_pos = 0; - ctx->seg = NULL; - ctx->nsegs = 0; - - b->init = 1; - b->ptr = (char *)ctx; - b->flags = 0; - b->num = 0; - - return 1; -} - -static int bsegs_free(BIO *b) -{ - if (b == NULL) - return 0; - - free(b->ptr); - b->ptr = NULL; - b->init = 0; - b->flags = 0; - - return 1; -} - -static long bsegs_callback_ctrl(BIO *b, int cmd, bio_info_cb *fp) -{ - return BIO_callback_ctrl(b->next_bio, cmd, fp); -} - -static BIO_METHOD methods_bsegs = -{ - 0,"segment reader", - NULL, - bsegs_read, - NULL, - NULL, - bsegs_ctrl, - bsegs_new, - bsegs_free, - bsegs_callback_ctrl, -}; - -static BIO_METHOD *BIO_f_segments(void) -{ - return &methods_bsegs; -} - -static void BIO_set_segments(BIO *b, int (*seg)[2], int nsegs) -{ - BIO_SEGS_CTX *ctx = (BIO_SEGS_CTX *)b->ptr; - - ctx->seg = seg; - ctx->nsegs = nsegs; -} - -typedef struct verify_context_s -{ - X509_STORE_CTX x509_ctx; - char certdesc[256]; - int err; -} verify_context; - -static int verify_callback(int ok, X509_STORE_CTX *ctx) -{ - verify_context *vctx; - X509 *err_cert; - int err, depth; - - vctx = (verify_context *)ctx; - - err_cert = X509_STORE_CTX_get_current_cert(ctx); - err = X509_STORE_CTX_get_error(ctx); - depth = X509_STORE_CTX_get_error_depth(ctx); - - X509_NAME_oneline(X509_get_subject_name(err_cert), vctx->certdesc, sizeof(vctx->certdesc)); - - if (!ok && depth >= 6) - { - X509_STORE_CTX_set_error(ctx, X509_V_ERR_CERT_CHAIN_TOO_LONG); - } - - switch (ctx->error) - { - case X509_V_ERR_INVALID_PURPOSE: - case X509_V_ERR_CERT_HAS_EXPIRED: - case X509_V_ERR_KEYUSAGE_NO_CERTSIGN: - err = X509_V_OK; - X509_STORE_CTX_set_error(ctx, X509_V_OK); - ok = 1; - break; - - case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: - /* - In this case, don't reset err to X509_V_OK, so that it can be reported, - although we do return 1, so that the digest will still be checked - */ - ok = 1; - break; - - default: - break; - } - - if (ok && vctx->err == X509_V_OK) - vctx->err = err; - return ok; -} - -static int pk7_verify(X509_STORE *cert_store, PKCS7 *p7, BIO *detached, char *ebuf, int ebufsize) -{ - PKCS7_SIGNER_INFO *si; - verify_context vctx; - BIO *p7bio=NULL; - char readbuf[1024*4]; - int res = 1; - int i; - STACK_OF(PKCS7_SIGNER_INFO) *sk; - - vctx.err = X509_V_OK; - ebuf[0] = 0; - - OpenSSL_add_all_algorithms(); - - EVP_add_digest(EVP_md5()); - EVP_add_digest(EVP_sha1()); - - ERR_load_crypto_strings(); - - ERR_clear_error(); - - X509_VERIFY_PARAM_set_flags(cert_store->param, X509_V_FLAG_CB_ISSUER_CHECK); - X509_STORE_set_verify_cb_func(cert_store, verify_callback); - - p7bio = PKCS7_dataInit(p7, detached); - - /* We now have to 'read' from p7bio to calculate digests etc. */ - while (BIO_read(p7bio, readbuf, sizeof(readbuf)) > 0) - ; - - /* We can now verify signatures */ - sk = PKCS7_get_signer_info(p7); - if (sk == NULL) - { - /* there are no signatures on this data */ - res = 0; - strncpy(ebuf, "No signatures", sizeof(ebuf)); - goto exit; - } - - for (i=0; inext_bio = bdata; - BIO_set_segments(bsegs, byte_range, byte_range_len); - - /* Find the certificates in the pk7 file */ - bcert = BIO_new_mem_buf(adobe_ca, sizeof(adobe_ca)); - pk7cert = d2i_PKCS7_bio(bcert, NULL); - if (pk7cert == NULL) - goto exit; - - t = OBJ_obj2nid(pk7cert->type); - switch (t) - { - case NID_pkcs7_signed: - certs = pk7cert->d.sign->cert; - break; - - case NID_pkcs7_signedAndEnveloped: - certs = pk7cert->d.sign->cert; - break; - - default: - break; - } - - st = X509_STORE_new(); - if (st == NULL) - goto exit; - - /* Add the certificates to the store */ - if (certs != NULL) - { - int i, n = sk_X509_num(certs); - - for (i = 0; i < n; i++) - { - X509 *c = sk_X509_value(certs, i); - X509_STORE_add_cert(st, c); - } - } - - res = pk7_verify(st, pk7sig, bsegs, ebuf, ebufsize); - -exit: - BIO_free(bsig); - BIO_free(bdata); - BIO_free(bsegs); - BIO_free(bcert); - PKCS7_free(pk7sig); - PKCS7_free(pk7cert); - X509_STORE_free(st); - - return res; -} - -int pdf_check_signature(fz_context *ctx, pdf_document *doc, pdf_widget *widget, char *file, char *ebuf, int ebufsize) -{ - int (*byte_range)[2] = NULL; - int byte_range_len; - char *contents = NULL; - int contents_len; - int res = 0; - - fz_var(byte_range); - fz_var(res); - fz_try(ctx); - { - byte_range_len = pdf_signature_widget_byte_range(doc, widget, NULL); - if (byte_range_len) - { - byte_range = fz_calloc(ctx, byte_range_len, sizeof(*byte_range)); - pdf_signature_widget_byte_range(doc, widget, byte_range); - } - - contents_len = pdf_signature_widget_contents(doc, widget, &contents); - if (byte_range && contents) - { - res = verify_sig(contents, contents_len, file, byte_range, byte_range_len, ebuf, ebufsize); - } - else - { - res = 0; - strncpy(ebuf, "Not signed", ebufsize); - } - - } - fz_always(ctx) - { - fz_free(ctx, byte_range); - } - fz_catch(ctx) - { - res = 0; - strncpy(ebuf, fz_caught_message(ctx), ebufsize); - } - - if (ebufsize > 0) - ebuf[ebufsize-1] = 0; - - return res; -} - -#else /* HAVE_OPENSSL */ - -int pdf_check_signature(fz_context *ctx, pdf_document *doc, pdf_widget *widget, char *file, char *ebuf, int ebufsize) -{ - strncpy(ebuf, "This version of MuPDF was built without signature support", ebufsize); - - return 0; -} - -#endif /* HAVE_OPENSSL */ diff --git a/fitz/crypt_sha2.c b/fitz/crypt_sha2.c deleted file mode 100644 index ffedfc95..00000000 --- a/fitz/crypt_sha2.c +++ /dev/null @@ -1,393 +0,0 @@ -/* -This code is based on the code found from 7-Zip, which has a modified -version of the SHA-256 found from Crypto++ . -The code was modified a little to fit into liblzma and fitz. - -This file has been put into the public domain. -You can do whatever you want with this file. - -SHA-384 and SHA-512 were also taken from Crypto++ and adapted for fitz. -*/ - -#include "mupdf/fitz.h" - -static inline int isbigendian(void) -{ - static const int one = 1; - return *(char*)&one == 0; -} - -static inline unsigned int bswap32(unsigned int num) -{ - if (!isbigendian()) - { - return ( (((num) << 24)) - | (((num) << 8) & 0x00FF0000) - | (((num) >> 8) & 0x0000FF00) - | (((num) >> 24)) ); - } - return num; -} - -static inline uint64_t bswap64(uint64_t num) -{ - if (!isbigendian()) - { - return ( (((num) << 56)) - | (((num) << 40) & 0x00FF000000000000ULL) - | (((num) << 24) & 0x0000FF0000000000ULL) - | (((num) << 8) & 0x000000FF00000000ULL) - | (((num) >> 8) & 0x00000000FF000000ULL) - | (((num) >> 24) & 0x0000000000FF0000ULL) - | (((num) >> 40) & 0x000000000000FF00ULL) - | (((num) >> 56)) ); - } - return num; -} - -/* At least on x86, GCC is able to optimize this to a rotate instruction. */ -#define rotr(num, amount) ((num) >> (amount) | (num) << (8 * sizeof(num) - (amount))) - -#define blk0(i) (W[i] = data[i]) -#define blk2(i) (W[i & 15] += s1(W[(i - 2) & 15]) + W[(i - 7) & 15] \ - + s0(W[(i - 15) & 15])) - -#define Ch(x, y, z) (z ^ (x & (y ^ z))) -#define Maj(x, y, z) ((x & y) | (z & (x | y))) - -#define a(i) T[(0 - i) & 7] -#define b(i) T[(1 - i) & 7] -#define c(i) T[(2 - i) & 7] -#define d(i) T[(3 - i) & 7] -#define e(i) T[(4 - i) & 7] -#define f(i) T[(5 - i) & 7] -#define g(i) T[(6 - i) & 7] -#define h(i) T[(7 - i) & 7] - -#define R(i) \ - h(i) += S1(e(i)) + Ch(e(i), f(i), g(i)) + K[i + j] \ - + (j ? blk2(i) : blk0(i)); \ - d(i) += h(i); \ - h(i) += S0(a(i)) + Maj(a(i), b(i), c(i)) - -/* For SHA256 */ - -#define S0(x) (rotr(x, 2) ^ rotr(x, 13) ^ rotr(x, 22)) -#define S1(x) (rotr(x, 6) ^ rotr(x, 11) ^ rotr(x, 25)) -#define s0(x) (rotr(x, 7) ^ rotr(x, 18) ^ (x >> 3)) -#define s1(x) (rotr(x, 17) ^ rotr(x, 19) ^ (x >> 10)) - -static const unsigned int SHA256_K[64] = { - 0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5, - 0x3956C25B, 0x59F111F1, 0x923F82A4, 0xAB1C5ED5, - 0xD807AA98, 0x12835B01, 0x243185BE, 0x550C7DC3, - 0x72BE5D74, 0x80DEB1FE, 0x9BDC06A7, 0xC19BF174, - 0xE49B69C1, 0xEFBE4786, 0x0FC19DC6, 0x240CA1CC, - 0x2DE92C6F, 0x4A7484AA, 0x5CB0A9DC, 0x76F988DA, - 0x983E5152, 0xA831C66D, 0xB00327C8, 0xBF597FC7, - 0xC6E00BF3, 0xD5A79147, 0x06CA6351, 0x14292967, - 0x27B70A85, 0x2E1B2138, 0x4D2C6DFC, 0x53380D13, - 0x650A7354, 0x766A0ABB, 0x81C2C92E, 0x92722C85, - 0xA2BFE8A1, 0xA81A664B, 0xC24B8B70, 0xC76C51A3, - 0xD192E819, 0xD6990624, 0xF40E3585, 0x106AA070, - 0x19A4C116, 0x1E376C08, 0x2748774C, 0x34B0BCB5, - 0x391C0CB3, 0x4ED8AA4A, 0x5B9CCA4F, 0x682E6FF3, - 0x748F82EE, 0x78A5636F, 0x84C87814, 0x8CC70208, - 0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2, -}; - -static void -transform256(unsigned int state[8], const unsigned int data_xe[16]) -{ - const unsigned int *K = SHA256_K; - unsigned int data[16]; - unsigned int W[16]; - unsigned int T[8]; - unsigned int j; - - /* ensure big-endian integers */ - for (j = 0; j < 16; j++) - data[j] = bswap32(data_xe[j]); - - /* Copy state[] to working vars. */ - memcpy(T, state, sizeof(T)); - - /* 64 operations, partially loop unrolled */ - for (j = 0; j < 64; j += 16) { - R( 0); R( 1); R( 2); R( 3); - R( 4); R( 5); R( 6); R( 7); - R( 8); R( 9); R(10); R(11); - R(12); R(13); R(14); R(15); - } - - /* Add the working vars back into state[]. */ - state[0] += a(0); - state[1] += b(0); - state[2] += c(0); - state[3] += d(0); - state[4] += e(0); - state[5] += f(0); - state[6] += g(0); - state[7] += h(0); -} - -#undef S0 -#undef S1 -#undef s0 -#undef s1 - -void fz_sha256_init(fz_sha256 *context) -{ - context->count[0] = context->count[1] = 0; - - context->state[0] = 0x6A09E667; - context->state[1] = 0xBB67AE85; - context->state[2] = 0x3C6EF372; - context->state[3] = 0xA54FF53A; - context->state[4] = 0x510E527F; - context->state[5] = 0x9B05688C; - context->state[6] = 0x1F83D9AB; - context->state[7] = 0x5BE0CD19; -} - -void fz_sha256_update(fz_sha256 *context, const unsigned char *input, unsigned int inlen) -{ - /* Copy the input data into a properly aligned temporary buffer. - * This way we can be called with arbitrarily sized buffers - * (no need to be multiple of 64 bytes), and the code works also - * on architectures that don't allow unaligned memory access. */ - while (inlen > 0) - { - const unsigned int copy_start = context->count[0] & 0x3F; - unsigned int copy_size = 64 - copy_start; - if (copy_size > inlen) - copy_size = inlen; - - memcpy(context->buffer.u8 + copy_start, input, copy_size); - - input += copy_size; - inlen -= copy_size; - context->count[0] += copy_size; - /* carry overflow from low to high */ - if (context->count[0] < copy_size) - context->count[1]++; - - if ((context->count[0] & 0x3F) == 0) - transform256(context->state, context->buffer.u32); - } -} - -void fz_sha256_final(fz_sha256 *context, unsigned char digest[32]) -{ - /* Add padding as described in RFC 3174 (it describes SHA-1 but - * the same padding style is used for SHA-256 too). */ - unsigned int j = context->count[0] & 0x3F; - context->buffer.u8[j++] = 0x80; - - while (j != 56) - { - if (j == 64) - { - transform256(context->state, context->buffer.u32); - j = 0; - } - context->buffer.u8[j++] = 0x00; - } - - /* Convert the message size from bytes to bits. */ - context->count[1] = (context->count[1] << 3) + (context->count[0] >> 29); - context->count[0] = context->count[0] << 3; - - context->buffer.u32[14] = bswap32(context->count[1]); - context->buffer.u32[15] = bswap32(context->count[0]); - transform256(context->state, context->buffer.u32); - - for (j = 0; j < 8; j++) - ((unsigned int *)digest)[j] = bswap32(context->state[j]); - memset(context, 0, sizeof(fz_sha256)); -} - -/* For SHA512 */ - -#define S0(x) (rotr(x, 28) ^ rotr(x, 34) ^ rotr(x, 39)) -#define S1(x) (rotr(x, 14) ^ rotr(x, 18) ^ rotr(x, 41)) -#define s0(x) (rotr(x, 1) ^ rotr(x, 8) ^ (x >> 7)) -#define s1(x) (rotr(x, 19) ^ rotr(x, 61) ^ (x >> 6)) - -static const uint64_t SHA512_K[80] = { - 0x428A2F98D728AE22ULL, 0x7137449123EF65CDULL, - 0xB5C0FBCFEC4D3B2FULL, 0xE9B5DBA58189DBBCULL, - 0x3956C25BF348B538ULL, 0x59F111F1B605D019ULL, - 0x923F82A4AF194F9BULL, 0xAB1C5ED5DA6D8118ULL, - 0xD807AA98A3030242ULL, 0x12835B0145706FBEULL, - 0x243185BE4EE4B28CULL, 0x550C7DC3D5FFB4E2ULL, - 0x72BE5D74F27B896FULL, 0x80DEB1FE3B1696B1ULL, - 0x9BDC06A725C71235ULL, 0xC19BF174CF692694ULL, - 0xE49B69C19EF14AD2ULL, 0xEFBE4786384F25E3ULL, - 0x0FC19DC68B8CD5B5ULL, 0x240CA1CC77AC9C65ULL, - 0x2DE92C6F592B0275ULL, 0x4A7484AA6EA6E483ULL, - 0x5CB0A9DCBD41FBD4ULL, 0x76F988DA831153B5ULL, - 0x983E5152EE66DFABULL, 0xA831C66D2DB43210ULL, - 0xB00327C898FB213FULL, 0xBF597FC7BEEF0EE4ULL, - 0xC6E00BF33DA88FC2ULL, 0xD5A79147930AA725ULL, - 0x06CA6351E003826FULL, 0x142929670A0E6E70ULL, - 0x27B70A8546D22FFCULL, 0x2E1B21385C26C926ULL, - 0x4D2C6DFC5AC42AEDULL, 0x53380D139D95B3DFULL, - 0x650A73548BAF63DEULL, 0x766A0ABB3C77B2A8ULL, - 0x81C2C92E47EDAEE6ULL, 0x92722C851482353BULL, - 0xA2BFE8A14CF10364ULL, 0xA81A664BBC423001ULL, - 0xC24B8B70D0F89791ULL, 0xC76C51A30654BE30ULL, - 0xD192E819D6EF5218ULL, 0xD69906245565A910ULL, - 0xF40E35855771202AULL, 0x106AA07032BBD1B8ULL, - 0x19A4C116B8D2D0C8ULL, 0x1E376C085141AB53ULL, - 0x2748774CDF8EEB99ULL, 0x34B0BCB5E19B48A8ULL, - 0x391C0CB3C5C95A63ULL, 0x4ED8AA4AE3418ACBULL, - 0x5B9CCA4F7763E373ULL, 0x682E6FF3D6B2B8A3ULL, - 0x748F82EE5DEFB2FCULL, 0x78A5636F43172F60ULL, - 0x84C87814A1F0AB72ULL, 0x8CC702081A6439ECULL, - 0x90BEFFFA23631E28ULL, 0xA4506CEBDE82BDE9ULL, - 0xBEF9A3F7B2C67915ULL, 0xC67178F2E372532BULL, - 0xCA273ECEEA26619CULL, 0xD186B8C721C0C207ULL, - 0xEADA7DD6CDE0EB1EULL, 0xF57D4F7FEE6ED178ULL, - 0x06F067AA72176FBAULL, 0x0A637DC5A2C898A6ULL, - 0x113F9804BEF90DAEULL, 0x1B710B35131C471BULL, - 0x28DB77F523047D84ULL, 0x32CAAB7B40C72493ULL, - 0x3C9EBE0A15C9BEBCULL, 0x431D67C49C100D4CULL, - 0x4CC5D4BECB3E42B6ULL, 0x597F299CFC657E2AULL, - 0x5FCB6FAB3AD6FAECULL, 0x6C44198C4A475817ULL, -}; - -static void -transform512(uint64_t state[8], const uint64_t data_xe[16]) -{ - const uint64_t *K = SHA512_K; - uint64_t data[16]; - uint64_t W[16]; - uint64_t T[8]; - unsigned int j; - - /* ensure big-endian integers */ - for (j = 0; j < 16; j++) - data[j] = bswap64(data_xe[j]); - - /* Copy state[] to working vars. */ - memcpy(T, state, sizeof(T)); - - /* 80 operations, partially loop unrolled */ - for (j = 0; j < 80; j+= 16) { - R( 0); R( 1); R( 2); R( 3); - R( 4); R( 5); R( 6); R( 7); - R( 8); R( 9); R(10); R(11); - R(12); R(13); R(14); R(15); - } - - /* Add the working vars back into state[]. */ - state[0] += a(0); - state[1] += b(0); - state[2] += c(0); - state[3] += d(0); - state[4] += e(0); - state[5] += f(0); - state[6] += g(0); - state[7] += h(0); -} - -#undef S0 -#undef S1 -#undef s0 -#undef s1 - -void fz_sha512_init(fz_sha512 *context) -{ - context->count[0] = context->count[1] = 0; - - context->state[0] = 0x6A09E667F3BCC908ull; - context->state[1] = 0xBB67AE8584CAA73Bull; - context->state[2] = 0x3C6EF372FE94F82Bull; - context->state[3] = 0xA54FF53A5F1D36F1ull; - context->state[4] = 0x510E527FADE682D1ull; - context->state[5] = 0x9B05688C2B3E6C1Full; - context->state[6] = 0x1F83D9ABFB41BD6Bull; - context->state[7] = 0x5BE0CD19137E2179ull; -} - -void fz_sha512_update(fz_sha512 *context, const unsigned char *input, unsigned int inlen) -{ - /* Copy the input data into a properly aligned temporary buffer. - * This way we can be called with arbitrarily sized buffers - * (no need to be multiple of 128 bytes), and the code works also - * on architectures that don't allow unaligned memory access. */ - while (inlen > 0) - { - const unsigned int copy_start = context->count[0] & 0x7F; - unsigned int copy_size = 128 - copy_start; - if (copy_size > inlen) - copy_size = inlen; - - memcpy(context->buffer.u8 + copy_start, input, copy_size); - - input += copy_size; - inlen -= copy_size; - context->count[0] += copy_size; - /* carry overflow from low to high */ - if (context->count[0] < copy_size) - context->count[1]++; - - if ((context->count[0] & 0x7F) == 0) - transform512(context->state, context->buffer.u64); - } -} - -void fz_sha512_final(fz_sha512 *context, unsigned char digest[64]) -{ - /* Add padding as described in RFC 3174 (it describes SHA-1 but - * the same padding style is used for SHA-512 too). */ - unsigned int j = context->count[0] & 0x7F; - context->buffer.u8[j++] = 0x80; - - while (j != 112) - { - if (j == 128) - { - transform512(context->state, context->buffer.u64); - j = 0; - } - context->buffer.u8[j++] = 0x00; - } - - /* Convert the message size from bytes to bits. */ - context->count[1] = (context->count[1] << 3) + (context->count[0] >> 29); - context->count[0] = context->count[0] << 3; - - context->buffer.u64[14] = bswap64(context->count[1]); - context->buffer.u64[15] = bswap64(context->count[0]); - transform512(context->state, context->buffer.u64); - - for (j = 0; j < 8; j++) - ((uint64_t *)digest)[j] = bswap64(context->state[j]); - memset(context, 0, sizeof(fz_sha512)); -} - -void fz_sha384_init(fz_sha384 *context) -{ - context->count[0] = context->count[1] = 0; - - context->state[0] = 0xCBBB9D5DC1059ED8ull; - context->state[1] = 0x629A292A367CD507ull; - context->state[2] = 0x9159015A3070DD17ull; - context->state[3] = 0x152FECD8F70E5939ull; - context->state[4] = 0x67332667FFC00B31ull; - context->state[5] = 0x8EB44A8768581511ull; - context->state[6] = 0xDB0C2E0D64F98FA7ull; - context->state[7] = 0x47B5481DBEFA4FA4ull; -} - -void fz_sha384_update(fz_sha384 *context, const unsigned char *input, unsigned int inlen) -{ - fz_sha512_update(context, input, inlen); -} - -void fz_sha384_final(fz_sha384 *context, unsigned char digest[64]) -{ - fz_sha512_final(context, digest); -} diff --git a/fitz/dev_bbox.c b/fitz/dev_bbox.c deleted file mode 100644 index 9cb2a27e..00000000 --- a/fitz/dev_bbox.c +++ /dev/null @@ -1,231 +0,0 @@ -#include "mupdf/fitz.h" - -#define STACK_SIZE 96 - -typedef struct fz_bbox_data_s -{ - fz_rect *result; - int top; - fz_rect stack[STACK_SIZE]; - /* mask content and tiles are ignored */ - int ignore; -} fz_bbox_data; - -static void -fz_bbox_add_rect(fz_device *dev, const fz_rect *rect, int clip) -{ - fz_bbox_data *data = dev->user; - fz_rect r = *rect; - - if (0 < data->top && data->top <= STACK_SIZE) - { - fz_intersect_rect(&r, &data->stack[data->top-1]); - } - if (!clip && data->top <= STACK_SIZE && !data->ignore) - { - fz_union_rect(data->result, &r); - } - if (clip && ++data->top <= STACK_SIZE) - { - data->stack[data->top-1] = r; - } -} - -static void -fz_bbox_fill_path(fz_device *dev, fz_path *path, int even_odd, const fz_matrix *ctm, - fz_colorspace *colorspace, float *color, float alpha) -{ - fz_rect r; - fz_bbox_add_rect(dev, fz_bound_path(dev->ctx, path, NULL, ctm, &r), 0); -} - -static void -fz_bbox_stroke_path(fz_device *dev, fz_path *path, fz_stroke_state *stroke, - const fz_matrix *ctm, fz_colorspace *colorspace, float *color, float alpha) -{ - fz_rect r; - fz_bbox_add_rect(dev, fz_bound_path(dev->ctx, path, stroke, ctm, &r), 0); -} - -static void -fz_bbox_fill_text(fz_device *dev, fz_text *text, const fz_matrix *ctm, - fz_colorspace *colorspace, float *color, float alpha) -{ - fz_rect r; - fz_bbox_add_rect(dev, fz_bound_text(dev->ctx, text, NULL, ctm, &r), 0); -} - -static void -fz_bbox_stroke_text(fz_device *dev, fz_text *text, fz_stroke_state *stroke, - const fz_matrix *ctm, fz_colorspace *colorspace, float *color, float alpha) -{ - fz_rect r; - fz_bbox_add_rect(dev, fz_bound_text(dev->ctx, text, stroke, ctm, &r), 0); -} - -static void -fz_bbox_fill_shade(fz_device *dev, fz_shade *shade, const fz_matrix *ctm, float alpha) -{ - fz_rect r; - fz_bbox_add_rect(dev, fz_bound_shade(dev->ctx, shade, ctm, &r), 0); -} - -static void -fz_bbox_fill_image(fz_device *dev, fz_image *image, const fz_matrix *ctm, float alpha) -{ - fz_rect r = fz_unit_rect; - fz_bbox_add_rect(dev, fz_transform_rect(&r, ctm), 0); -} - -static void -fz_bbox_fill_image_mask(fz_device *dev, fz_image *image, const fz_matrix *ctm, - fz_colorspace *colorspace, float *color, float alpha) -{ - fz_rect r = fz_unit_rect; - fz_bbox_add_rect(dev, fz_transform_rect(&r, ctm), 0); -} - -static void -fz_bbox_clip_path(fz_device *dev, fz_path *path, const fz_rect *rect, int even_odd, const fz_matrix *ctm) -{ - fz_rect r; - fz_bbox_add_rect(dev, fz_bound_path(dev->ctx, path, NULL, ctm, &r), 1); -} - -static void -fz_bbox_clip_stroke_path(fz_device *dev, fz_path *path, const fz_rect *rect, fz_stroke_state *stroke, const fz_matrix *ctm) -{ - fz_rect r; - fz_bbox_add_rect(dev, fz_bound_path(dev->ctx, path, stroke, ctm, &r), 1); -} - -static void -fz_bbox_clip_text(fz_device *dev, fz_text *text, const fz_matrix *ctm, int accumulate) -{ - fz_rect r = fz_infinite_rect; - if (accumulate) - fz_bbox_add_rect(dev, &r, accumulate != 2); - else - fz_bbox_add_rect(dev, fz_bound_text(dev->ctx, text, NULL, ctm, &r), 1); -} - -static void -fz_bbox_clip_stroke_text(fz_device *dev, fz_text *text, fz_stroke_state *stroke, const fz_matrix *ctm) -{ - fz_rect r; - fz_bbox_add_rect(dev, fz_bound_text(dev->ctx, text, stroke, ctm, &r), 1); -} - -static void -fz_bbox_clip_image_mask(fz_device *dev, fz_image *image, const fz_rect *rect, const fz_matrix *ctm) -{ - fz_rect r = *rect; - fz_bbox_add_rect(dev, fz_transform_rect(&r, ctm), 1); -} - -static void -fz_bbox_pop_clip(fz_device *dev) -{ - fz_bbox_data *data = dev->user; - if (data->top > 0) - data->top--; - else - fz_warn(dev->ctx, "unexpected pop clip"); -} - -static void -fz_bbox_begin_mask(fz_device *dev, const fz_rect *rect, int luminosity, fz_colorspace *colorspace, float *color) -{ - fz_bbox_data *data = dev->user; - fz_bbox_add_rect(dev, rect, 1); - data->ignore++; -} - -static void -fz_bbox_end_mask(fz_device *dev) -{ - fz_bbox_data *data = dev->user; - assert(data->ignore > 0); - data->ignore--; -} - -static void -fz_bbox_begin_group(fz_device *dev, const fz_rect *rect, int isolated, int knockout, int blendmode, float alpha) -{ - fz_bbox_add_rect(dev, rect, 1); -} - -static void -fz_bbox_end_group(fz_device *dev) -{ - fz_bbox_pop_clip(dev); -} - -static int -fz_bbox_begin_tile(fz_device *dev, const fz_rect *area, const fz_rect *view, float xstep, float ystep, const fz_matrix *ctm, int id) -{ - fz_bbox_data *data = dev->user; - fz_rect r = *area; - fz_bbox_add_rect(dev, fz_transform_rect(&r, ctm), 0); - data->ignore++; - return 0; -} - -static void -fz_bbox_end_tile(fz_device *dev) -{ - fz_bbox_data *data = dev->user; - assert(data->ignore > 0); - data->ignore--; -} - -static void -fz_bbox_free_user(fz_device *dev) -{ - fz_bbox_data *data = dev->user; - if (data->top > 0) - fz_warn(dev->ctx, "items left on stack in bbox device: %d", data->top); - fz_free(dev->ctx, dev->user); -} - -fz_device * -fz_new_bbox_device(fz_context *ctx, fz_rect *result) -{ - fz_device *dev; - - fz_bbox_data *user = fz_malloc_struct(ctx, fz_bbox_data); - user->result = result; - user->top = 0; - user->ignore = 0; - dev = fz_new_device(ctx, user); - dev->free_user = fz_bbox_free_user; - - dev->fill_path = fz_bbox_fill_path; - dev->stroke_path = fz_bbox_stroke_path; - dev->clip_path = fz_bbox_clip_path; - dev->clip_stroke_path = fz_bbox_clip_stroke_path; - - dev->fill_text = fz_bbox_fill_text; - dev->stroke_text = fz_bbox_stroke_text; - dev->clip_text = fz_bbox_clip_text; - dev->clip_stroke_text = fz_bbox_clip_stroke_text; - - dev->fill_shade = fz_bbox_fill_shade; - dev->fill_image = fz_bbox_fill_image; - dev->fill_image_mask = fz_bbox_fill_image_mask; - dev->clip_image_mask = fz_bbox_clip_image_mask; - - dev->pop_clip = fz_bbox_pop_clip; - - dev->begin_mask = fz_bbox_begin_mask; - dev->end_mask = fz_bbox_end_mask; - dev->begin_group = fz_bbox_begin_group; - dev->end_group = fz_bbox_end_group; - - dev->begin_tile = fz_bbox_begin_tile; - dev->end_tile = fz_bbox_end_tile; - - *result = fz_empty_rect; - - return dev; -} diff --git a/fitz/dev_list.c b/fitz/dev_list.c deleted file mode 100644 index 6ffe165f..00000000 --- a/fitz/dev_list.c +++ /dev/null @@ -1,851 +0,0 @@ -#include "mupdf/fitz.h" - -typedef struct fz_display_node_s fz_display_node; - -#define STACK_SIZE 96 - -typedef enum fz_display_command_e -{ - FZ_CMD_BEGIN_PAGE, - FZ_CMD_END_PAGE, - FZ_CMD_FILL_PATH, - FZ_CMD_STROKE_PATH, - FZ_CMD_CLIP_PATH, - FZ_CMD_CLIP_STROKE_PATH, - FZ_CMD_FILL_TEXT, - FZ_CMD_STROKE_TEXT, - FZ_CMD_CLIP_TEXT, - FZ_CMD_CLIP_STROKE_TEXT, - FZ_CMD_IGNORE_TEXT, - FZ_CMD_FILL_SHADE, - FZ_CMD_FILL_IMAGE, - FZ_CMD_FILL_IMAGE_MASK, - FZ_CMD_CLIP_IMAGE_MASK, - FZ_CMD_POP_CLIP, - FZ_CMD_BEGIN_MASK, - FZ_CMD_END_MASK, - FZ_CMD_BEGIN_GROUP, - FZ_CMD_END_GROUP, - FZ_CMD_BEGIN_TILE, - FZ_CMD_END_TILE -} fz_display_command; - -struct fz_display_node_s -{ - fz_display_command cmd; - fz_display_node *next; - fz_rect rect; - union { - fz_path *path; - fz_text *text; - fz_shade *shade; - fz_image *image; - int blendmode; - } item; - fz_stroke_state *stroke; - int flag; /* even_odd, accumulate, isolated/knockout... */ - fz_matrix ctm; - fz_colorspace *colorspace; - float alpha; - float color[FZ_MAX_COLORS]; -}; - -struct fz_display_list_s -{ - fz_storable storable; - fz_display_node *first; - fz_display_node *last; - int len; - - int top; - struct { - fz_rect *update; - fz_rect rect; - } stack[STACK_SIZE]; - int tiled; -}; - -enum { ISOLATED = 1, KNOCKOUT = 2 }; - -static fz_display_node * -fz_new_display_node(fz_context *ctx, fz_display_command cmd, const fz_matrix *ctm, - fz_colorspace *colorspace, float *color, float alpha) -{ - fz_display_node *node; - int i; - - node = fz_malloc_struct(ctx, fz_display_node); - node->cmd = cmd; - node->next = NULL; - node->rect = fz_empty_rect; - node->item.path = NULL; - node->stroke = NULL; - node->flag = (cmd == FZ_CMD_BEGIN_TILE ? fz_gen_id(ctx) : 0); - node->ctm = *ctm; - if (colorspace) - { - node->colorspace = fz_keep_colorspace(ctx, colorspace); - if (color) - { - for (i = 0; i < node->colorspace->n; i++) - node->color[i] = color[i]; - } - } - else - { - node->colorspace = NULL; - } - node->alpha = alpha; - - return node; -} - -static void -fz_append_display_node(fz_display_list *list, fz_display_node *node) -{ - switch (node->cmd) - { - case FZ_CMD_CLIP_PATH: - case FZ_CMD_CLIP_STROKE_PATH: - case FZ_CMD_CLIP_IMAGE_MASK: - if (list->top < STACK_SIZE) - { - list->stack[list->top].update = &node->rect; - list->stack[list->top].rect = fz_empty_rect; - } - list->top++; - break; - case FZ_CMD_END_MASK: - case FZ_CMD_CLIP_TEXT: - case FZ_CMD_CLIP_STROKE_TEXT: - if (list->top < STACK_SIZE) - { - list->stack[list->top].update = NULL; - list->stack[list->top].rect = fz_empty_rect; - } - list->top++; - break; - case FZ_CMD_BEGIN_TILE: - list->tiled++; - if (list->top > 0 && list->top <= STACK_SIZE) - { - list->stack[list->top-1].rect = fz_infinite_rect; - } - break; - case FZ_CMD_END_TILE: - list->tiled--; - break; - case FZ_CMD_END_GROUP: - break; - case FZ_CMD_POP_CLIP: - if (list->top > STACK_SIZE) - { - list->top--; - node->rect = fz_infinite_rect; - } - else if (list->top > 0) - { - fz_rect *update; - list->top--; - update = list->stack[list->top].update; - if (list->tiled == 0) - { - if (update) - { - fz_intersect_rect(update, &list->stack[list->top].rect); - node->rect = *update; - } - else - node->rect = list->stack[list->top].rect; - } - else - node->rect = fz_infinite_rect; - } - /* fallthrough */ - default: - if (list->top > 0 && list->tiled == 0 && list->top <= STACK_SIZE) - fz_union_rect(&list->stack[list->top-1].rect, &node->rect); - break; - } - if (!list->first) - { - list->first = node; - list->last = node; - } - else - { - list->last->next = node; - list->last = node; - } - list->len++; -} - -static void -fz_free_display_node(fz_context *ctx, fz_display_node *node) -{ - switch (node->cmd) - { - case FZ_CMD_FILL_PATH: - case FZ_CMD_STROKE_PATH: - case FZ_CMD_CLIP_PATH: - case FZ_CMD_CLIP_STROKE_PATH: - fz_free_path(ctx, node->item.path); - break; - case FZ_CMD_FILL_TEXT: - case FZ_CMD_STROKE_TEXT: - case FZ_CMD_CLIP_TEXT: - case FZ_CMD_CLIP_STROKE_TEXT: - case FZ_CMD_IGNORE_TEXT: - fz_free_text(ctx, node->item.text); - break; - case FZ_CMD_FILL_SHADE: - fz_drop_shade(ctx, node->item.shade); - break; - case FZ_CMD_FILL_IMAGE: - case FZ_CMD_FILL_IMAGE_MASK: - case FZ_CMD_CLIP_IMAGE_MASK: - fz_drop_image(ctx, node->item.image); - break; - case FZ_CMD_POP_CLIP: - case FZ_CMD_BEGIN_MASK: - case FZ_CMD_END_MASK: - case FZ_CMD_BEGIN_GROUP: - case FZ_CMD_END_GROUP: - case FZ_CMD_BEGIN_TILE: - case FZ_CMD_END_TILE: - case FZ_CMD_BEGIN_PAGE: - case FZ_CMD_END_PAGE: - break; - } - if (node->stroke) - fz_drop_stroke_state(ctx, node->stroke); - if (node->colorspace) - fz_drop_colorspace(ctx, node->colorspace); - fz_free(ctx, node); -} - -static void -fz_list_begin_page(fz_device *dev, const fz_rect *mediabox, const fz_matrix *ctm) -{ - fz_context *ctx = dev->ctx; - fz_display_node *node = fz_new_display_node(ctx, FZ_CMD_BEGIN_PAGE, ctm, NULL, NULL, 0); - node->rect = *mediabox; - fz_transform_rect(&node->rect, ctm); - fz_append_display_node(dev->user, node); -} - -static void -fz_list_end_page(fz_device *dev) -{ - fz_context *ctx = dev->ctx; - fz_display_node *node = fz_new_display_node(ctx, FZ_CMD_END_PAGE, &fz_identity, NULL, NULL, 0); - fz_append_display_node(dev->user, node); -} - -static void -fz_list_fill_path(fz_device *dev, fz_path *path, int even_odd, const fz_matrix *ctm, - fz_colorspace *colorspace, float *color, float alpha) -{ - fz_display_node *node; - fz_context *ctx = dev->ctx; - node = fz_new_display_node(ctx, FZ_CMD_FILL_PATH, ctm, colorspace, color, alpha); - fz_try(ctx) - { - fz_bound_path(dev->ctx, path, NULL, ctm, &node->rect); - node->item.path = fz_clone_path(dev->ctx, path); - node->flag = even_odd; - } - fz_catch(ctx) - { - fz_free_display_node(ctx, node); - fz_rethrow(ctx); - } - fz_append_display_node(dev->user, node); -} - -static void -fz_list_stroke_path(fz_device *dev, fz_path *path, fz_stroke_state *stroke, - const fz_matrix *ctm, fz_colorspace *colorspace, float *color, float alpha) -{ - fz_display_node *node; - fz_context *ctx = dev->ctx; - node = fz_new_display_node(ctx, FZ_CMD_STROKE_PATH, ctm, colorspace, color, alpha); - fz_try(ctx) - { - fz_bound_path(dev->ctx, path, stroke, ctm, &node->rect); - node->item.path = fz_clone_path(dev->ctx, path); - node->stroke = fz_keep_stroke_state(dev->ctx, stroke); - } - fz_catch(ctx) - { - fz_free_display_node(ctx, node); - fz_rethrow(ctx); - } - fz_append_display_node(dev->user, node); -} - -static void -fz_list_clip_path(fz_device *dev, fz_path *path, const fz_rect *rect, int even_odd, const fz_matrix *ctm) -{ - fz_display_node *node; - fz_context *ctx = dev->ctx; - node = fz_new_display_node(ctx, FZ_CMD_CLIP_PATH, ctm, NULL, NULL, 0); - fz_try(ctx) - { - fz_bound_path(dev->ctx, path, NULL, ctm, &node->rect); - if (rect) - fz_intersect_rect(&node->rect, rect); - node->item.path = fz_clone_path(dev->ctx, path); - node->flag = even_odd; - } - fz_catch(ctx) - { - fz_free_display_node(ctx, node); - fz_rethrow(ctx); - } - fz_append_display_node(dev->user, node); -} - -static void -fz_list_clip_stroke_path(fz_device *dev, fz_path *path, const fz_rect *rect, fz_stroke_state *stroke, const fz_matrix *ctm) -{ - fz_display_node *node; - fz_context *ctx = dev->ctx; - node = fz_new_display_node(ctx, FZ_CMD_CLIP_STROKE_PATH, ctm, NULL, NULL, 0); - fz_try(ctx) - { - fz_bound_path(dev->ctx, path, stroke, ctm, &node->rect); - if (rect) - fz_intersect_rect(&node->rect, rect); - node->item.path = fz_clone_path(dev->ctx, path); - node->stroke = fz_keep_stroke_state(dev->ctx, stroke); - } - fz_catch(ctx) - { - fz_free_display_node(ctx, node); - fz_rethrow(ctx); - } - fz_append_display_node(dev->user, node); -} - -static void -fz_list_fill_text(fz_device *dev, fz_text *text, const fz_matrix *ctm, - fz_colorspace *colorspace, float *color, float alpha) -{ - fz_display_node *node; - fz_context *ctx = dev->ctx; - node = fz_new_display_node(ctx, FZ_CMD_FILL_TEXT, ctm, colorspace, color, alpha); - fz_try(ctx) - { - fz_bound_text(dev->ctx, text, NULL, ctm, &node->rect); - node->item.text = fz_clone_text(dev->ctx, text); - } - fz_catch(ctx) - { - fz_free_display_node(ctx, node); - fz_rethrow(ctx); - } - fz_append_display_node(dev->user, node); -} - -static void -fz_list_stroke_text(fz_device *dev, fz_text *text, fz_stroke_state *stroke, const fz_matrix *ctm, - fz_colorspace *colorspace, float *color, float alpha) -{ - fz_display_node *node; - fz_context *ctx = dev->ctx; - node = fz_new_display_node(ctx, FZ_CMD_STROKE_TEXT, ctm, colorspace, color, alpha); - node->item.text = NULL; - fz_try(ctx) - { - fz_bound_text(dev->ctx, text, stroke, ctm, &node->rect); - node->item.text = fz_clone_text(dev->ctx, text); - node->stroke = fz_keep_stroke_state(dev->ctx, stroke); - } - fz_catch(ctx) - { - fz_free_display_node(ctx, node); - fz_rethrow(ctx); - } - fz_append_display_node(dev->user, node); -} - -static void -fz_list_clip_text(fz_device *dev, fz_text *text, const fz_matrix *ctm, int accumulate) -{ - fz_display_node *node; - fz_context *ctx = dev->ctx; - node = fz_new_display_node(ctx, FZ_CMD_CLIP_TEXT, ctm, NULL, NULL, 0); - fz_try(ctx) - { - fz_bound_text(dev->ctx, text, NULL, ctm, &node->rect); - node->item.text = fz_clone_text(dev->ctx, text); - node->flag = accumulate; - /* when accumulating, be conservative about culling */ - if (accumulate) - node->rect = fz_infinite_rect; - } - fz_catch(ctx) - { - fz_free_display_node(ctx, node); - fz_rethrow(ctx); - } - fz_append_display_node(dev->user, node); -} - -static void -fz_list_clip_stroke_text(fz_device *dev, fz_text *text, fz_stroke_state *stroke, const fz_matrix *ctm) -{ - fz_display_node *node; - fz_context *ctx = dev->ctx; - node = fz_new_display_node(ctx, FZ_CMD_CLIP_STROKE_TEXT, ctm, NULL, NULL, 0); - fz_try(ctx) - { - fz_bound_text(dev->ctx, text, stroke, ctm, &node->rect); - node->item.text = fz_clone_text(dev->ctx, text); - node->stroke = fz_keep_stroke_state(dev->ctx, stroke); - } - fz_catch(ctx) - { - fz_free_display_node(ctx, node); - fz_rethrow(ctx); - } - fz_append_display_node(dev->user, node); -} - -static void -fz_list_ignore_text(fz_device *dev, fz_text *text, const fz_matrix *ctm) -{ - fz_display_node *node; - fz_context *ctx = dev->ctx; - node = fz_new_display_node(ctx, FZ_CMD_IGNORE_TEXT, ctm, NULL, NULL, 0); - fz_try(ctx) - { - fz_bound_text(dev->ctx, text, NULL, ctm, &node->rect); - node->item.text = fz_clone_text(dev->ctx, text); - } - fz_catch(ctx) - { - fz_free_display_node(ctx, node); - fz_rethrow(ctx); - } - fz_append_display_node(dev->user, node); -} - -static void -fz_list_pop_clip(fz_device *dev) -{ - fz_display_node *node; - node = fz_new_display_node(dev->ctx, FZ_CMD_POP_CLIP, &fz_identity, NULL, NULL, 0); - fz_append_display_node(dev->user, node); -} - -static void -fz_list_fill_shade(fz_device *dev, fz_shade *shade, const fz_matrix *ctm, float alpha) -{ - fz_display_node *node; - fz_context *ctx = dev->ctx; - node = fz_new_display_node(ctx, FZ_CMD_FILL_SHADE, ctm, NULL, NULL, alpha); - fz_bound_shade(ctx, shade, ctm, &node->rect); - node->item.shade = fz_keep_shade(ctx, shade); - fz_append_display_node(dev->user, node); -} - -static void -fz_list_fill_image(fz_device *dev, fz_image *image, const 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_unit_rect; - fz_transform_rect(&node->rect, ctm); - 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_image *image, const 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_unit_rect; - fz_transform_rect(&node->rect, ctm); - 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_image *image, const fz_rect *rect, const 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_unit_rect; - fz_transform_rect(&node->rect, ctm); - if (rect) - fz_intersect_rect(&node->rect, rect); - node->item.image = fz_keep_image(dev->ctx, image); - fz_append_display_node(dev->user, node); -} - -static void -fz_list_begin_mask(fz_device *dev, const fz_rect *rect, int luminosity, fz_colorspace *colorspace, float *color) -{ - fz_display_node *node; - node = fz_new_display_node(dev->ctx, FZ_CMD_BEGIN_MASK, &fz_identity, colorspace, color, 0); - node->rect = *rect; - node->flag = luminosity; - fz_append_display_node(dev->user, node); -} - -static void -fz_list_end_mask(fz_device *dev) -{ - fz_display_node *node; - node = fz_new_display_node(dev->ctx, FZ_CMD_END_MASK, &fz_identity, NULL, NULL, 0); - fz_append_display_node(dev->user, node); -} - -static void -fz_list_begin_group(fz_device *dev, const fz_rect *rect, int isolated, int knockout, int blendmode, float alpha) -{ - fz_display_node *node; - node = fz_new_display_node(dev->ctx, FZ_CMD_BEGIN_GROUP, &fz_identity, NULL, NULL, alpha); - node->rect = *rect; - node->item.blendmode = blendmode; - node->flag |= isolated ? ISOLATED : 0; - node->flag |= knockout ? KNOCKOUT : 0; - fz_append_display_node(dev->user, node); -} - -static void -fz_list_end_group(fz_device *dev) -{ - fz_display_node *node; - node = fz_new_display_node(dev->ctx, FZ_CMD_END_GROUP, &fz_identity, NULL, NULL, 0); - fz_append_display_node(dev->user, node); -} - -static int -fz_list_begin_tile(fz_device *dev, const fz_rect *area, const fz_rect *view, float xstep, float ystep, const fz_matrix *ctm, int id) -{ - /* We ignore id here, as we will pass on our own id */ - fz_display_node *node; - node = fz_new_display_node(dev->ctx, FZ_CMD_BEGIN_TILE, ctm, NULL, NULL, 0); - node->rect = *area; - node->color[0] = xstep; - node->color[1] = ystep; - node->color[2] = view->x0; - node->color[3] = view->y0; - node->color[4] = view->x1; - node->color[5] = view->y1; - fz_append_display_node(dev->user, node); - return 0; -} - -static void -fz_list_end_tile(fz_device *dev) -{ - fz_display_node *node; - node = fz_new_display_node(dev->ctx, FZ_CMD_END_TILE, &fz_identity, NULL, NULL, 0); - fz_append_display_node(dev->user, node); -} - -fz_device * -fz_new_list_device(fz_context *ctx, fz_display_list *list) -{ - fz_device *dev = fz_new_device(ctx, list); - - dev->begin_page = fz_list_begin_page; - dev->end_page = fz_list_end_page; - - dev->fill_path = fz_list_fill_path; - dev->stroke_path = fz_list_stroke_path; - dev->clip_path = fz_list_clip_path; - dev->clip_stroke_path = fz_list_clip_stroke_path; - - dev->fill_text = fz_list_fill_text; - dev->stroke_text = fz_list_stroke_text; - dev->clip_text = fz_list_clip_text; - dev->clip_stroke_text = fz_list_clip_stroke_text; - dev->ignore_text = fz_list_ignore_text; - - dev->fill_shade = fz_list_fill_shade; - dev->fill_image = fz_list_fill_image; - dev->fill_image_mask = fz_list_fill_image_mask; - dev->clip_image_mask = fz_list_clip_image_mask; - - dev->pop_clip = fz_list_pop_clip; - - dev->begin_mask = fz_list_begin_mask; - dev->end_mask = fz_list_end_mask; - dev->begin_group = fz_list_begin_group; - dev->end_group = fz_list_end_group; - - dev->begin_tile = fz_list_begin_tile; - dev->end_tile = fz_list_end_tile; - - return dev; -} - -static void -fz_free_display_list(fz_context *ctx, fz_storable *list_) -{ - fz_display_list *list = (fz_display_list *)list_; - fz_display_node *node; - - if (list == NULL) - return; - node = list->first; - while (node) - { - fz_display_node *next = node->next; - fz_free_display_node(ctx, node); - node = next; - } - fz_free(ctx, list); -} - -fz_display_list * -fz_new_display_list(fz_context *ctx) -{ - fz_display_list *list = fz_malloc_struct(ctx, fz_display_list); - FZ_INIT_STORABLE(list, 1, fz_free_display_list); - list->first = NULL; - list->last = NULL; - list->len = 0; - list->top = 0; - list->tiled = 0; - return list; -} - -fz_display_list * -fz_keep_display_list(fz_context *ctx, fz_display_list *list) -{ - return (fz_display_list *)fz_keep_storable(ctx, &list->storable); -} - -void -fz_drop_display_list(fz_context *ctx, fz_display_list *list) -{ - fz_drop_storable(ctx, &list->storable); -} - -static fz_display_node * -skip_to_end_tile(fz_display_node *node, int *progress) -{ - fz_display_node *next; - int depth = 1; - - /* Skip through until we find the matching end_tile. Note that - * (somewhat nastily) we return the PREVIOUS node to this to help - * the calling routine. */ - do - { - next = node->next; - if (next == NULL) - break; - if (next->cmd == FZ_CMD_BEGIN_TILE) - depth++; - else if (next->cmd == FZ_CMD_END_TILE) - { - depth--; - if (depth == 0) - return node; - } - (*progress)++; - node = next; - } - while (1); - - return NULL; -} - -void -fz_run_display_list(fz_display_list *list, fz_device *dev, const fz_matrix *top_ctm, const fz_rect *scissor, fz_cookie *cookie) -{ - fz_display_node *node; - fz_matrix ctm; - int clipped = 0; - int tiled = 0; - int progress = 0; - fz_context *ctx = dev->ctx; - - if (!scissor) - scissor = &fz_infinite_rect; - - if (cookie) - { - cookie->progress_max = list->len; - cookie->progress = 0; - } - - for (node = list->first; node; node = node->next) - { - int empty; - - fz_rect node_rect = node->rect; - fz_transform_rect(&node_rect, top_ctm); - - /* Check the cookie for aborting */ - if (cookie) - { - if (cookie->abort) - break; - cookie->progress = progress++; - } - - /* cull objects to draw using a quick visibility test */ - - if (tiled || - node->cmd == FZ_CMD_BEGIN_TILE || node->cmd == FZ_CMD_END_TILE || - node->cmd == FZ_CMD_BEGIN_PAGE || node->cmd == FZ_CMD_END_PAGE) - { - empty = 0; - } - else - { - fz_rect rect = node_rect; - fz_intersect_rect(&rect, scissor); - empty = fz_is_empty_rect(&rect); - } - - if (clipped || empty) - { - switch (node->cmd) - { - case FZ_CMD_CLIP_PATH: - case FZ_CMD_CLIP_STROKE_PATH: - case FZ_CMD_CLIP_STROKE_TEXT: - case FZ_CMD_CLIP_IMAGE_MASK: - case FZ_CMD_BEGIN_MASK: - case FZ_CMD_BEGIN_GROUP: - clipped++; - continue; - case FZ_CMD_CLIP_TEXT: - /* Accumulated text has no extra pops */ - if (node->flag != 2) - clipped++; - continue; - case FZ_CMD_POP_CLIP: - case FZ_CMD_END_GROUP: - if (!clipped) - goto visible; - clipped--; - continue; - case FZ_CMD_END_MASK: - if (!clipped) - goto visible; - continue; - default: - continue; - } - } - -visible: - fz_concat(&ctm, &node->ctm, top_ctm); - - - fz_try(ctx) - { - switch (node->cmd) - { - case FZ_CMD_BEGIN_PAGE: - fz_begin_page(dev, &node_rect, &ctm); - break; - case FZ_CMD_END_PAGE: - fz_end_page(dev); - break; - case FZ_CMD_FILL_PATH: - fz_fill_path(dev, node->item.path, node->flag, &ctm, - node->colorspace, node->color, node->alpha); - break; - case FZ_CMD_STROKE_PATH: - fz_stroke_path(dev, node->item.path, node->stroke, &ctm, - node->colorspace, node->color, node->alpha); - break; - case FZ_CMD_CLIP_PATH: - fz_clip_path(dev, node->item.path, &node_rect, node->flag, &ctm); - break; - case FZ_CMD_CLIP_STROKE_PATH: - fz_clip_stroke_path(dev, node->item.path, &node_rect, node->stroke, &ctm); - break; - case FZ_CMD_FILL_TEXT: - fz_fill_text(dev, node->item.text, &ctm, - node->colorspace, node->color, node->alpha); - break; - case FZ_CMD_STROKE_TEXT: - fz_stroke_text(dev, node->item.text, node->stroke, &ctm, - node->colorspace, node->color, node->alpha); - break; - case FZ_CMD_CLIP_TEXT: - fz_clip_text(dev, node->item.text, &ctm, node->flag); - break; - case FZ_CMD_CLIP_STROKE_TEXT: - fz_clip_stroke_text(dev, node->item.text, node->stroke, &ctm); - break; - case FZ_CMD_IGNORE_TEXT: - fz_ignore_text(dev, node->item.text, &ctm); - break; - case FZ_CMD_FILL_SHADE: - if ((dev->hints & FZ_IGNORE_SHADE) == 0) - fz_fill_shade(dev, node->item.shade, &ctm, node->alpha); - break; - case FZ_CMD_FILL_IMAGE: - if ((dev->hints & FZ_IGNORE_IMAGE) == 0) - fz_fill_image(dev, node->item.image, &ctm, node->alpha); - break; - case FZ_CMD_FILL_IMAGE_MASK: - if ((dev->hints & FZ_IGNORE_IMAGE) == 0) - fz_fill_image_mask(dev, node->item.image, &ctm, - node->colorspace, node->color, node->alpha); - break; - case FZ_CMD_CLIP_IMAGE_MASK: - if ((dev->hints & FZ_IGNORE_IMAGE) == 0) - fz_clip_image_mask(dev, node->item.image, &node_rect, &ctm); - break; - case FZ_CMD_POP_CLIP: - fz_pop_clip(dev); - break; - case FZ_CMD_BEGIN_MASK: - fz_begin_mask(dev, &node_rect, node->flag, node->colorspace, node->color); - break; - case FZ_CMD_END_MASK: - fz_end_mask(dev); - break; - case FZ_CMD_BEGIN_GROUP: - fz_begin_group(dev, &node_rect, - (node->flag & ISOLATED) != 0, (node->flag & KNOCKOUT) != 0, - node->item.blendmode, node->alpha); - break; - case FZ_CMD_END_GROUP: - fz_end_group(dev); - break; - case FZ_CMD_BEGIN_TILE: - { - int cached; - fz_rect tile_rect; - tiled++; - tile_rect.x0 = node->color[2]; - tile_rect.y0 = node->color[3]; - tile_rect.x1 = node->color[4]; - tile_rect.y1 = node->color[5]; - cached = fz_begin_tile_id(dev, &node->rect, &tile_rect, node->color[0], node->color[1], &ctm, node->flag); - if (cached) - node = skip_to_end_tile(node, &progress); - break; - } - case FZ_CMD_END_TILE: - tiled--; - fz_end_tile(dev); - break; - } - } - fz_catch(ctx) - { - /* Swallow the error */ - if (cookie) - cookie->errors++; - fz_warn(ctx, "Ignoring error during interpretation"); - } - } -} diff --git a/fitz/dev_null.c b/fitz/dev_null.c deleted file mode 100644 index 175b00db..00000000 --- a/fitz/dev_null.c +++ /dev/null @@ -1,388 +0,0 @@ -#include "mupdf/fitz.h" - -fz_device * -fz_new_device(fz_context *ctx, void *user) -{ - fz_device *dev = fz_malloc_struct(ctx, fz_device); - dev->hints = 0; - dev->flags = 0; - dev->user = user; - dev->ctx = ctx; - dev->error_depth = 0; - return dev; -} - -void -fz_free_device(fz_device *dev) -{ - if (dev == NULL) - return; - if (dev->free_user) - dev->free_user(dev); - fz_free(dev->ctx, dev); -} - -void -fz_enable_device_hints(fz_device *dev, int hints) -{ - dev->hints |= hints; -} - -void -fz_disable_device_hints(fz_device *dev, int hints) -{ - dev->hints &= ~hints; -} - -void -fz_begin_page(fz_device *dev, const fz_rect *rect, const fz_matrix *ctm) -{ - if (dev->begin_page) - dev->begin_page(dev, rect, ctm); -} - -void -fz_end_page(fz_device *dev) -{ - if (dev->end_page) - dev->end_page(dev); -} - -void -fz_fill_path(fz_device *dev, fz_path *path, int even_odd, const fz_matrix *ctm, - fz_colorspace *colorspace, float *color, float alpha) -{ - if (dev->error_depth) - return; - if (dev->fill_path) - dev->fill_path(dev, path, even_odd, ctm, colorspace, color, alpha); -} - -void -fz_stroke_path(fz_device *dev, fz_path *path, fz_stroke_state *stroke, const fz_matrix *ctm, - fz_colorspace *colorspace, float *color, float alpha) -{ - if (dev->error_depth) - return; - if (dev->stroke_path) - dev->stroke_path(dev, path, stroke, ctm, colorspace, color, alpha); -} - -void -fz_clip_path(fz_device *dev, fz_path *path, const fz_rect *rect, int even_odd, const fz_matrix *ctm) -{ - fz_context *ctx = dev->ctx; - - if (dev->error_depth) - { - dev->error_depth++; - return; - } - - fz_try(ctx) - { - if (dev->clip_path) - dev->clip_path(dev, path, rect, even_odd, ctm); - } - fz_catch(ctx) - { - dev->error_depth = 1; - strcpy(dev->errmess, fz_caught_message(ctx)); - /* Error swallowed */ - } -} - -void -fz_clip_stroke_path(fz_device *dev, fz_path *path, const fz_rect *rect, fz_stroke_state *stroke, const fz_matrix *ctm) -{ - fz_context *ctx = dev->ctx; - - if (dev->error_depth) - { - dev->error_depth++; - return; - } - - fz_try(ctx) - { - if (dev->clip_stroke_path) - dev->clip_stroke_path(dev, path, rect, stroke, ctm); - } - fz_catch(ctx) - { - dev->error_depth = 1; - strcpy(dev->errmess, fz_caught_message(ctx)); - /* Error swallowed */ - } -} - -void -fz_fill_text(fz_device *dev, fz_text *text, const fz_matrix *ctm, - fz_colorspace *colorspace, float *color, float alpha) -{ - if (dev->error_depth) - return; - if (dev->fill_text) - dev->fill_text(dev, text, ctm, colorspace, color, alpha); -} - -void -fz_stroke_text(fz_device *dev, fz_text *text, fz_stroke_state *stroke, const fz_matrix *ctm, - fz_colorspace *colorspace, float *color, float alpha) -{ - if (dev->error_depth) - return; - if (dev->stroke_text) - dev->stroke_text(dev, text, stroke, ctm, colorspace, color, alpha); -} - -void -fz_clip_text(fz_device *dev, fz_text *text, const fz_matrix *ctm, int accumulate) -{ - fz_context *ctx = dev->ctx; - - if (dev->error_depth) - { - if (accumulate == 0 || accumulate == 1) - dev->error_depth++; - return; - } - - fz_try(ctx) - { - if (dev->clip_text) - dev->clip_text(dev, text, ctm, accumulate); - } - fz_catch(ctx) - { - if (accumulate == 2) - fz_rethrow(ctx); - dev->error_depth = 1; - strcpy(dev->errmess, fz_caught_message(ctx)); - /* Error swallowed */ - } -} - -void -fz_clip_stroke_text(fz_device *dev, fz_text *text, fz_stroke_state *stroke, const fz_matrix *ctm) -{ - fz_context *ctx = dev->ctx; - - if (dev->error_depth) - { - dev->error_depth++; - return; - } - - fz_try(ctx) - { - if (dev->clip_stroke_text) - dev->clip_stroke_text(dev, text, stroke, ctm); - } - fz_catch(ctx) - { - dev->error_depth = 1; - strcpy(dev->errmess, fz_caught_message(ctx)); - /* Error swallowed */ - } -} - -void -fz_ignore_text(fz_device *dev, fz_text *text, const fz_matrix *ctm) -{ - if (dev->error_depth) - return; - if (dev->ignore_text) - dev->ignore_text(dev, text, ctm); -} - -void -fz_pop_clip(fz_device *dev) -{ - if (dev->error_depth) - { - dev->error_depth--; - if (dev->error_depth == 0) - fz_throw(dev->ctx, FZ_ERROR_GENERIC, "%s", dev->errmess); - return; - } - if (dev->pop_clip) - dev->pop_clip(dev); -} - -void -fz_fill_shade(fz_device *dev, fz_shade *shade, const fz_matrix *ctm, float alpha) -{ - if (dev->error_depth) - return; - if (dev->fill_shade) - dev->fill_shade(dev, shade, ctm, alpha); -} - -void -fz_fill_image(fz_device *dev, fz_image *image, const fz_matrix *ctm, float alpha) -{ - if (dev->error_depth) - return; - if (dev->fill_image) - dev->fill_image(dev, image, ctm, alpha); -} - -void -fz_fill_image_mask(fz_device *dev, fz_image *image, const fz_matrix *ctm, - fz_colorspace *colorspace, float *color, float alpha) -{ - if (dev->error_depth) - return; - if (dev->fill_image_mask) - dev->fill_image_mask(dev, image, ctm, colorspace, color, alpha); -} - -void -fz_clip_image_mask(fz_device *dev, fz_image *image, const fz_rect *rect, const fz_matrix *ctm) -{ - fz_context *ctx = dev->ctx; - - if (dev->error_depth) - { - dev->error_depth++; - return; - } - - fz_try(ctx) - { - if (dev->clip_image_mask) - dev->clip_image_mask(dev, image, rect, ctm); - } - fz_catch(ctx) - { - dev->error_depth = 1; - strcpy(dev->errmess, fz_caught_message(ctx)); - /* Error swallowed */ - } -} - -void -fz_begin_mask(fz_device *dev, const fz_rect *area, int luminosity, fz_colorspace *colorspace, float *bc) -{ - fz_context *ctx = dev->ctx; - - if (dev->error_depth) - { - dev->error_depth++; - return; - } - - fz_try(ctx) - { - if (dev->begin_mask) - dev->begin_mask(dev, area, luminosity, colorspace, bc); - } - fz_catch(ctx) - { - dev->error_depth = 1; - strcpy(dev->errmess, fz_caught_message(ctx)); - /* Error swallowed */ - } -} - -void -fz_end_mask(fz_device *dev) -{ - if (dev->error_depth) - { - /* Converts from mask to clip, so no change in stack depth */ - return; - } - if (dev->end_mask) - dev->end_mask(dev); -} - -void -fz_begin_group(fz_device *dev, const fz_rect *area, int isolated, int knockout, int blendmode, float alpha) -{ - fz_context *ctx = dev->ctx; - - if (dev->error_depth) - { - dev->error_depth++; - return; - } - - fz_try(ctx) - { - if (dev->begin_group) - dev->begin_group(dev, area, isolated, knockout, blendmode, alpha); - } - fz_catch(ctx) - { - dev->error_depth = 1; - strcpy(dev->errmess, fz_caught_message(ctx)); - /* Error swallowed */ - } -} - -void -fz_end_group(fz_device *dev) -{ - if (dev->error_depth) - { - dev->error_depth--; - if (dev->error_depth == 0) - fz_throw(dev->ctx, FZ_ERROR_GENERIC, "%s", dev->errmess); - return; - } - if (dev->end_group) - dev->end_group(dev); -} - -void -fz_begin_tile(fz_device *dev, const fz_rect *area, const fz_rect *view, float xstep, float ystep, const fz_matrix *ctm) -{ - (void)fz_begin_tile_id(dev, area, view, xstep, ystep, ctm, 0); -} - -int -fz_begin_tile_id(fz_device *dev, const fz_rect *area, const fz_rect *view, float xstep, float ystep, const fz_matrix *ctm, int id) -{ - fz_context *ctx = dev->ctx; - int ret = 0; - - if (dev->error_depth) - { - dev->error_depth++; - return 0; - } - - if (xstep < 0) - xstep = -xstep; - if (ystep < 0) - ystep = -ystep; - - fz_try(ctx) - { - if (dev->begin_tile) - ret = dev->begin_tile(dev, area, view, xstep, ystep, ctm, id); - } - fz_catch(ctx) - { - dev->error_depth = 1; - strcpy(dev->errmess, fz_caught_message(ctx)); - /* Error swallowed */ - } - return ret; -} - -void -fz_end_tile(fz_device *dev) -{ - if (dev->error_depth) - { - dev->error_depth--; - if (dev->error_depth == 0) - fz_throw(dev->ctx, FZ_ERROR_GENERIC, "%s", dev->errmess); - return; - } - if (dev->end_tile) - dev->end_tile(dev); -} diff --git a/fitz/dev_svg.c b/fitz/dev_svg.c deleted file mode 100644 index 4dd82120..00000000 --- a/fitz/dev_svg.c +++ /dev/null @@ -1,619 +0,0 @@ -#include "mupdf/fitz.h" - -typedef struct svg_device_s svg_device; - -typedef struct tile_s tile; - -struct tile_s -{ - int pattern; - fz_matrix ctm; - fz_rect view; - fz_rect area; - fz_point step; -}; - -struct svg_device_s -{ - fz_context *ctx; - fz_output *out; - - int id; - - int num_tiles; - int max_tiles; - tile *tiles; -}; - -/* Helper functions */ - -static void -svg_dev_path(svg_device *sdev, fz_path *path) -{ - fz_output *out = sdev->out; - float x, y; - int i = 0; - fz_printf(out, " d=\""); - while (i < path->len) - { - switch (path->items[i++].k) - { - case FZ_MOVETO: - x = path->items[i++].v; - y = path->items[i++].v; - fz_printf(out, "M %g %g ", x, y); - break; - case FZ_LINETO: - x = path->items[i++].v; - y = path->items[i++].v; - fz_printf(out, "L %g %g ", x, y); - break; - case FZ_CURVETO: - x = path->items[i++].v; - y = path->items[i++].v; - fz_printf(out, "C %g %g ", x, y); - x = path->items[i++].v; - y = path->items[i++].v; - fz_printf(out, "%g %g ", x, y); - x = path->items[i++].v; - y = path->items[i++].v; - fz_printf(out, "%g %g ", x, y); - break; - case FZ_CLOSE_PATH: - fz_printf(out, "Z "); - break; - } - } - fz_printf(out, "\""); -} - -static void -svg_dev_ctm(svg_device *sdev, const fz_matrix *ctm) -{ - fz_output *out = sdev->out; - - if (ctm->a != 1.0 || ctm->b != 0 || ctm->c != 0 || ctm->d != 1.0 || ctm->e != 0 || ctm->f != 0) - { - fz_printf(out, " transform=\"matrix(%g,%g,%g,%g,%g,%g)\"", - ctm->a, ctm->b, ctm->c, ctm->d, ctm->e, ctm->f); - } -} - -static void -svg_dev_stroke_state(svg_device *sdev, fz_stroke_state *stroke_state) -{ - fz_output *out = sdev->out; - - fz_printf(out, " stroke-width=\"%g\"", stroke_state->linewidth); - fz_printf(out, " stroke-linecap=\"%s\"", - (stroke_state->start_cap == FZ_LINECAP_SQUARE ? "square" : - (stroke_state->start_cap == FZ_LINECAP_ROUND ? "round" : "butt"))); - if (stroke_state->dash_len != 0) - { - int i; - fz_printf(out, " stroke-dasharray="); - for (i = 0; i < stroke_state->dash_len; i++) - fz_printf(out, "%c%g", (i == 0 ? '\"' : ','), stroke_state->dash_list[i]); - fz_printf(out, "\""); - if (stroke_state->dash_phase != 0) - fz_printf(out, " stroke-dashoffset=\"%g\"", stroke_state->dash_phase); - } - if (stroke_state->linejoin == FZ_LINEJOIN_MITER || stroke_state->linejoin == FZ_LINEJOIN_MITER_XPS) - fz_printf(out, " stroke-miterlimit=\"%g\"", stroke_state->miterlimit); - fz_printf(out, " stroke-linejoin=\"%s\"", - (stroke_state->linejoin == FZ_LINEJOIN_BEVEL ? "bevel" : - (stroke_state->linejoin == FZ_LINEJOIN_ROUND ? "round" : "miter"))); -} - -static void -svg_dev_fill_color(svg_device *sdev, fz_colorspace *colorspace, float *color, float alpha) -{ - fz_context *ctx = sdev->ctx; - fz_output *out = sdev->out; - float rgb[FZ_MAX_COLORS]; - - if (colorspace != fz_device_rgb(ctx)) - { - /* If it's not rgb, make it rgb */ - colorspace->to_rgb(ctx, colorspace, color, rgb); - color = rgb; - } - - if (color[0] == 0 && color[1] == 0 && color[2] == 0) - { - /* don't send a fill, as it will be assumed to be black */ - } - else - fz_printf(out, " fill=\"rgb(%d,%d,%d)\"", (int)(255*color[0] + 0.5), (int)(255*color[1] + 0.5), (int)(255*color[2]+0.5)); - if (alpha != 1) - fz_printf(out, " fill-opacity=\"%g\"", alpha); -} - -static void -svg_dev_stroke_color(svg_device *sdev, fz_colorspace *colorspace, float *color, float alpha) -{ - fz_context *ctx = sdev->ctx; - fz_output *out = sdev->out; - float rgb[FZ_MAX_COLORS]; - - if (colorspace != fz_device_rgb(ctx)) - { - /* If it's not rgb, make it rgb */ - colorspace->to_rgb(ctx, colorspace, color, rgb); - color = rgb; - } - - fz_printf(out, " fill=\"none\" stroke=\"rgb(%d,%d,%d)\"", (int)(255*color[0] + 0.5), (int)(255*color[1] + 0.5), (int)(255*color[2]+0.5)); - if (alpha != 1) - fz_printf(out, " stroke-opacity=\"%g\"", alpha); -} - -static void -svg_dev_text(svg_device *sdev, const fz_matrix *ctm, fz_text *text) -{ - fz_output *out = sdev->out; - int i; - fz_matrix inverse; - fz_matrix local_trm; - float size; - - /* Rely on the fact that trm.{e,f} == 0 */ - size = fz_matrix_expansion(&text->trm); - local_trm.a = text->trm.a / size; - local_trm.b = text->trm.b / size; - local_trm.c = -text->trm.c / size; - local_trm.d = -text->trm.d / size; - local_trm.e = 0; - local_trm.f = 0; - fz_invert_matrix(&inverse, &local_trm); - fz_concat(&local_trm, &local_trm, ctm); - - fz_printf(out, " transform=\"matrix(%g,%g,%g,%g,%g,%g)\"", - local_trm.a, local_trm.b, local_trm.c, local_trm.d, local_trm.e, local_trm.f); - fz_printf(out, " font-size=\"%g\"", size); - fz_printf(out, " font-family=\"%s\"", text->font->name); - - fz_printf(out, " x="); - for (i=0; i < text->len; i++) - { - fz_text_item *it = &text->items[i]; - fz_point p; - p.x = it->x; - p.y = it->y; - fz_transform_point(&p, &inverse); - fz_printf(out, "%c%g", i == 0 ? '\"' : ' ', p.x); - } - fz_printf(out, "\" y="); - for (i=0; i < text->len; i++) - { - fz_text_item *it = &text->items[i]; - fz_point p; - p.x = it->x; - p.y = it->y; - fz_transform_point(&p, &inverse); - fz_printf(out, "%c%g", i == 0 ? '\"' : ' ', p.y); - } - fz_printf(out, "\">\n"); - for (i=0; i < text->len; i++) - { - fz_text_item *it = &text->items[i]; - int c = it->ucs; - if (c >= 32 && c <= 127 && c != '<' && c != '&') - fz_printf(out, "%c", c); - else - fz_printf(out, "&#x%04x;", c); - } - fz_printf(out, "\n\n"); -} - -/* Entry points */ - -static void -svg_dev_fill_path(fz_device *dev, fz_path *path, int even_odd, const fz_matrix *ctm, - fz_colorspace *colorspace, float *color, float alpha) -{ - svg_device *sdev = dev->user; - fz_output *out = sdev->out; - - fz_printf(out, "\n"); -} - -static void -svg_dev_stroke_path(fz_device *dev, fz_path *path, fz_stroke_state *stroke, const fz_matrix *ctm, - fz_colorspace *colorspace, float *color, float alpha) -{ - svg_device *sdev = dev->user; - fz_output *out = sdev->out; - - fz_printf(out, "\n"); -} - -static void -svg_dev_clip_path(fz_device *dev, fz_path *path, const fz_rect *rect, int even_odd, const fz_matrix *ctm) -{ - svg_device *sdev = dev->user; - fz_output *out = sdev->out; - int num = sdev->id++; - - fz_printf(out, "\n", num); - fz_printf(out, "\n\n\n", num); -} - -static void -svg_dev_clip_stroke_path(fz_device *dev, fz_path *path, const fz_rect *rect, fz_stroke_state *stroke, const fz_matrix *ctm) -{ - svg_device *sdev = dev->user; - fz_output *out = sdev->out; - fz_context *ctx = dev->ctx; - fz_rect bounds; - int num = sdev->id++; - float white[3] = { 255, 255, 255 }; - - fz_bound_path(ctx, path, stroke, ctm, &bounds); - - fz_printf(out, "\n", - num, bounds.x0, bounds.y0, bounds.x1 - bounds.x0, bounds.y1 - bounds.y0); - fz_printf(out, "\n\n\n", num); -} - -static void -svg_dev_fill_text(fz_device *dev, fz_text *text, const fz_matrix *ctm, - fz_colorspace *colorspace, float *color, float alpha) -{ - svg_device *sdev = dev->user; - fz_output *out = sdev->out; - - fz_printf(out, "user; - fz_output *out = sdev->out; - - fz_printf(out, "user; - fz_output *out = sdev->out; - fz_context *ctx = dev->ctx; - fz_rect bounds; - int num = sdev->id++; - float white[3] = { 255, 255, 255 }; - - fz_bound_text(ctx, text, NULL, ctm, &bounds); - - fz_printf(out, "\n", - num, bounds.x0, bounds.y0, bounds.x1 - bounds.x0, bounds.y1 - bounds.y0); - fz_printf(out, "\n\n", num); -} - -static void -svg_dev_clip_stroke_text(fz_device *dev, fz_text *text, fz_stroke_state *stroke, const fz_matrix *ctm) -{ - svg_device *sdev = dev->user; - fz_output *out = sdev->out; - fz_context *ctx = dev->ctx; - fz_rect bounds; - int num = sdev->id++; - float white[3] = { 255, 255, 255 }; - - fz_bound_text(ctx, text, NULL, ctm, &bounds); - - fz_printf(out, "\n", - num, bounds.x0, bounds.y0, bounds.x1 - bounds.x0, bounds.y1 - bounds.y0); - fz_printf(out, "\n\n", num); -} - -static void -svg_dev_ignore_text(fz_device *dev, fz_text *text, const fz_matrix *ctm) -{ -} - -static void -send_data_base64(fz_output *out, fz_buffer *buffer) -{ - int i, len; - static const char set[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - - len = buffer->len/3; - for (i = 0; i < len; i++) - { - int c = buffer->data[3*i]; - int d = buffer->data[3*i+1]; - int e = buffer->data[3*i+2]; - if ((i & 15) == 0) - fz_printf(out, "\n"); - fz_printf(out, "%c%c%c%c", set[c>>2], set[((c&3)<<4)|(d>>4)], set[((d&15)<<2)|(e>>6)], set[e & 63]); - } - i *= 3; - switch (buffer->len-i) - { - case 2: - { - int c = buffer->data[i]; - int d = buffer->data[i+1]; - fz_printf(out, "%c%c%c=", set[c>>2], set[((c&3)<<4)|(d>>4)], set[((d&15)<<2)]); - break; - } - case 1: - { - int c = buffer->data[i]; - fz_printf(out, "%c%c==", set[c>>2], set[(c&3)<<4]); - break; - } - default: - case 0: - break; - } -} - -static void -svg_dev_fill_image(fz_device *dev, fz_image *image, const fz_matrix *ctm, float alpha) -{ - svg_device *sdev = (svg_device *)dev->user; - fz_context *ctx = dev->ctx; - fz_output *out = sdev->out; - fz_matrix local_ctm = *ctm; - fz_matrix scale = { 1.0f/image->w, 0, 0, 1.0f/image->h, 0, 0}; - - fz_concat(&local_ctm, &scale, ctm); - fz_printf(out, "w, image->h); - switch (image->buffer == NULL ? FZ_IMAGE_JPX : image->buffer->params.type) - { - case FZ_IMAGE_JPEG: - fz_printf(out, "image/jpeg;base64,"); - send_data_base64(out, image->buffer->buffer); - break; - case FZ_IMAGE_PNG: - fz_printf(out, "image/png;base64,"); - send_data_base64(out, image->buffer->buffer); - break; - default: - { - fz_buffer *buf = fz_image_as_png(ctx, image, image->w, image->h); - fz_printf(out, "image/png;base64,"); - send_data_base64(out, buf); - fz_drop_buffer(ctx, buf); - break; - } - } - fz_printf(out, "\"/>\n"); -} - -static void -svg_dev_fill_shade(fz_device *dev, fz_shade *shade, const fz_matrix *ctm, float alpha) -{ -} - -static void -svg_dev_fill_image_mask(fz_device *dev, fz_image *image, const fz_matrix *ctm, -fz_colorspace *colorspace, float *color, float alpha) -{ -} - -static void -svg_dev_clip_image_mask(fz_device *dev, fz_image *image, const fz_rect *rect, const fz_matrix *ctm) -{ - svg_device *sdev = dev->user; - fz_output *out = sdev->out; - - fz_printf(out, "\n"); -} - -static void -svg_dev_pop_clip(fz_device *dev) -{ - svg_device *sdev = (svg_device *)dev->user; - fz_output *out = sdev->out; - - /* FIXME */ - fz_printf(out, "\n"); -} - -static void -svg_dev_begin_mask(fz_device *dev, const fz_rect *bbox, int luminosity, fz_colorspace *colorspace, float *color) -{ -} - -static void -svg_dev_end_mask(fz_device *dev) -{ - -} - -static void -svg_dev_begin_group(fz_device *dev, const fz_rect *bbox, int isolated, int knockout, int blendmode, float alpha) -{ - -} - -static void -svg_dev_end_group(fz_device *dev) -{ - -} - -static int -svg_dev_begin_tile(fz_device *dev, const fz_rect *area, const fz_rect *view, float xstep, float ystep, const fz_matrix *ctm, int id) -{ - svg_device *sdev = (svg_device *)dev->user; - fz_output *out = sdev->out; - fz_context *ctx = dev->ctx; - fz_matrix inverse; - int num; - tile *t; - - if (sdev->num_tiles == sdev->max_tiles) - { - int n = (sdev->num_tiles == 0 ? 4 : sdev->num_tiles * 2); - - sdev->tiles = fz_resize_array(ctx, sdev->tiles, n, sizeof(tile)); - sdev->max_tiles = n; - } - num = sdev->num_tiles++; - t = &sdev->tiles[num]; - t->area = *area; - t->view = *view; - t->ctm = *ctm; - t->pattern = sdev->id++; - t->step.x = xstep; - t->step.y = ystep; - - /* view = area of our reference tile in pattern space. - * area = area to tile into in pattern space. - * xstep/ystep = pattern repeat step in pattern space. - * All of these need to be transformed by ctm to get to device space. - * SVG only allows us to specify pattern tiles as axis aligned - * rectangles, so we send these through as is, and ensure that the - * correct matrix is used on the fill. - */ - - /* In svg, the reference tile is taken from (x,y) to (x+width,y+height) - * and is repeated at (x+n*width,y+m*height) for all integer n and m. - * This means that width and height correspond to xstep and ystep. */ - fz_printf(out, "pattern); - fz_printf(out, " x=\"%g\" y=\"%g\" width=\"%g\" height=\"%g\">\n", - view->x0, view->y0, xstep, ystep); - /* All the pattern contents will have their own ctm applied. Let's - * undo the current one to allow for this */ - fz_invert_matrix(&inverse, ctm); - fz_printf(out, "\n"); - - return 0; -} - -static void -svg_dev_end_tile(fz_device *dev) -{ - svg_device *sdev = (svg_device *)dev->user; - fz_output *out = sdev->out; - int num; - tile *t; - - if (sdev->num_tiles == 0) - return; - num = --sdev->num_tiles; - t = &sdev->tiles[num]; - - fz_printf(out, "\n\n"); - fz_printf(out, "ctm); - fz_printf(out, " fill=\"url(#pa%d)\" x=\"%g\" y=\"%g\" width=\"%g\" height=\"%g\"/>\n", - t->pattern, t->area.x0, t->area.y0, t->area.x1 - t->area.x0, t->area.y1 - t->area.y0); -} - -static void -svg_dev_free_user(fz_device *dev) -{ - svg_device *sdev = dev->user; - fz_context *ctx = sdev->ctx; - fz_output *out = sdev->out; - - fz_free(ctx, sdev->tiles); - - fz_printf(out, "\n"); - - fz_free(ctx, sdev); -} - -fz_device *fz_new_svg_device(fz_context *ctx, fz_output *out, float page_width, float page_height) -{ - svg_device *sdev = fz_malloc_struct(ctx, svg_device); - fz_device *dev; - - fz_try(ctx) - { - sdev->ctx = ctx; - sdev->out = out; - sdev->id = 0; - - dev = fz_new_device(ctx, sdev); - } - fz_catch(ctx) - { - fz_free(ctx, sdev); - fz_rethrow(ctx); - } - - dev->free_user = svg_dev_free_user; - - dev->fill_path = svg_dev_fill_path; - dev->stroke_path = svg_dev_stroke_path; - dev->clip_path = svg_dev_clip_path; - dev->clip_stroke_path = svg_dev_clip_stroke_path; - - dev->fill_text = svg_dev_fill_text; - dev->stroke_text = svg_dev_stroke_text; - dev->clip_text = svg_dev_clip_text; - dev->clip_stroke_text = svg_dev_clip_stroke_text; - dev->ignore_text = svg_dev_ignore_text; - - dev->fill_shade = svg_dev_fill_shade; - dev->fill_image = svg_dev_fill_image; - dev->fill_image_mask = svg_dev_fill_image_mask; - dev->clip_image_mask = svg_dev_clip_image_mask; - - dev->pop_clip = svg_dev_pop_clip; - - dev->begin_mask = svg_dev_begin_mask; - dev->end_mask = svg_dev_end_mask; - dev->begin_group = svg_dev_begin_group; - dev->end_group = svg_dev_end_group; - - dev->begin_tile = svg_dev_begin_tile; - dev->end_tile = svg_dev_end_tile; - - fz_printf(out, "\n"); - fz_printf(out, "\n"); - fz_printf(out, "\n", - page_width*2.54/72, page_height*2.54/72, page_width, page_height); - - return dev; -} diff --git a/fitz/dev_trace.c b/fitz/dev_trace.c deleted file mode 100644 index b3cade91..00000000 --- a/fitz/dev_trace.c +++ /dev/null @@ -1,339 +0,0 @@ -#include "mupdf/fitz.h" - -static void -fz_trace_matrix(const fz_matrix *ctm) -{ - printf(" matrix=\"%g %g %g %g %g %g\"", - ctm->a, ctm->b, ctm->c, ctm->d, ctm->e, ctm->f); -} - -static void -fz_trace_trm(const fz_matrix *trm) -{ - printf(" trm=\"%g %g %g %g\"", - trm->a, trm->b, trm->c, trm->d); -} - -static void -fz_trace_color(fz_colorspace *colorspace, float *color, float alpha) -{ - int i; - printf(" colorspace=\"%s\" color=\"", colorspace->name); - for (i = 0; i < colorspace->n; i++) - printf("%s%g", i == 0 ? "" : " ", color[i]); - printf("\""); - if (alpha < 1) - printf(" alpha=\"%g\"", alpha); -} - -static void -fz_trace_path(fz_path *path, int indent) -{ - float x, y; - int i = 0; - int n; - while (i < path->len) - { - for (n = 0; n < indent; n++) - putchar(' '); - switch (path->items[i++].k) - { - case FZ_MOVETO: - x = path->items[i++].v; - y = path->items[i++].v; - printf("\n", x, y); - break; - case FZ_LINETO: - x = path->items[i++].v; - y = path->items[i++].v; - printf("\n", x, y); - break; - case FZ_CURVETO: - x = path->items[i++].v; - y = path->items[i++].v; - printf("items[i++].v; - y = path->items[i++].v; - printf(" x2=\"%g\" y2=\"%g\"", x, y); - x = path->items[i++].v; - y = path->items[i++].v; - printf(" x3=\"%g\" y3=\"%g\"/>\n", x, y); - break; - case FZ_CLOSE_PATH: - printf("\n"); - break; - } - } -} - -static void -fz_trace_begin_page(fz_device *dev, const fz_rect *rect, const fz_matrix *ctm) -{ - printf("x0, rect->y0, rect->x1, rect->y1); - fz_trace_matrix(ctm); - printf(">\n"); -} - -static void -fz_trace_end_page(fz_device *dev) -{ - printf("\n"); -} - -static void -fz_trace_fill_path(fz_device *dev, fz_path *path, int even_odd, const fz_matrix *ctm, - fz_colorspace *colorspace, float *color, float alpha) -{ - printf("\n"); - fz_trace_path(path, 0); - printf("\n"); -} - -static void -fz_trace_stroke_path(fz_device *dev, fz_path *path, fz_stroke_state *stroke, const fz_matrix *ctm, - fz_colorspace *colorspace, float *color, float alpha) -{ - int i; - - printf("linewidth); - printf(" miterlimit=\"%g\"", stroke->miterlimit); - printf(" linecap=\"%d,%d,%d\"", stroke->start_cap, stroke->dash_cap, stroke->end_cap); - printf(" linejoin=\"%d\"", stroke->linejoin); - - if (stroke->dash_len) - { - printf(" dash_phase=\"%g\" dash=\"", stroke->dash_phase); - for (i = 0; i < stroke->dash_len; i++) - printf("%s%g", i > 0 ? " " : "", stroke->dash_list[i]); - printf("\""); - } - - fz_trace_color(colorspace, color, alpha); - fz_trace_matrix(ctm); - printf(">\n"); - - fz_trace_path(path, 0); - - printf("\n"); -} - -static void -fz_trace_clip_path(fz_device *dev, fz_path *path, const fz_rect *rect, int even_odd, const fz_matrix *ctm) -{ - printf("\n", rect->x0, rect->y0, rect->x1, rect->y1); - else - printf(">\n"); - fz_trace_path(path, 0); - printf("\n"); -} - -static void -fz_trace_clip_stroke_path(fz_device *dev, fz_path *path, const fz_rect *rect, fz_stroke_state *stroke, const fz_matrix *ctm) -{ - printf("\n"); - fz_trace_path(path, 0); - printf("\n"); -} - -static void -fz_trace_fill_text(fz_device *dev, fz_text *text, const fz_matrix *ctm, - fz_colorspace *colorspace, float *color, float alpha) -{ - printf("font->name, text->wmode); - fz_trace_color(colorspace, color, alpha); - fz_trace_matrix(ctm); - fz_trace_trm(&text->trm); - printf(">\n"); - fz_print_text(dev->ctx, stdout, text); - printf("\n"); -} - -static void -fz_trace_stroke_text(fz_device *dev, fz_text *text, fz_stroke_state *stroke, const fz_matrix *ctm, - fz_colorspace *colorspace, float *color, float alpha) -{ - printf("font->name, text->wmode); - fz_trace_color(colorspace, color, alpha); - fz_trace_matrix(ctm); - fz_trace_trm(&text->trm); - printf(">\n"); - fz_print_text(dev->ctx, stdout, text); - printf("\n"); -} - -static void -fz_trace_clip_text(fz_device *dev, fz_text *text, const fz_matrix *ctm, int accumulate) -{ - printf("font->name, text->wmode); - printf(" accumulate=\"%d\"", accumulate); - fz_trace_matrix(ctm); - fz_trace_trm(&text->trm); - printf(">\n"); - fz_print_text(dev->ctx, stdout, text); - printf("\n"); -} - -static void -fz_trace_clip_stroke_text(fz_device *dev, fz_text *text, fz_stroke_state *stroke, const fz_matrix *ctm) -{ - printf("font->name, text->wmode); - fz_trace_matrix(ctm); - fz_trace_trm(&text->trm); - printf(">\n"); - fz_print_text(dev->ctx, stdout, text); - printf("\n"); -} - -static void -fz_trace_ignore_text(fz_device *dev, fz_text *text, const fz_matrix *ctm) -{ - printf("font->name, text->wmode); - fz_trace_matrix(ctm); - fz_trace_trm(&text->trm); - printf(">\n"); - fz_print_text(dev->ctx, stdout, text); - printf("\n"); -} - -static void -fz_trace_fill_image(fz_device *dev, fz_image *image, const fz_matrix *ctm, float alpha) -{ - printf("w, image->h); - printf("/>\n"); -} - -static void -fz_trace_fill_shade(fz_device *dev, fz_shade *shade, const fz_matrix *ctm, float alpha) -{ - printf("\n"); -} - -static void -fz_trace_fill_image_mask(fz_device *dev, fz_image *image, const fz_matrix *ctm, -fz_colorspace *colorspace, float *color, float alpha) -{ - printf("w, image->h); - printf("/>\n"); -} - -static void -fz_trace_clip_image_mask(fz_device *dev, fz_image *image, const fz_rect *rect, const fz_matrix *ctm) -{ - printf("w, image->h); - printf("/>\n"); -} - -static void -fz_trace_pop_clip(fz_device *dev) -{ - printf("\n"); -} - -static void -fz_trace_begin_mask(fz_device *dev, const fz_rect *bbox, int luminosity, fz_colorspace *colorspace, float *color) -{ - printf("x0, bbox->y0, bbox->x1, bbox->y1, - luminosity ? "luminosity" : "alpha"); - printf(">\n"); -} - -static void -fz_trace_end_mask(fz_device *dev) -{ - printf("\n"); -} - -static void -fz_trace_begin_group(fz_device *dev, const fz_rect *bbox, int isolated, int knockout, int blendmode, float alpha) -{ - printf("\n", - bbox->x0, bbox->y0, bbox->x1, bbox->y1, - isolated, knockout, fz_blendmode_name(blendmode), alpha); -} - -static void -fz_trace_end_group(fz_device *dev) -{ - printf("\n"); -} - -static int -fz_trace_begin_tile(fz_device *dev, const fz_rect *area, const fz_rect *view, float xstep, float ystep, const fz_matrix *ctm, int id) -{ - printf("x0, area->y0, area->x1, area->y1); - printf(" view=\"%g %g %g %g\"", view->x0, view->y0, view->x1, view->y1); - printf(" xstep=\"%g\" ystep=\"%g\"", xstep, ystep); - fz_trace_matrix(ctm); - printf(">\n"); - return 0; -} - -static void -fz_trace_end_tile(fz_device *dev) -{ - printf("\n"); -} - -fz_device *fz_new_trace_device(fz_context *ctx) -{ - fz_device *dev = fz_new_device(ctx, NULL); - - dev->begin_page = fz_trace_begin_page; - dev->end_page = fz_trace_end_page; - - dev->fill_path = fz_trace_fill_path; - dev->stroke_path = fz_trace_stroke_path; - dev->clip_path = fz_trace_clip_path; - dev->clip_stroke_path = fz_trace_clip_stroke_path; - - dev->fill_text = fz_trace_fill_text; - dev->stroke_text = fz_trace_stroke_text; - dev->clip_text = fz_trace_clip_text; - dev->clip_stroke_text = fz_trace_clip_stroke_text; - dev->ignore_text = fz_trace_ignore_text; - - dev->fill_shade = fz_trace_fill_shade; - dev->fill_image = fz_trace_fill_image; - dev->fill_image_mask = fz_trace_fill_image_mask; - dev->clip_image_mask = fz_trace_clip_image_mask; - - dev->pop_clip = fz_trace_pop_clip; - - dev->begin_mask = fz_trace_begin_mask; - dev->end_mask = fz_trace_end_mask; - dev->begin_group = fz_trace_begin_group; - dev->end_group = fz_trace_end_group; - - dev->begin_tile = fz_trace_begin_tile; - dev->end_tile = fz_trace_end_tile; - - return dev; -} diff --git a/fitz/doc_document.c b/fitz/doc_document.c deleted file mode 100644 index 8adbf816..00000000 --- a/fitz/doc_document.c +++ /dev/null @@ -1,274 +0,0 @@ -#include "mupdf/fitz.h" - -/* Yuck! Promiscuous we are. */ -extern struct pdf_document *pdf_open_document(fz_context *ctx, const char *filename); -extern struct xps_document *xps_open_document(fz_context *ctx, const char *filename); -extern struct cbz_document *cbz_open_document(fz_context *ctx, const char *filename); -extern struct image_document *image_open_document(fz_context *ctx, const char *filename); - -extern struct pdf_document *pdf_open_document_with_stream(fz_context *ctx, fz_stream *file); -extern struct xps_document *xps_open_document_with_stream(fz_context *ctx, fz_stream *file); -extern struct cbz_document *cbz_open_document_with_stream(fz_context *ctx, fz_stream *file); -extern struct image_document *image_open_document_with_stream(fz_context *ctx, fz_stream *file); - -extern int pdf_js_supported(void); - -static inline int fz_tolower(int c) -{ - if (c >= 'A' && c <= 'Z') - return c + 32; - return c; -} - -static inline int fz_strcasecmp(const char *a, const char *b) -{ - while (fz_tolower(*a) == fz_tolower(*b)) - { - if (*a++ == 0) - return 0; - b++; - } - return fz_tolower(*a) - fz_tolower(*b); -} - -fz_document * -fz_open_document_with_stream(fz_context *ctx, const char *magic, fz_stream *stream) -{ - char *ext = strrchr(magic, '.'); - - if (ext) - { - if (!fz_strcasecmp(ext, ".xps") || !fz_strcasecmp(ext, ".rels") || !fz_strcasecmp(ext, ".oxps")) - return (fz_document*) xps_open_document_with_stream(ctx, stream); - if (!fz_strcasecmp(ext, ".cbz") || !fz_strcasecmp(ext, ".zip")) - return (fz_document*) cbz_open_document_with_stream(ctx, stream); - if (!fz_strcasecmp(ext, ".pdf")) - return (fz_document*) pdf_open_document_with_stream(ctx, stream); - if (!fz_strcasecmp(ext, ".png") || !fz_strcasecmp(ext, ".jpg") || - !fz_strcasecmp(ext, ".jpeg") || !fz_strcasecmp(ext, ".jfif") || - !fz_strcasecmp(ext, ".jfif-tbnl") || !fz_strcasecmp(ext, ".jpe") || - !fz_strcasecmp(ext, ".tif") || !fz_strcasecmp(ext, ".tiff")) - return (fz_document*) image_open_document_with_stream(ctx, stream); - } - - if (!strcmp(magic, "cbz") || !strcmp(magic, "application/x-cbz")) - return (fz_document*) cbz_open_document_with_stream(ctx, stream); - if (!strcmp(magic, "xps") || !strcmp(magic, "oxps") || !strcmp(magic, "application/vnd.ms-xpsdocument")) - return (fz_document*) xps_open_document_with_stream(ctx, stream); - if (!strcmp(magic, "pdf") || !strcmp(magic, "application/pdf")) - return (fz_document*) pdf_open_document_with_stream(ctx, stream); - if (!strcmp(magic, "png") || !strcmp(magic, "image/png") || - !strcmp(magic, "jpg") || !strcmp(magic, "image/jpeg") || - !strcmp(magic, "jpeg") || !strcmp(magic, "image/pjpeg") || - !strcmp(magic, "jpe") || !strcmp(magic, "jfif") || - !strcmp(magic, "tif") || !strcmp(magic, "image/tiff") || - !strcmp(magic, "tiff") || !strcmp(magic, "image/x-tiff")) - return (fz_document*) image_open_document_with_stream(ctx, stream); - - /* last guess: pdf */ - return (fz_document*) pdf_open_document_with_stream(ctx, stream); -} - -fz_document * -fz_open_document(fz_context *ctx, const char *filename) -{ - char *ext = strrchr(filename, '.'); - - if (ext) - { - if (!fz_strcasecmp(ext, ".xps") || !fz_strcasecmp(ext, ".rels") || !fz_strcasecmp(ext, ".oxps")) - return (fz_document*) xps_open_document(ctx, filename); - if (!fz_strcasecmp(ext, ".cbz") || !fz_strcasecmp(ext, ".zip")) - return (fz_document*) cbz_open_document(ctx, filename); - if (!fz_strcasecmp(ext, ".pdf")) - return (fz_document*) pdf_open_document(ctx, filename); - if (!fz_strcasecmp(ext, ".png") || !fz_strcasecmp(ext, ".jpg") || - !fz_strcasecmp(ext, ".jpeg") || !fz_strcasecmp(ext, ".jpe") || - !fz_strcasecmp(ext, ".jfif") || !fz_strcasecmp(ext, ".jfif-tbnl") || - !fz_strcasecmp(ext, ".tif") || !fz_strcasecmp(ext, ".tiff")) - return (fz_document*) image_open_document(ctx, filename); - } - - /* last guess: pdf */ - return (fz_document*) pdf_open_document(ctx, filename); -} - -void -fz_close_document(fz_document *doc) -{ - if (doc && doc->close) - doc->close(doc); -} - -int -fz_needs_password(fz_document *doc) -{ - if (doc && doc->needs_password) - return doc->needs_password(doc); - return 0; -} - -int -fz_authenticate_password(fz_document *doc, char *password) -{ - if (doc && doc->authenticate_password) - return doc->authenticate_password(doc, password); - return 1; -} - -fz_outline * -fz_load_outline(fz_document *doc) -{ - if (doc && doc->load_outline) - return doc->load_outline(doc); - return NULL; -} - -int -fz_count_pages(fz_document *doc) -{ - if (doc && doc->count_pages) - return doc->count_pages(doc); - return 0; -} - -fz_page * -fz_load_page(fz_document *doc, int number) -{ - if (doc && doc->load_page) - return doc->load_page(doc, number); - return NULL; -} - -fz_link * -fz_load_links(fz_document *doc, fz_page *page) -{ - if (doc && doc->load_links && page) - return doc->load_links(doc, page); - return NULL; -} - -fz_rect * -fz_bound_page(fz_document *doc, fz_page *page, fz_rect *r) -{ - if (doc && doc->bound_page && page && r) - return doc->bound_page(doc, page, r); - if (r) - *r = fz_empty_rect; - return r; -} - -fz_annot * -fz_first_annot(fz_document *doc, fz_page *page) -{ - if (doc && doc->first_annot && page) - return doc->first_annot(doc, page); - return NULL; -} - -fz_annot * -fz_next_annot(fz_document *doc, fz_annot *annot) -{ - if (doc && doc->next_annot && annot) - return doc->next_annot(doc, annot); - return NULL; -} - -fz_rect * -fz_bound_annot(fz_document *doc, fz_annot *annot, fz_rect *rect) -{ - if (doc && doc->bound_annot && annot && rect) - return doc->bound_annot(doc, annot, rect); - if (rect) - *rect = fz_empty_rect; - return rect; -} - -void -fz_run_page_contents(fz_document *doc, fz_page *page, fz_device *dev, const fz_matrix *transform, fz_cookie *cookie) -{ - if (doc && doc->run_page_contents && page) - doc->run_page_contents(doc, page, dev, transform, cookie); -} - -void -fz_run_annot(fz_document *doc, fz_page *page, fz_annot *annot, fz_device *dev, const fz_matrix *transform, fz_cookie *cookie) -{ - if (doc && doc->run_annot && page && annot) - doc->run_annot(doc, page, annot, dev, transform, cookie); -} - -void -fz_run_page(fz_document *doc, fz_page *page, fz_device *dev, const fz_matrix *transform, fz_cookie *cookie) -{ - fz_annot *annot; - fz_rect mediabox; - - fz_bound_page(doc, page, &mediabox); - fz_begin_page(dev, &mediabox, transform); - - fz_run_page_contents(doc, page, dev, transform, cookie); - - if (cookie && cookie->progress_max != -1) - { - int count = 1; - for (annot = fz_first_annot(doc, page); annot; annot = fz_next_annot(doc, annot)) - count++; - cookie->progress_max += count; - } - - for (annot = fz_first_annot(doc, page); annot; annot = fz_next_annot(doc, annot)) - { - /* Check the cookie for aborting */ - if (cookie) - { - if (cookie->abort) - break; - cookie->progress++; - } - - fz_run_annot(doc, page, annot, dev, transform, cookie); - } - - fz_end_page(dev); -} - -void -fz_free_page(fz_document *doc, fz_page *page) -{ - if (doc && doc->free_page && page) - doc->free_page(doc, page); -} - -int -fz_meta(fz_document *doc, int key, void *ptr, int size) -{ - if (doc && doc->meta) - return doc->meta(doc, key, ptr, size); - return FZ_META_UNKNOWN_KEY; -} - -fz_transition * -fz_page_presentation(fz_document *doc, fz_page *page, float *duration) -{ - float dummy; - if (duration) - *duration = 0; - else - duration = &dummy; - if (doc && doc->page_presentation && page) - return doc->page_presentation(doc, page, duration); - return NULL; -} - -int fz_javascript_supported(void) -{ - return pdf_js_supported(); -} - -void -fz_write_document(fz_document *doc, char *filename, fz_write_options *opts) -{ - if (doc && doc->write) - doc->write(doc, filename, opts); -} diff --git a/fitz/doc_link.c b/fitz/doc_link.c deleted file mode 100644 index 30dca222..00000000 --- a/fitz/doc_link.c +++ /dev/null @@ -1,65 +0,0 @@ -#include "mupdf/fitz.h" - -void -fz_free_link_dest(fz_context *ctx, fz_link_dest *dest) -{ - switch (dest->kind) - { - case FZ_LINK_NONE: - case FZ_LINK_GOTO: - break; - case FZ_LINK_URI: - fz_free(ctx, dest->ld.uri.uri); - break; - case FZ_LINK_LAUNCH: - fz_free(ctx, dest->ld.launch.file_spec); - break; - case FZ_LINK_NAMED: - fz_free(ctx, dest->ld.named.named); - break; - case FZ_LINK_GOTOR: - fz_free(ctx, dest->ld.gotor.file_spec); - break; - } -} - -fz_link * -fz_new_link(fz_context *ctx, const fz_rect *bbox, fz_link_dest dest) -{ - fz_link *link; - - fz_try(ctx) - { - link = fz_malloc_struct(ctx, fz_link); - link->refs = 1; - } - fz_catch(ctx) - { - fz_free_link_dest(ctx, &dest); - fz_rethrow(ctx); - } - link->dest = dest; - link->rect = *bbox; - link->next = NULL; - return link; -} - -fz_link * -fz_keep_link(fz_context *ctx, fz_link *link) -{ - if (link) - link->refs++; - return link; -} - -void -fz_drop_link(fz_context *ctx, fz_link *link) -{ - while (link && --link->refs == 0) - { - fz_link *next = link->next; - fz_free_link_dest(ctx, &link->dest); - fz_free(ctx, link); - link = next; - } -} diff --git a/fitz/doc_outline.c b/fitz/doc_outline.c deleted file mode 100644 index e26fd378..00000000 --- a/fitz/doc_outline.c +++ /dev/null @@ -1,62 +0,0 @@ -#include "mupdf/fitz.h" - -void -fz_free_outline(fz_context *ctx, fz_outline *outline) -{ - while (outline) - { - fz_outline *next = outline->next; - fz_free_outline(ctx, outline->down); - fz_free(ctx, outline->title); - fz_free_link_dest(ctx, &outline->dest); - fz_free(ctx, outline); - outline = next; - } -} - -static void -do_debug_outline_xml(fz_output *out, fz_outline *outline, int level) -{ - while (outline) - { - fz_printf(out, "title, outline->dest.kind == FZ_LINK_GOTO ? outline->dest.ld.gotor.page + 1 : 0); - if (outline->down) - { - fz_printf(out, ">\n"); - do_debug_outline_xml(out, outline->down, level + 1); - fz_printf(out, "\n"); - } - else - { - fz_printf(out, " />\n"); - } - outline = outline->next; - } -} - -void -fz_print_outline_xml(fz_context *ctx, fz_output *out, fz_outline *outline) -{ - do_debug_outline_xml(out, outline, 0); -} - -static void -do_debug_outline(fz_output *out, fz_outline *outline, int level) -{ - int i; - while (outline) - { - for (i = 0; i < level; i++) - fz_printf(out, "\t"); - fz_printf(out, "%s\t%d\n", outline->title, outline->dest.kind == FZ_LINK_GOTO ? outline->dest.ld.gotor.page + 1 : 0); - if (outline->down) - do_debug_outline(out, outline->down, level + 1); - outline = outline->next; - } -} - -void -fz_print_outline(fz_context *ctx, fz_output *out, fz_outline *outline) -{ - do_debug_outline(out, outline, 0); -} diff --git a/fitz/filt_basic.c b/fitz/filt_basic.c deleted file mode 100644 index 3968d193..00000000 --- a/fitz/filt_basic.c +++ /dev/null @@ -1,662 +0,0 @@ -#include "mupdf/fitz.h" - -/* Pretend we have a filter that just copies data forever */ - -fz_stream * -fz_open_copy(fz_stream *chain) -{ - return fz_keep_stream(chain); -} - -/* Null filter copies a specified amount of data */ - -struct null_filter -{ - fz_stream *chain; - int remain; - int pos; -}; - -static int -read_null(fz_stream *stm, unsigned char *buf, int len) -{ - struct null_filter *state = stm->state; - int amount = fz_mini(len, state->remain); - int n; - - fz_seek(state->chain, state->pos, 0); - n = fz_read(state->chain, buf, amount); - state->remain -= n; - state->pos += n; - return n; -} - -static void -close_null(fz_context *ctx, void *state_) -{ - struct null_filter *state = (struct null_filter *)state_; - fz_stream *chain = state->chain; - fz_free(ctx, state); - fz_close(chain); -} - -fz_stream * -fz_open_null(fz_stream *chain, int len, int offset) -{ - struct null_filter *state; - fz_context *ctx = chain->ctx; - - if (len < 0) - len = 0; - fz_try(ctx) - { - state = fz_malloc_struct(ctx, struct null_filter); - state->chain = chain; - state->remain = len; - state->pos = offset; - } - fz_catch(ctx) - { - fz_close(chain); - fz_rethrow(ctx); - } - - return fz_new_stream(ctx, state, read_null, close_null); -} - -/* Concat filter concatenates several streams into one */ - -struct concat_filter -{ - int max; - int count; - int current; - int pad; /* 1 if we should add whitespace padding between streams */ - int ws; /* 1 if we should send a whitespace padding byte next */ - fz_stream *chain[1]; -}; - -static int -read_concat(fz_stream *stm, unsigned char *buf, int len) -{ - struct concat_filter *state = (struct concat_filter *)stm->state; - int n; - int read = 0; - - if (len <= 0) - return 0; - - while (state->current != state->count && len > 0) - { - /* If we need to send a whitespace char, do that */ - if (state->ws) - { - *buf++ = 32; - read++; - len--; - state->ws = 0; - continue; - } - /* Otherwise, read as much data as will fit in the buffer */ - n = fz_read(state->chain[state->current], buf, len); - read += n; - buf += n; - len -= n; - /* If we didn't read any, then we must have hit the end of - * our buffer space. Move to the next stream, and remember to - * pad. */ - if (n == 0) - { - fz_close(state->chain[state->current]); - state->current++; - state->ws = state->pad; - } - } - - return read; -} - -static void -close_concat(fz_context *ctx, void *state_) -{ - struct concat_filter *state = (struct concat_filter *)state_; - int i; - - for (i = state->current; i < state->count; i++) - { - fz_close(state->chain[i]); - } - fz_free(ctx, state); -} - -fz_stream * -fz_open_concat(fz_context *ctx, int len, int pad) -{ - struct concat_filter *state; - - state = fz_calloc(ctx, 1, sizeof(struct concat_filter) + (len-1)*sizeof(fz_stream *)); - state->max = len; - state->count = 0; - state->current = 0; - state->pad = pad; - state->ws = 0; /* We never send padding byte at the start */ - - return fz_new_stream(ctx, state, read_concat, close_concat); -} - -void -fz_concat_push(fz_stream *concat, fz_stream *chain) -{ - struct concat_filter *state = (struct concat_filter *)concat->state; - - if (state->count == state->max) - fz_throw(concat->ctx, FZ_ERROR_GENERIC, "Concat filter size exceeded"); - - state->chain[state->count++] = chain; -} - -/* ASCII Hex Decode */ - -typedef struct fz_ahxd_s fz_ahxd; - -struct fz_ahxd_s -{ - fz_stream *chain; - int eod; -}; - -static inline int iswhite(int a) -{ - switch (a) { - case '\n': case '\r': case '\t': case ' ': - case '\0': case '\f': case '\b': case 0177: - return 1; - } - return 0; -} - -static inline int ishex(int a) -{ - return (a >= 'A' && a <= 'F') || - (a >= 'a' && a <= 'f') || - (a >= '0' && a <= '9'); -} - -static inline int unhex(int a) -{ - if (a >= 'A' && a <= 'F') return a - 'A' + 0xA; - if (a >= 'a' && a <= 'f') return a - 'a' + 0xA; - if (a >= '0' && a <= '9') return a - '0'; - return 0; -} - -static int -read_ahxd(fz_stream *stm, unsigned char *buf, int len) -{ - fz_ahxd *state = stm->state; - unsigned char *p = buf; - unsigned char *ep = buf + len; - int a, b, c, odd; - - odd = 0; - - while (p < ep) - { - if (state->eod) - return p - buf; - - c = fz_read_byte(state->chain); - if (c < 0) - return p - buf; - - if (ishex(c)) - { - if (!odd) - { - a = unhex(c); - odd = 1; - } - else - { - b = unhex(c); - *p++ = (a << 4) | b; - odd = 0; - } - } - else if (c == '>') - { - if (odd) - *p++ = (a << 4); - state->eod = 1; - } - else if (!iswhite(c)) - { - fz_throw(stm->ctx, FZ_ERROR_GENERIC, "bad data in ahxd: '%c'", c); - } - } - - return p - buf; -} - -static void -close_ahxd(fz_context *ctx, void *state_) -{ - fz_ahxd *state = (fz_ahxd *)state_; - fz_stream *chain = state->chain; - fz_free(ctx, state); - fz_close(chain); -} - -fz_stream * -fz_open_ahxd(fz_stream *chain) -{ - fz_ahxd *state; - fz_context *ctx = chain->ctx; - - fz_try(ctx) - { - state = fz_malloc_struct(ctx, fz_ahxd); - state->chain = chain; - state->eod = 0; - } - fz_catch(ctx) - { - fz_close(chain); - fz_rethrow(ctx); - } - - return fz_new_stream(ctx, state, read_ahxd, close_ahxd); -} - -/* ASCII 85 Decode */ - -typedef struct fz_a85d_s fz_a85d; - -struct fz_a85d_s -{ - fz_stream *chain; - unsigned char bp[4]; - unsigned char *rp, *wp; - int eod; -}; - -static int -read_a85d(fz_stream *stm, unsigned char *buf, int len) -{ - fz_a85d *state = stm->state; - unsigned char *p = buf; - unsigned char *ep = buf + len; - int count = 0; - int word = 0; - int c; - - while (state->rp < state->wp && p < ep) - *p++ = *state->rp++; - - while (p < ep) - { - if (state->eod) - return p - buf; - - c = fz_read_byte(state->chain); - if (c < 0) - return p - buf; - - if (c >= '!' && c <= 'u') - { - if (count == 4) - { - word = word * 85 + (c - '!'); - - state->bp[0] = (word >> 24) & 0xff; - state->bp[1] = (word >> 16) & 0xff; - state->bp[2] = (word >> 8) & 0xff; - state->bp[3] = (word) & 0xff; - state->rp = state->bp; - state->wp = state->bp + 4; - - word = 0; - count = 0; - } - else - { - word = word * 85 + (c - '!'); - count ++; - } - } - - else if (c == 'z' && count == 0) - { - state->bp[0] = 0; - state->bp[1] = 0; - state->bp[2] = 0; - state->bp[3] = 0; - state->rp = state->bp; - state->wp = state->bp + 4; - } - - else if (c == '~') - { - c = fz_read_byte(state->chain); - if (c != '>') - fz_warn(stm->ctx, "bad eod marker in a85d"); - - switch (count) { - case 0: - break; - case 1: - /* Specifically illegal in the spec, but adobe - * and gs both cope. See normal_87.pdf for a - * case where this matters. */ - fz_warn(stm->ctx, "partial final byte in a85d"); - break; - case 2: - word = word * (85 * 85 * 85) + 0xffffff; - state->bp[0] = word >> 24; - state->rp = state->bp; - state->wp = state->bp + 1; - break; - case 3: - word = word * (85 * 85) + 0xffff; - state->bp[0] = word >> 24; - state->bp[1] = word >> 16; - state->rp = state->bp; - state->wp = state->bp + 2; - break; - case 4: - word = word * 85 + 0xff; - state->bp[0] = word >> 24; - state->bp[1] = word >> 16; - state->bp[2] = word >> 8; - state->rp = state->bp; - state->wp = state->bp + 3; - break; - } - state->eod = 1; - } - - else if (!iswhite(c)) - { - fz_throw(stm->ctx, FZ_ERROR_GENERIC, "bad data in a85d: '%c'", c); - } - - while (state->rp < state->wp && p < ep) - *p++ = *state->rp++; - } - - return p - buf; -} - -static void -close_a85d(fz_context *ctx, void *state_) -{ - fz_a85d *state = (fz_a85d *)state_; - fz_stream *chain = state->chain; - - fz_free(ctx, state); - fz_close(chain); -} - -fz_stream * -fz_open_a85d(fz_stream *chain) -{ - fz_a85d *state; - fz_context *ctx = chain->ctx; - - fz_try(ctx) - { - state = fz_malloc_struct(ctx, fz_a85d); - state->chain = chain; - state->rp = state->bp; - state->wp = state->bp; - state->eod = 0; - } - fz_catch(ctx) - { - fz_close(chain); - fz_rethrow(ctx); - } - - return fz_new_stream(ctx, state, read_a85d, close_a85d); -} - -/* Run Length Decode */ - -typedef struct fz_rld_s fz_rld; - -struct fz_rld_s -{ - fz_stream *chain; - int run, n, c; -}; - -static int -read_rld(fz_stream *stm, unsigned char *buf, int len) -{ - fz_rld *state = stm->state; - unsigned char *p = buf; - unsigned char *ep = buf + len; - - while (p < ep) - { - if (state->run == 128) - return p - buf; - - if (state->n == 0) - { - state->run = fz_read_byte(state->chain); - if (state->run < 0) - state->run = 128; - if (state->run < 128) - state->n = state->run + 1; - if (state->run > 128) - { - state->n = 257 - state->run; - state->c = fz_read_byte(state->chain); - if (state->c < 0) - fz_throw(stm->ctx, FZ_ERROR_GENERIC, "premature end of data in run length decode"); - } - } - - if (state->run < 128) - { - while (p < ep && state->n) - { - int c = fz_read_byte(state->chain); - if (c < 0) - fz_throw(stm->ctx, FZ_ERROR_GENERIC, "premature end of data in run length decode"); - *p++ = c; - state->n--; - } - } - - if (state->run > 128) - { - while (p < ep && state->n) - { - *p++ = state->c; - state->n--; - } - } - } - - return p - buf; -} - -static void -close_rld(fz_context *ctx, void *state_) -{ - fz_rld *state = (fz_rld *)state_; - fz_stream *chain = state->chain; - - fz_free(ctx, state); - fz_close(chain); -} - -fz_stream * -fz_open_rld(fz_stream *chain) -{ - fz_rld *state; - fz_context *ctx = chain->ctx; - - fz_try(ctx) - { - state = fz_malloc_struct(ctx, fz_rld); - state->chain = chain; - state->run = 0; - state->n = 0; - state->c = 0; - } - fz_catch(ctx) - { - fz_close(chain); - fz_rethrow(ctx); - } - - return fz_new_stream(ctx, state, read_rld, close_rld); -} - -/* RC4 Filter */ - -typedef struct fz_arc4c_s fz_arc4c; - -struct fz_arc4c_s -{ - fz_stream *chain; - fz_arc4 arc4; -}; - -static int -read_arc4(fz_stream *stm, unsigned char *buf, int len) -{ - fz_arc4c *state = stm->state; - int n = fz_read(state->chain, buf, len); - fz_arc4_encrypt(&state->arc4, buf, buf, n); - return n; -} - -static void -close_arc4(fz_context *ctx, void *state_) -{ - fz_arc4c *state = (fz_arc4c *)state_; - fz_stream *chain = state->chain; - - fz_free(ctx, state); - fz_close(chain); -} - -fz_stream * -fz_open_arc4(fz_stream *chain, unsigned char *key, unsigned keylen) -{ - fz_arc4c *state; - fz_context *ctx = chain->ctx; - - fz_try(ctx) - { - state = fz_malloc_struct(ctx, fz_arc4c); - state->chain = chain; - fz_arc4_init(&state->arc4, key, keylen); - } - fz_catch(ctx) - { - fz_close(chain); - fz_rethrow(ctx); - } - - return fz_new_stream(ctx, state, read_arc4, close_arc4); -} - -/* AES Filter */ - -typedef struct fz_aesd_s fz_aesd; - -struct fz_aesd_s -{ - fz_stream *chain; - fz_aes aes; - unsigned char iv[16]; - int ivcount; - unsigned char bp[16]; - unsigned char *rp, *wp; -}; - -static int -read_aesd(fz_stream *stm, unsigned char *buf, int len) -{ - fz_aesd *state = stm->state; - unsigned char *p = buf; - unsigned char *ep = buf + len; - - while (state->ivcount < 16) - { - int c = fz_read_byte(state->chain); - if (c < 0) - fz_throw(stm->ctx, FZ_ERROR_GENERIC, "premature end in aes filter"); - state->iv[state->ivcount++] = c; - } - - while (state->rp < state->wp && p < ep) - *p++ = *state->rp++; - - while (p < ep) - { - int n = fz_read(state->chain, state->bp, 16); - if (n == 0) - return p - buf; - else if (n < 16) - fz_throw(stm->ctx, FZ_ERROR_GENERIC, "partial block in aes filter"); - - aes_crypt_cbc(&state->aes, AES_DECRYPT, 16, state->iv, state->bp, state->bp); - state->rp = state->bp; - state->wp = state->bp + 16; - - /* strip padding at end of file */ - if (fz_is_eof(state->chain)) - { - int pad = state->bp[15]; - if (pad < 1 || pad > 16) - fz_throw(stm->ctx, FZ_ERROR_GENERIC, "aes padding out of range: %d", pad); - state->wp -= pad; - } - - while (state->rp < state->wp && p < ep) - *p++ = *state->rp++; - } - - return p - buf; -} - -static void -close_aesd(fz_context *ctx, void *state_) -{ - fz_aesd *state = (fz_aesd *)state_; - fz_stream *chain = state->chain; - - fz_free(ctx, state); - fz_close(chain); -} - -fz_stream * -fz_open_aesd(fz_stream *chain, unsigned char *key, unsigned keylen) -{ - fz_aesd *state; - fz_context *ctx = chain->ctx; - - fz_try(ctx) - { - state = fz_malloc_struct(ctx, fz_aesd); - state->chain = chain; - if (aes_setkey_dec(&state->aes, key, keylen * 8)) - fz_throw(ctx, FZ_ERROR_GENERIC, "AES key init failed (keylen=%d)", keylen * 8); - state->ivcount = 0; - state->rp = state->bp; - state->wp = state->bp; - } - fz_catch(ctx) - { - fz_close(chain); - fz_rethrow(ctx); - } - - return fz_new_stream(ctx, state, read_aesd, close_aesd); -} diff --git a/fitz/filt_dctd.c b/fitz/filt_dctd.c deleted file mode 100644 index 1a55e584..00000000 --- a/fitz/filt_dctd.c +++ /dev/null @@ -1,256 +0,0 @@ -#include "mupdf/fitz.h" - -#include -#include - -typedef struct fz_dctd_s fz_dctd; - -struct fz_dctd_s -{ - fz_stream *chain; - fz_context *ctx; - int color_transform; - int init; - int stride; - int l2factor; - unsigned char *scanline; - unsigned char *rp, *wp; - struct jpeg_decompress_struct cinfo; - struct jpeg_source_mgr srcmgr; - struct jpeg_error_mgr errmgr; - jmp_buf jb; - char msg[JMSG_LENGTH_MAX]; -}; - -static void error_exit(j_common_ptr cinfo) -{ - fz_dctd *state = cinfo->client_data; - cinfo->err->format_message(cinfo, state->msg); - longjmp(state->jb, 1); -} - -static void init_source(j_decompress_ptr cinfo) -{ - /* nothing to do */ -} - -static void term_source(j_decompress_ptr cinfo) -{ - /* nothing to do */ -} - -static boolean fill_input_buffer(j_decompress_ptr cinfo) -{ - struct jpeg_source_mgr *src = cinfo->src; - fz_dctd *state = cinfo->client_data; - fz_stream *chain = state->chain; - fz_context *ctx = chain->ctx; - - chain->rp = chain->wp; - fz_try(ctx) - { - fz_fill_buffer(chain); - } - fz_catch(ctx) - { - /* FIXME: TRYLATER */ - return 0; - } - src->next_input_byte = chain->rp; - src->bytes_in_buffer = chain->wp - chain->rp; - - if (src->bytes_in_buffer == 0) - { - static unsigned char eoi[2] = { 0xFF, JPEG_EOI }; - fz_warn(state->ctx, "premature end of file in jpeg"); - src->next_input_byte = eoi; - src->bytes_in_buffer = 2; - } - - return 1; -} - -static void skip_input_data(j_decompress_ptr cinfo, long num_bytes) -{ - struct jpeg_source_mgr *src = cinfo->src; - if (num_bytes > 0) - { - while ((size_t)num_bytes > src->bytes_in_buffer) - { - num_bytes -= src->bytes_in_buffer; - (void) src->fill_input_buffer(cinfo); - } - src->next_input_byte += num_bytes; - src->bytes_in_buffer -= num_bytes; - } -} - -static int -read_dctd(fz_stream *stm, unsigned char *buf, int len) -{ - fz_dctd *state = stm->state; - j_decompress_ptr cinfo = &state->cinfo; - unsigned char *p = buf; - unsigned char *ep = buf + len; - - if (setjmp(state->jb)) - { - if (cinfo->src) - state->chain->rp = state->chain->wp - cinfo->src->bytes_in_buffer; - fz_throw(stm->ctx, FZ_ERROR_GENERIC, "jpeg error: %s", state->msg); - } - - if (!state->init) - { - int c; - cinfo->client_data = state; - cinfo->err = &state->errmgr; - jpeg_std_error(cinfo->err); - cinfo->err->error_exit = error_exit; - jpeg_create_decompress(cinfo); - state->init = 1; - - /* Skip over any stray returns at the start of the stream */ - while ((c = fz_peek_byte(state->chain)) == '\n' || c == '\r') - (void)fz_read_byte(state->chain); - - cinfo->src = &state->srcmgr; - cinfo->src->init_source = init_source; - cinfo->src->fill_input_buffer = fill_input_buffer; - cinfo->src->skip_input_data = skip_input_data; - cinfo->src->resync_to_restart = jpeg_resync_to_restart; - cinfo->src->term_source = term_source; - cinfo->src->next_input_byte = state->chain->rp; - cinfo->src->bytes_in_buffer = state->chain->wp - state->chain->rp; - - jpeg_read_header(cinfo, 1); - - /* speed up jpeg decoding a bit */ - cinfo->dct_method = JDCT_FASTEST; - cinfo->do_fancy_upsampling = FALSE; - - /* default value if ColorTransform is not set */ - if (state->color_transform == -1) - { - if (state->cinfo.num_components == 3) - state->color_transform = 1; - else - state->color_transform = 0; - } - - if (cinfo->saw_Adobe_marker) - state->color_transform = cinfo->Adobe_transform; - - /* Guess the input colorspace, and set output colorspace accordingly */ - switch (cinfo->num_components) - { - case 3: - if (state->color_transform) - cinfo->jpeg_color_space = JCS_YCbCr; - else - cinfo->jpeg_color_space = JCS_RGB; - break; - case 4: - if (state->color_transform) - cinfo->jpeg_color_space = JCS_YCCK; - else - cinfo->jpeg_color_space = JCS_CMYK; - break; - } - - cinfo->scale_num = 8/(1<l2factor); - cinfo->scale_denom = 8; - - jpeg_start_decompress(cinfo); - - state->stride = cinfo->output_width * cinfo->output_components; - state->scanline = fz_malloc(state->ctx, state->stride); - state->rp = state->scanline; - state->wp = state->scanline; - } - - while (state->rp < state->wp && p < ep) - *p++ = *state->rp++; - - while (p < ep) - { - if (cinfo->output_scanline == cinfo->output_height) - break; - - if (p + state->stride <= ep) - { - jpeg_read_scanlines(cinfo, &p, 1); - p += state->stride; - } - else - { - jpeg_read_scanlines(cinfo, &state->scanline, 1); - state->rp = state->scanline; - state->wp = state->scanline + state->stride; - } - - while (state->rp < state->wp && p < ep) - *p++ = *state->rp++; - } - - return p - buf; -} - -static void -close_dctd(fz_context *ctx, void *state_) -{ - fz_dctd *state = (fz_dctd *)state_; - - if (setjmp(state->jb)) - { - fz_warn(ctx, "jpeg error: %s", state->msg); - goto skip; - } - - if (state->init) - jpeg_finish_decompress(&state->cinfo); - -skip: - if (state->cinfo.src) - state->chain->rp = state->chain->wp - state->cinfo.src->bytes_in_buffer; - if (state->init) - jpeg_destroy_decompress(&state->cinfo); - - fz_free(ctx, state->scanline); - fz_close(state->chain); - fz_free(ctx, state); -} - -/* Default: color_transform = -1 (unset) */ -fz_stream * -fz_open_dctd(fz_stream *chain, int color_transform) -{ - return fz_open_resized_dctd(chain, color_transform, 0); -} - -fz_stream * -fz_open_resized_dctd(fz_stream *chain, int color_transform, int l2factor) -{ - fz_context *ctx = chain->ctx; - fz_dctd *state = NULL; - - fz_var(state); - - fz_try(ctx) - { - state = fz_malloc_struct(chain->ctx, fz_dctd); - state->ctx = ctx; - state->chain = chain; - state->color_transform = color_transform; - state->init = 0; - state->l2factor = l2factor; - } - fz_catch(ctx) - { - fz_free(ctx, state); - fz_close(chain); - fz_rethrow(ctx); - } - - return fz_new_stream(ctx, state, read_dctd, close_dctd); -} diff --git a/fitz/filt_faxd.c b/fitz/filt_faxd.c deleted file mode 100644 index 8ac98f42..00000000 --- a/fitz/filt_faxd.c +++ /dev/null @@ -1,776 +0,0 @@ -#include "mupdf/fitz.h" - -/* Fax G3/G4 decoder */ - -/* TODO: uncompressed */ - -/* - the first 2^(initialbits) entries map bit patterns to decodes - let's say initial_bits is 8 for the sake of example - and that the code is 1001 - that means that entries 0x90 .. 0x9f have the entry { val, 4 } - because those are all the bytes that start with the code - and the 4 is the length of the code -... if (n_bits > initial_bits) ... - anyway, in that case, it basically points to a mini table - the n_bits is the maximum length of all codes beginning with that byte - so 2^(n_bits - initial_bits) is the size of the mini-table - peter came up with this, and it makes sense -*/ - -typedef struct cfd_node_s cfd_node; - -struct cfd_node_s -{ - short val; - short nbits; -}; - -enum -{ - cfd_white_initial_bits = 8, - cfd_black_initial_bits = 7, - cfd_2d_initial_bits = 7, - cfd_uncompressed_initial_bits = 6 /* must be 6 */ -}; - -/* non-run codes in tables */ -enum -{ - ERROR = -1, - ZEROS = -2, /* EOL follows, possibly with more padding first */ - UNCOMPRESSED = -3 -}; - -/* semantic codes for cf_2d_decode */ -enum -{ - P = -4, - H = -5, - VR3 = 0, - VR2 = 1, - VR1 = 2, - V0 = 3, - VL1 = 4, - VL2 = 5, - VL3 = 6 -}; - -/* White decoding table. */ -static const cfd_node cf_white_decode[] = { - {256,12},{272,12},{29,8},{30,8},{45,8},{46,8},{22,7},{22,7}, - {23,7},{23,7},{47,8},{48,8},{13,6},{13,6},{13,6},{13,6},{20,7}, - {20,7},{33,8},{34,8},{35,8},{36,8},{37,8},{38,8},{19,7},{19,7}, - {31,8},{32,8},{1,6},{1,6},{1,6},{1,6},{12,6},{12,6},{12,6},{12,6}, - {53,8},{54,8},{26,7},{26,7},{39,8},{40,8},{41,8},{42,8},{43,8}, - {44,8},{21,7},{21,7},{28,7},{28,7},{61,8},{62,8},{63,8},{0,8}, - {320,8},{384,8},{10,5},{10,5},{10,5},{10,5},{10,5},{10,5},{10,5}, - {10,5},{11,5},{11,5},{11,5},{11,5},{11,5},{11,5},{11,5},{11,5}, - {27,7},{27,7},{59,8},{60,8},{288,9},{290,9},{18,7},{18,7},{24,7}, - {24,7},{49,8},{50,8},{51,8},{52,8},{25,7},{25,7},{55,8},{56,8}, - {57,8},{58,8},{192,6},{192,6},{192,6},{192,6},{1664,6},{1664,6}, - {1664,6},{1664,6},{448,8},{512,8},{292,9},{640,8},{576,8},{294,9}, - {296,9},{298,9},{300,9},{302,9},{256,7},{256,7},{2,4},{2,4},{2,4}, - {2,4},{2,4},{2,4},{2,4},{2,4},{2,4},{2,4},{2,4},{2,4},{2,4},{2,4}, - {2,4},{2,4},{3,4},{3,4},{3,4},{3,4},{3,4},{3,4},{3,4},{3,4},{3,4}, - {3,4},{3,4},{3,4},{3,4},{3,4},{3,4},{3,4},{128,5},{128,5},{128,5}, - {128,5},{128,5},{128,5},{128,5},{128,5},{8,5},{8,5},{8,5},{8,5}, - {8,5},{8,5},{8,5},{8,5},{9,5},{9,5},{9,5},{9,5},{9,5},{9,5},{9,5}, - {9,5},{16,6},{16,6},{16,6},{16,6},{17,6},{17,6},{17,6},{17,6}, - {4,4},{4,4},{4,4},{4,4},{4,4},{4,4},{4,4},{4,4},{4,4},{4,4},{4,4}, - {4,4},{4,4},{4,4},{4,4},{4,4},{5,4},{5,4},{5,4},{5,4},{5,4},{5,4}, - {5,4},{5,4},{5,4},{5,4},{5,4},{5,4},{5,4},{5,4},{5,4},{5,4}, - {14,6},{14,6},{14,6},{14,6},{15,6},{15,6},{15,6},{15,6},{64,5}, - {64,5},{64,5},{64,5},{64,5},{64,5},{64,5},{64,5},{6,4},{6,4}, - {6,4},{6,4},{6,4},{6,4},{6,4},{6,4},{6,4},{6,4},{6,4},{6,4},{6,4}, - {6,4},{6,4},{6,4},{7,4},{7,4},{7,4},{7,4},{7,4},{7,4},{7,4},{7,4}, - {7,4},{7,4},{7,4},{7,4},{7,4},{7,4},{7,4},{7,4},{-2,3},{-2,3}, - {-1,0},{-1,0},{-1,0},{-1,0},{-1,0},{-1,0},{-1,0},{-1,0},{-1,0}, - {-1,0},{-1,0},{-1,0},{-1,0},{-3,4},{1792,3},{1792,3},{1984,4}, - {2048,4},{2112,4},{2176,4},{2240,4},{2304,4},{1856,3},{1856,3}, - {1920,3},{1920,3},{2368,4},{2432,4},{2496,4},{2560,4},{1472,1}, - {1536,1},{1600,1},{1728,1},{704,1},{768,1},{832,1},{896,1}, - {960,1},{1024,1},{1088,1},{1152,1},{1216,1},{1280,1},{1344,1}, - {1408,1} -}; - -/* Black decoding table. */ -static const cfd_node cf_black_decode[] = { - {128,12},{160,13},{224,12},{256,12},{10,7},{11,7},{288,12},{12,7}, - {9,6},{9,6},{8,6},{8,6},{7,5},{7,5},{7,5},{7,5},{6,4},{6,4},{6,4}, - {6,4},{6,4},{6,4},{6,4},{6,4},{5,4},{5,4},{5,4},{5,4},{5,4},{5,4}, - {5,4},{5,4},{1,3},{1,3},{1,3},{1,3},{1,3},{1,3},{1,3},{1,3},{1,3}, - {1,3},{1,3},{1,3},{1,3},{1,3},{1,3},{1,3},{4,3},{4,3},{4,3},{4,3}, - {4,3},{4,3},{4,3},{4,3},{4,3},{4,3},{4,3},{4,3},{4,3},{4,3},{4,3}, - {4,3},{3,2},{3,2},{3,2},{3,2},{3,2},{3,2},{3,2},{3,2},{3,2},{3,2}, - {3,2},{3,2},{3,2},{3,2},{3,2},{3,2},{3,2},{3,2},{3,2},{3,2},{3,2}, - {3,2},{3,2},{3,2},{3,2},{3,2},{3,2},{3,2},{3,2},{3,2},{3,2},{3,2}, - {2,2},{2,2},{2,2},{2,2},{2,2},{2,2},{2,2},{2,2},{2,2},{2,2},{2,2}, - {2,2},{2,2},{2,2},{2,2},{2,2},{2,2},{2,2},{2,2},{2,2},{2,2},{2,2}, - {2,2},{2,2},{2,2},{2,2},{2,2},{2,2},{2,2},{2,2},{2,2},{2,2}, - {-2,4},{-2,4},{-1,0},{-1,0},{-1,0},{-1,0},{-1,0},{-1,0},{-1,0}, - {-1,0},{-1,0},{-1,0},{-1,0},{-1,0},{-1,0},{-3,5},{1792,4}, - {1792,4},{1984,5},{2048,5},{2112,5},{2176,5},{2240,5},{2304,5}, - {1856,4},{1856,4},{1920,4},{1920,4},{2368,5},{2432,5},{2496,5}, - {2560,5},{18,3},{18,3},{18,3},{18,3},{18,3},{18,3},{18,3},{18,3}, - {52,5},{52,5},{640,6},{704,6},{768,6},{832,6},{55,5},{55,5}, - {56,5},{56,5},{1280,6},{1344,6},{1408,6},{1472,6},{59,5},{59,5}, - {60,5},{60,5},{1536,6},{1600,6},{24,4},{24,4},{24,4},{24,4}, - {25,4},{25,4},{25,4},{25,4},{1664,6},{1728,6},{320,5},{320,5}, - {384,5},{384,5},{448,5},{448,5},{512,6},{576,6},{53,5},{53,5}, - {54,5},{54,5},{896,6},{960,6},{1024,6},{1088,6},{1152,6},{1216,6}, - {64,3},{64,3},{64,3},{64,3},{64,3},{64,3},{64,3},{64,3},{13,1}, - {13,1},{13,1},{13,1},{13,1},{13,1},{13,1},{13,1},{13,1},{13,1}, - {13,1},{13,1},{13,1},{13,1},{13,1},{13,1},{23,4},{23,4},{50,5}, - {51,5},{44,5},{45,5},{46,5},{47,5},{57,5},{58,5},{61,5},{256,5}, - {16,3},{16,3},{16,3},{16,3},{17,3},{17,3},{17,3},{17,3},{48,5}, - {49,5},{62,5},{63,5},{30,5},{31,5},{32,5},{33,5},{40,5},{41,5}, - {22,4},{22,4},{14,1},{14,1},{14,1},{14,1},{14,1},{14,1},{14,1}, - {14,1},{14,1},{14,1},{14,1},{14,1},{14,1},{14,1},{14,1},{14,1}, - {15,2},{15,2},{15,2},{15,2},{15,2},{15,2},{15,2},{15,2},{128,5}, - {192,5},{26,5},{27,5},{28,5},{29,5},{19,4},{19,4},{20,4},{20,4}, - {34,5},{35,5},{36,5},{37,5},{38,5},{39,5},{21,4},{21,4},{42,5}, - {43,5},{0,3},{0,3},{0,3},{0,3} -}; - -/* 2-D decoding table. */ -static const cfd_node cf_2d_decode[] = { - {128,11},{144,10},{6,7},{0,7},{5,6},{5,6},{1,6},{1,6},{-4,4}, - {-4,4},{-4,4},{-4,4},{-4,4},{-4,4},{-4,4},{-4,4},{-5,3},{-5,3}, - {-5,3},{-5,3},{-5,3},{-5,3},{-5,3},{-5,3},{-5,3},{-5,3},{-5,3}, - {-5,3},{-5,3},{-5,3},{-5,3},{-5,3},{4,3},{4,3},{4,3},{4,3},{4,3}, - {4,3},{4,3},{4,3},{4,3},{4,3},{4,3},{4,3},{4,3},{4,3},{4,3},{4,3}, - {2,3},{2,3},{2,3},{2,3},{2,3},{2,3},{2,3},{2,3},{2,3},{2,3},{2,3}, - {2,3},{2,3},{2,3},{2,3},{2,3},{3,1},{3,1},{3,1},{3,1},{3,1},{3,1}, - {3,1},{3,1},{3,1},{3,1},{3,1},{3,1},{3,1},{3,1},{3,1},{3,1},{3,1}, - {3,1},{3,1},{3,1},{3,1},{3,1},{3,1},{3,1},{3,1},{3,1},{3,1},{3,1}, - {3,1},{3,1},{3,1},{3,1},{3,1},{3,1},{3,1},{3,1},{3,1},{3,1},{3,1}, - {3,1},{3,1},{3,1},{3,1},{3,1},{3,1},{3,1},{3,1},{3,1},{3,1},{3,1}, - {3,1},{3,1},{3,1},{3,1},{3,1},{3,1},{3,1},{3,1},{3,1},{3,1},{3,1}, - {3,1},{3,1},{3,1},{-2,4},{-1,0},{-1,0},{-1,0},{-1,0},{-1,0}, - {-1,0},{-1,0},{-1,0},{-1,0},{-1,0},{-1,0},{-1,0},{-1,0},{-1,0}, - {-1,0},{-1,0},{-1,0},{-1,0},{-1,0},{-1,0},{-1,0},{-1,0},{-3,3} -}; - -/* Uncompressed decoding table. */ -static const cfd_node cf_uncompressed_decode[] = { - {64,12},{5,6},{4,5},{4,5},{3,4},{3,4},{3,4},{3,4},{2,3},{2,3}, - {2,3},{2,3},{2,3},{2,3},{2,3},{2,3},{1,2},{1,2},{1,2},{1,2},{1,2}, - {1,2},{1,2},{1,2},{1,2},{1,2},{1,2},{1,2},{1,2},{1,2},{1,2},{1,2}, - {0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1}, - {0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1}, - {0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1}, - {-1,0},{-1,0},{8,6},{9,6},{6,5},{6,5},{7,5},{7,5},{4,4},{4,4}, - {4,4},{4,4},{5,4},{5,4},{5,4},{5,4},{2,3},{2,3},{2,3},{2,3},{2,3}, - {2,3},{2,3},{2,3},{3,3},{3,3},{3,3},{3,3},{3,3},{3,3},{3,3},{3,3}, - {0,2},{0,2},{0,2},{0,2},{0,2},{0,2},{0,2},{0,2},{0,2},{0,2},{0,2}, - {0,2},{0,2},{0,2},{0,2},{0,2},{1,2},{1,2},{1,2},{1,2},{1,2},{1,2}, - {1,2},{1,2},{1,2},{1,2},{1,2},{1,2},{1,2},{1,2},{1,2},{1,2} -}; - -/* bit magic */ - -static inline int getbit(const unsigned char *buf, int x) -{ - return ( buf[x >> 3] >> ( 7 - (x & 7) ) ) & 1; -} - -static const unsigned char mask[8] = { - 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0 -}; - -static const unsigned char clz[256] = { - 8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 -}; - -static inline int -find_changing(const unsigned char *line, int x, int w) -{ - int a, b, m, W; - - if (!line) - return w; - - /* We assume w > 0, -1 <= x < w */ - if (x < 0) - { - x = 0; - m = 0xFF; - } - else - { - /* Mask out the bits we've already used (including the one - * we started from) */ - m = mask[x & 7]; - } - /* We have 'w' pixels (bits) in line. The last pixel that can be - * safely accessed is the (w-1)th bit of line. - * By taking W = w>>3, we know that the first W bytes of line are - * full, with w&7 stray bits following. */ - W = w>>3; - x >>= 3; - a = line[x]; /* Safe as x < w => x <= w-1 => x>>3 <= (w-1)>>3 */ - b = a ^ (a>>1); - b &= m; - if (x >= W) - { - /* Within the last byte already */ - x = (x<<3) + clz[b]; - if (x > w) - x = w; - return x; - } - while (b == 0) - { - if (++x >= W) - goto nearend; - b = a & 1; - a = line[x]; - b = (b<<7) ^ a ^ (a>>1); - } - return (x<<3) + clz[b]; -nearend: - /* We have less than a byte to go. If no stray bits, exit now. */ - if ((x<<3) == w) - return w; - b = a&1; - a = line[x]; - b = (b<<7) ^ a ^ (a>>1); - x = (x<<3) + clz[b]; - if (x > w) - x = w; - return x; -} - -static inline int -find_changing_color(const unsigned char *line, int x, int w, int color) -{ - if (!line || x >= w) - return w; - - x = find_changing(line, (x > 0 || !color) ? x : -1, w); - - if (x < w && getbit(line, x) != color) - x = find_changing(line, x, w); - - return x; -} - -static const unsigned char lm[8] = { - 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01 -}; - -static const unsigned char rm[8] = { - 0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE -}; - -static inline void setbits(unsigned char *line, int x0, int x1) -{ - int a0, a1, b0, b1, a; - - if (x1 <= x0) - return; - - a0 = x0 >> 3; - a1 = x1 >> 3; - - b0 = x0 & 7; - b1 = x1 & 7; - - if (a0 == a1) - { - if (b1) - line[a0] |= lm[b0] & rm[b1]; - } - else - { - line[a0] |= lm[b0]; - for (a = a0 + 1; a < a1; a++) - line[a] = 0xFF; - if (b1) - line[a1] |= rm[b1]; - } -} - -typedef struct fz_faxd_s fz_faxd; - -enum -{ - STATE_NORMAL, /* neutral state, waiting for any code */ - STATE_MAKEUP, /* got a 1d makeup code, waiting for terminating code */ - STATE_EOL, /* at eol, needs output buffer space */ - STATE_H1, STATE_H2, /* in H part 1 and 2 (both makeup and terminating codes) */ - STATE_DONE /* all done */ -}; - -struct fz_faxd_s -{ - fz_context *ctx; - 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; - - int stride; - int ridx; - - int bidx; - unsigned int word; - - int stage; - - int a, c, dim, eolc; - unsigned char *ref; - unsigned char *dst; - unsigned char *rp, *wp; -}; - -static inline void eat_bits(fz_faxd *fax, int nbits) -{ - fax->word <<= nbits; - fax->bidx += nbits; -} - -static int -fill_bits(fz_faxd *fax) -{ - while (fax->bidx >= 8) - { - int c = fz_read_byte(fax->chain); - if (c == EOF) - return EOF; - fax->bidx -= 8; - fax->word |= c << fax->bidx; - } - return 0; -} - -static int -get_code(fz_faxd *fax, const cfd_node *table, int initialbits) -{ - unsigned int word = fax->word; - int tidx = word >> (32 - initialbits); - int val = table[tidx].val; - int nbits = table[tidx].nbits; - - if (nbits > initialbits) - { - int mask = (1 << (32 - initialbits)) - 1; - tidx = val + ((word & mask) >> (32 - nbits)); - val = table[tidx].val; - nbits = initialbits + table[tidx].nbits; - } - - eat_bits(fax, nbits); - - return val; -} - -/* decode one 1d code */ -static void -dec1d(fz_context *ctx, fz_faxd *fax) -{ - int code; - - if (fax->a == -1) - fax->a = 0; - - if (fax->c) - code = get_code(fax, cf_black_decode, cfd_black_initial_bits); - else - code = get_code(fax, cf_white_decode, cfd_white_initial_bits); - - if (code == UNCOMPRESSED) - fz_throw(ctx, FZ_ERROR_GENERIC, "uncompressed data in faxd"); - - if (code < 0) - fz_throw(ctx, FZ_ERROR_GENERIC, "negative code in 1d faxd"); - - if (fax->a + code > fax->columns) - fz_throw(ctx, FZ_ERROR_GENERIC, "overflow in 1d faxd"); - - if (fax->c) - setbits(fax->dst, fax->a, fax->a + code); - - fax->a += code; - - if (code < 64) - { - fax->c = !fax->c; - fax->stage = STATE_NORMAL; - } - else - fax->stage = STATE_MAKEUP; -} - -/* decode one 2d code */ -static void -dec2d(fz_context *ctx, fz_faxd *fax) -{ - int code, b1, b2; - - if (fax->stage == STATE_H1 || fax->stage == STATE_H2) - { - if (fax->a == -1) - fax->a = 0; - - if (fax->c) - code = get_code(fax, cf_black_decode, cfd_black_initial_bits); - else - code = get_code(fax, cf_white_decode, cfd_white_initial_bits); - - if (code == UNCOMPRESSED) - fz_throw(ctx, FZ_ERROR_GENERIC, "uncompressed data in faxd"); - - if (code < 0) - fz_throw(ctx, FZ_ERROR_GENERIC, "negative code in 2d faxd"); - - if (fax->a + code > fax->columns) - fz_throw(ctx, FZ_ERROR_GENERIC, "overflow in 2d faxd"); - - if (fax->c) - setbits(fax->dst, fax->a, fax->a + code); - - fax->a += code; - - if (code < 64) - { - fax->c = !fax->c; - if (fax->stage == STATE_H1) - fax->stage = STATE_H2; - else if (fax->stage == STATE_H2) - fax->stage = STATE_NORMAL; - } - - return; - } - - code = get_code(fax, cf_2d_decode, cfd_2d_initial_bits); - - switch (code) - { - case H: - fax->stage = STATE_H1; - break; - - case P: - b1 = find_changing_color(fax->ref, fax->a, fax->columns, !fax->c); - if (b1 >= fax->columns) - b2 = fax->columns; - else - b2 = find_changing(fax->ref, b1, fax->columns); - if (fax->c) setbits(fax->dst, fax->a, b2); - fax->a = b2; - break; - - case V0: - b1 = find_changing_color(fax->ref, fax->a, fax->columns, !fax->c); - if (fax->c) setbits(fax->dst, fax->a, b1); - fax->a = b1; - fax->c = !fax->c; - break; - - case VR1: - b1 = 1 + find_changing_color(fax->ref, fax->a, fax->columns, !fax->c); - if (b1 >= fax->columns) b1 = fax->columns; - if (fax->c) setbits(fax->dst, fax->a, b1); - fax->a = b1; - fax->c = !fax->c; - break; - - case VR2: - b1 = 2 + find_changing_color(fax->ref, fax->a, fax->columns, !fax->c); - if (b1 >= fax->columns) b1 = fax->columns; - if (fax->c) setbits(fax->dst, fax->a, b1); - fax->a = b1; - fax->c = !fax->c; - break; - - case VR3: - b1 = 3 + find_changing_color(fax->ref, fax->a, fax->columns, !fax->c); - if (b1 >= fax->columns) b1 = fax->columns; - if (fax->c) setbits(fax->dst, fax->a, b1); - fax->a = b1; - fax->c = !fax->c; - break; - - case VL1: - b1 = -1 + find_changing_color(fax->ref, fax->a, fax->columns, !fax->c); - if (b1 < 0) b1 = 0; - if (fax->c) setbits(fax->dst, fax->a, b1); - fax->a = b1; - fax->c = !fax->c; - break; - - case VL2: - b1 = -2 + find_changing_color(fax->ref, fax->a, fax->columns, !fax->c); - if (b1 < 0) b1 = 0; - if (fax->c) setbits(fax->dst, fax->a, b1); - fax->a = b1; - fax->c = !fax->c; - break; - - case VL3: - b1 = -3 + find_changing_color(fax->ref, fax->a, fax->columns, !fax->c); - if (b1 < 0) b1 = 0; - if (fax->c) setbits(fax->dst, fax->a, b1); - fax->a = b1; - fax->c = !fax->c; - break; - - case UNCOMPRESSED: - fz_throw(ctx, FZ_ERROR_GENERIC, "uncompressed data in faxd"); - - case ERROR: - fz_throw(ctx, FZ_ERROR_GENERIC, "invalid code in 2d faxd"); - - default: - fz_throw(ctx, FZ_ERROR_GENERIC, "invalid code in 2d faxd (%d)", code); - } -} - -static int -read_faxd(fz_stream *stm, unsigned char *buf, int len) -{ - fz_faxd *fax = stm->state; - unsigned char *p = buf; - unsigned char *ep = buf + len; - unsigned char *tmp; - - if (fax->stage == STATE_DONE) - return 0; - - if (fax->stage == STATE_EOL) - goto eol; - -loop: - - if (fill_bits(fax)) - { - if (fax->bidx > 31) - { - if (fax->a > 0) - goto eol; - goto rtc; - } - } - - if ((fax->word >> (32 - 12)) == 0) - { - eat_bits(fax, 1); - goto loop; - } - - if ((fax->word >> (32 - 12)) == 1) - { - eat_bits(fax, 12); - fax->eolc ++; - - if (fax->k > 0) - { - if (fax->a == -1) - fax->a = 0; - if ((fax->word >> (32 - 1)) == 1) - fax->dim = 1; - else - fax->dim = 2; - eat_bits(fax, 1); - } - } - else if (fax->k > 0 && fax->a == -1) - { - fax->a = 0; - if ((fax->word >> (32 - 1)) == 1) - fax->dim = 1; - else - fax->dim = 2; - eat_bits(fax, 1); - } - else if (fax->dim == 1) - { - fax->eolc = 0; - dec1d(stm->ctx, fax); - } - else if (fax->dim == 2) - { - fax->eolc = 0; - dec2d(stm->ctx, fax); - } - - /* no eol check after makeup codes nor in the middle of an H code */ - if (fax->stage == STATE_MAKEUP || fax->stage == STATE_H1 || fax->stage == STATE_H2) - goto loop; - - /* check for eol conditions */ - if (fax->eolc || fax->a >= fax->columns) - { - if (fax->a > 0) - goto eol; - if (fax->eolc == (fax->k < 0 ? 2 : 6)) - goto rtc; - } - - goto loop; - -eol: - fax->stage = STATE_EOL; - - if (fax->black_is_1) - { - while (fax->rp < fax->wp && p < ep) - *p++ = *fax->rp++; - } - else - { - while (fax->rp < fax->wp && p < ep) - *p++ = *fax->rp++ ^ 0xff; - } - - if (fax->rp < fax->wp) - return p - buf; - - tmp = fax->ref; - fax->ref = fax->dst; - fax->dst = tmp; - memset(fax->dst, 0, fax->stride); - - fax->rp = fax->dst; - fax->wp = fax->dst + fax->stride; - - fax->stage = STATE_NORMAL; - fax->c = 0; - fax->a = -1; - fax->ridx ++; - - if (!fax->end_of_block && fax->rows) - { - if (fax->ridx >= fax->rows) - goto rtc; - } - - /* we have not read dim from eol, make a guess */ - if (fax->k > 0 && !fax->eolc && fax->a == -1) - { - if (fax->ridx % fax->k == 0) - fax->dim = 1; - else - fax->dim = 2; - } - - /* if end_of_line & encoded_byte_align, EOLs are *not* optional */ - if (fax->encoded_byte_align) - { - if (fax->end_of_line) - eat_bits(fax, (12 - fax->bidx) & 7); - else - eat_bits(fax, (8 - fax->bidx) & 7); - } - - /* no more space in output, don't decode the next row yet */ - if (p == buf + len) - return p - buf; - - goto loop; - -rtc: - fax->stage = STATE_DONE; - return p - buf; -} - -static void -close_faxd(fz_context *ctx, void *state_) -{ - fz_faxd *fax = (fz_faxd *)state_; - int i; - - /* if we read any extra bytes, try to put them back */ - i = (32 - fax->bidx) / 8; - while (i--) - fz_unread_byte(fax->chain); - - fz_close(fax->chain); - fz_free(ctx, fax->ref); - fz_free(ctx, fax->dst); - fz_free(ctx, fax); -} - -/* Default: columns = 1728, end_of_block = 1, the rest = 0 */ -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_context *ctx = chain->ctx; - fz_faxd *fax = NULL; - - fz_var(fax); - - fz_try(ctx) - { - fax = fz_malloc_struct(ctx, fz_faxd); - fax->chain = chain; - - fax->ref = NULL; - fax->dst = NULL; - - fax->k = k; - fax->end_of_line = end_of_line; - fax->encoded_byte_align = encoded_byte_align; - fax->columns = columns; - fax->rows = rows; - fax->end_of_block = end_of_block; - fax->black_is_1 = black_is_1; - - fax->stride = ((fax->columns - 1) >> 3) + 1; - fax->ridx = 0; - fax->bidx = 32; - fax->word = 0; - - fax->stage = STATE_NORMAL; - fax->a = -1; - fax->c = 0; - fax->dim = fax->k < 0 ? 2 : 1; - fax->eolc = 0; - - fax->ref = fz_malloc(ctx, fax->stride); - fax->dst = fz_malloc(ctx, fax->stride); - fax->rp = fax->dst; - fax->wp = fax->dst + fax->stride; - - memset(fax->ref, 0, fax->stride); - memset(fax->dst, 0, fax->stride); - } - fz_catch(ctx) - { - if (fax) - { - fz_free(ctx, fax->dst); - fz_free(ctx, fax->ref); - } - fz_free(ctx, fax); - fz_close(chain); - fz_rethrow(ctx); - } - - return fz_new_stream(ctx, fax, read_faxd, close_faxd); -} diff --git a/fitz/filt_flate.c b/fitz/filt_flate.c deleted file mode 100644 index 73451d59..00000000 --- a/fitz/filt_flate.c +++ /dev/null @@ -1,117 +0,0 @@ -#include "mupdf/fitz.h" - -#include - -typedef struct fz_flate_s fz_flate; - -struct fz_flate_s -{ - fz_stream *chain; - z_stream z; -}; - -static void *zalloc(void *opaque, unsigned int items, unsigned int size) -{ - return fz_malloc_array_no_throw(opaque, items, size); -} - -static void zfree(void *opaque, void *ptr) -{ - fz_free(opaque, ptr); -} - -static int -read_flated(fz_stream *stm, unsigned char *outbuf, int outlen) -{ - fz_flate *state = stm->state; - fz_stream *chain = state->chain; - z_streamp zp = &state->z; - int code; - - zp->next_out = outbuf; - zp->avail_out = outlen; - - while (zp->avail_out > 0) - { - if (chain->rp == chain->wp) - fz_fill_buffer(chain); - - zp->next_in = chain->rp; - zp->avail_in = chain->wp - chain->rp; - - code = inflate(zp, Z_SYNC_FLUSH); - - chain->rp = chain->wp - zp->avail_in; - - if (code == Z_STREAM_END) - { - return outlen - zp->avail_out; - } - else if (code == Z_BUF_ERROR) - { - fz_warn(stm->ctx, "premature end of data in flate filter"); - return outlen - zp->avail_out; - } - else if (code == Z_DATA_ERROR && zp->avail_in == 0) - { - fz_warn(stm->ctx, "ignoring zlib error: %s", zp->msg); - return outlen - zp->avail_out; - } - else if (code != Z_OK) - { - fz_throw(stm->ctx, FZ_ERROR_GENERIC, "zlib error: %s", zp->msg); - } - } - - return outlen - zp->avail_out; -} - -static void -close_flated(fz_context *ctx, void *state_) -{ - fz_flate *state = (fz_flate *)state_; - int code; - - code = inflateEnd(&state->z); - if (code != Z_OK) - fz_warn(ctx, "zlib error: inflateEnd: %s", state->z.msg); - - fz_close(state->chain); - fz_free(ctx, state); -} - -fz_stream * -fz_open_flated(fz_stream *chain) -{ - fz_flate *state = NULL; - int code = Z_OK; - fz_context *ctx = chain->ctx; - - fz_var(code); - fz_var(state); - - fz_try(ctx) - { - state = fz_malloc_struct(ctx, fz_flate); - state->chain = chain; - - state->z.zalloc = zalloc; - state->z.zfree = zfree; - state->z.opaque = ctx; - state->z.next_in = NULL; - state->z.avail_in = 0; - - code = inflateInit(&state->z); - if (code != Z_OK) - fz_throw(ctx, FZ_ERROR_GENERIC, "zlib error: inflateInit: %s", state->z.msg); - } - fz_catch(ctx) - { - if (state && code == Z_OK) - inflateEnd(&state->z); - fz_free(ctx, state); - fz_close(chain); - fz_rethrow(ctx); - } - return fz_new_stream(ctx, state, read_flated, close_flated); -} diff --git a/fitz/filt_jbig2d.c b/fitz/filt_jbig2d.c deleted file mode 100644 index 12eb8c3b..00000000 --- a/fitz/filt_jbig2d.c +++ /dev/null @@ -1,108 +0,0 @@ -#include "mupdf/fitz.h" - -#include - -typedef struct fz_jbig2d_s fz_jbig2d; - -struct fz_jbig2d_s -{ - fz_stream *chain; - Jbig2Ctx *ctx; - Jbig2GlobalCtx *gctx; - Jbig2Image *page; - int idx; -}; - -static void -close_jbig2d(fz_context *ctx, void *state_) -{ - fz_jbig2d *state = (fz_jbig2d *)state_; - if (state->page) - jbig2_release_page(state->ctx, state->page); - if (state->gctx) - jbig2_global_ctx_free(state->gctx); - jbig2_ctx_free(state->ctx); - fz_close(state->chain); - fz_free(ctx, state); -} - -static int -read_jbig2d(fz_stream *stm, unsigned char *buf, int len) -{ - fz_jbig2d *state = stm->state; - unsigned char tmp[4096]; - unsigned char *p = buf; - unsigned char *ep = buf + len; - unsigned char *s; - int x, w, n; - - if (!state->page) - { - while (1) - { - n = fz_read(state->chain, tmp, sizeof tmp); - if (n == 0) - break; - jbig2_data_in(state->ctx, tmp, n); - } - - jbig2_complete_page(state->ctx); - - state->page = jbig2_page_out(state->ctx); - if (!state->page) - fz_throw(stm->ctx, FZ_ERROR_GENERIC, "jbig2_page_out failed"); - } - - s = state->page->data; - w = state->page->height * state->page->stride; - x = state->idx; - while (p < ep && x < w) - *p++ = s[x++] ^ 0xff; - state->idx = x; - - return p - buf; -} - -fz_stream * -fz_open_jbig2d(fz_stream *chain, fz_buffer *globals) -{ - fz_jbig2d *state = NULL; - fz_context *ctx = chain->ctx; - - fz_var(state); - - fz_try(ctx) - { - state = fz_malloc_struct(chain->ctx, fz_jbig2d); - state->ctx = NULL; - state->gctx = NULL; - state->chain = chain; - state->ctx = jbig2_ctx_new(NULL, JBIG2_OPTIONS_EMBEDDED, NULL, NULL, NULL); - state->page = NULL; - state->idx = 0; - - if (globals) - { - jbig2_data_in(state->ctx, globals->data, globals->len); - state->gctx = jbig2_make_global_ctx(state->ctx); - state->ctx = jbig2_ctx_new(NULL, JBIG2_OPTIONS_EMBEDDED, state->gctx, NULL, NULL); - } - } - fz_catch(ctx) - { - if (state) - { - if (state->gctx) - jbig2_global_ctx_free(state->gctx); - if (state->ctx) - jbig2_ctx_free(state->ctx); - } - fz_drop_buffer(ctx, globals); - fz_free(ctx, state); - fz_close(chain); - fz_rethrow(ctx); - } - fz_drop_buffer(ctx, globals); - - return fz_new_stream(ctx, state, read_jbig2d, close_jbig2d); -} diff --git a/fitz/filt_lzwd.c b/fitz/filt_lzwd.c deleted file mode 100644 index 73909ca1..00000000 --- a/fitz/filt_lzwd.c +++ /dev/null @@ -1,224 +0,0 @@ -#include "mupdf/fitz.h" - -/* TODO: error checking */ - -enum -{ - MIN_BITS = 9, - MAX_BITS = 12, - NUM_CODES = (1 << MAX_BITS), - LZW_CLEAR = 256, - LZW_EOD = 257, - LZW_FIRST = 258, - MAX_LENGTH = 4097 -}; - -typedef struct lzw_code_s lzw_code; - -struct lzw_code_s -{ - int prev; /* prev code (in string) */ - unsigned short length; /* string len, including this token */ - unsigned char value; /* data value */ - unsigned char first_char; /* first token of string */ -}; - -typedef struct fz_lzwd_s fz_lzwd; - -struct fz_lzwd_s -{ - fz_stream *chain; - int eod; - - int early_change; - - int code_bits; /* num bits/code */ - int code; /* current code */ - int old_code; /* previously recognized code */ - int next_code; /* next free entry */ - - lzw_code table[NUM_CODES]; - - unsigned char bp[MAX_LENGTH]; - unsigned char *rp, *wp; -}; - -static int -read_lzwd(fz_stream *stm, unsigned char *buf, int len) -{ - fz_lzwd *lzw = stm->state; - lzw_code *table = lzw->table; - unsigned char *p = buf; - unsigned char *ep = buf + len; - unsigned char *s; - int codelen; - - int code_bits = lzw->code_bits; - int code = lzw->code; - int old_code = lzw->old_code; - int next_code = lzw->next_code; - - while (lzw->rp < lzw->wp && p < ep) - *p++ = *lzw->rp++; - - while (p < ep) - { - if (lzw->eod) - return 0; - - code = fz_read_bits(lzw->chain, code_bits); - - if (fz_is_eof_bits(lzw->chain)) - { - lzw->eod = 1; - break; - } - - if (code == LZW_EOD) - { - lzw->eod = 1; - break; - } - - if (next_code >= NUM_CODES && code != LZW_CLEAR) - { - fz_warn(stm->ctx, "missing clear code in lzw decode"); - code = LZW_CLEAR; - } - - if (code == LZW_CLEAR) - { - code_bits = MIN_BITS; - next_code = LZW_FIRST; - old_code = -1; - continue; - } - - /* if stream starts without a clear code, old_code is undefined... */ - if (old_code == -1) - { - old_code = code; - } - else if (code > next_code || next_code >= NUM_CODES) - { - fz_warn(stm->ctx, "out of range code encountered in lzw decode"); - } - else - { - /* add new entry to the code table */ - table[next_code].prev = old_code; - table[next_code].first_char = table[old_code].first_char; - table[next_code].length = table[old_code].length + 1; - if (code < next_code) - table[next_code].value = table[code].first_char; - else if (code == next_code) - table[next_code].value = table[next_code].first_char; - else - fz_warn(stm->ctx, "out of range code encountered in lzw decode"); - - next_code ++; - - if (next_code > (1 << code_bits) - lzw->early_change - 1) - { - code_bits ++; - if (code_bits > MAX_BITS) - code_bits = MAX_BITS; - } - - old_code = code; - } - - /* code maps to a string, copy to output (in reverse...) */ - if (code > 255) - { - codelen = table[code].length; - lzw->rp = lzw->bp; - lzw->wp = lzw->bp + codelen; - - assert(codelen < MAX_LENGTH); - - s = lzw->wp; - do { - *(--s) = table[code].value; - code = table[code].prev; - } while (code >= 0 && s > lzw->bp); - } - - /* ... or just a single character */ - else - { - lzw->bp[0] = code; - lzw->rp = lzw->bp; - lzw->wp = lzw->bp + 1; - } - - /* copy to output */ - while (lzw->rp < lzw->wp && p < ep) - *p++ = *lzw->rp++; - } - - lzw->code_bits = code_bits; - lzw->code = code; - lzw->old_code = old_code; - lzw->next_code = next_code; - - return p - buf; -} - -static void -close_lzwd(fz_context *ctx, void *state_) -{ - fz_lzwd *lzw = (fz_lzwd *)state_; - fz_close(lzw->chain); - fz_free(ctx, lzw); -} - -/* Default: early_change = 1 */ -fz_stream * -fz_open_lzwd(fz_stream *chain, int early_change) -{ - fz_context *ctx = chain->ctx; - fz_lzwd *lzw = NULL; - int i; - - fz_var(lzw); - - fz_try(ctx) - { - lzw = fz_malloc_struct(ctx, fz_lzwd); - lzw->chain = chain; - lzw->eod = 0; - lzw->early_change = early_change; - - for (i = 0; i < 256; i++) - { - lzw->table[i].value = i; - lzw->table[i].first_char = i; - lzw->table[i].length = 1; - lzw->table[i].prev = -1; - } - - for (i = 256; i < NUM_CODES; i++) - { - lzw->table[i].value = 0; - lzw->table[i].first_char = 0; - lzw->table[i].length = 0; - lzw->table[i].prev = -1; - } - - lzw->code_bits = MIN_BITS; - lzw->code = -1; - lzw->next_code = LZW_FIRST; - lzw->old_code = -1; - lzw->rp = lzw->bp; - lzw->wp = lzw->bp; - } - fz_catch(ctx) - { - fz_free(ctx, lzw); - fz_close(chain); - fz_rethrow(ctx); - } - - return fz_new_stream(ctx, lzw, read_lzwd, close_lzwd); -} diff --git a/fitz/filt_predict.c b/fitz/filt_predict.c deleted file mode 100644 index c8de290a..00000000 --- a/fitz/filt_predict.c +++ /dev/null @@ -1,256 +0,0 @@ -#include "mupdf/fitz.h" - -/* TODO: check if this works with 16bpp images */ - -enum { MAXC = 32 }; - -typedef struct fz_predict_s fz_predict; - -struct fz_predict_s -{ - fz_stream *chain; - - int predictor; - int columns; - int colors; - int bpc; - - int stride; - int bpp; - unsigned char *in; - unsigned char *out; - unsigned char *ref; - unsigned char *rp, *wp; -}; - -static inline int getcomponent(unsigned char *line, int x, int bpc) -{ - switch (bpc) - { - case 1: return (line[x >> 3] >> ( 7 - (x & 7) ) ) & 1; - case 2: return (line[x >> 2] >> ( ( 3 - (x & 3) ) << 1 ) ) & 3; - case 4: return (line[x >> 1] >> ( ( 1 - (x & 1) ) << 2 ) ) & 15; - case 8: return line[x]; - case 16: return (line[x<<1]<<8)+line[(x<<1)+1]; - } - return 0; -} - -static inline void putcomponent(unsigned char *buf, int x, int bpc, int value) -{ - switch (bpc) - { - case 1: buf[x >> 3] |= value << (7 - (x & 7)); break; - case 2: buf[x >> 2] |= value << ((3 - (x & 3)) << 1); break; - case 4: buf[x >> 1] |= value << ((1 - (x & 1)) << 2); break; - case 8: buf[x] = value; break; - case 16: buf[x<<1] = value>>8; buf[(x<<1)+1] = value; break; - } -} - -static inline int paeth(int a, int b, int c) -{ - /* The definitions of ac and bc are correct, not a typo. */ - int ac = b - c, bc = a - c, abcc = ac + bc; - int pa = fz_absi(ac); - int pb = fz_absi(bc); - int pc = fz_absi(abcc); - return pa <= pb && pa <= pc ? a : pb <= pc ? b : c; -} - -static void -fz_predict_tiff(fz_predict *state, unsigned char *out, unsigned char *in, int len) -{ - int left[MAXC]; - int i, k; - const int mask = (1 << state->bpc)-1; - - for (k = 0; k < state->colors; k++) - left[k] = 0; - memset(out, 0, state->stride); - - for (i = 0; i < state->columns; i++) - { - for (k = 0; k < state->colors; k++) - { - int a = getcomponent(in, i * state->colors + k, state->bpc); - int b = a + left[k]; - int c = b & mask; - putcomponent(out, i * state->colors + k, state->bpc, c); - left[k] = c; - } - } -} - -static void -fz_predict_png(fz_predict *state, unsigned char *out, unsigned char *in, int len, int predictor) -{ - int bpp = state->bpp; - int i; - unsigned char *ref = state->ref; - - switch (predictor) - { - case 0: - memcpy(out, in, len); - break; - case 1: - for (i = bpp; i > 0; i--) - { - *out++ = *in++; - } - for (i = len - bpp; i > 0; i--) - { - *out = *in++ + out[-bpp]; - out++; - } - break; - case 2: - for (i = bpp; i > 0; i--) - { - *out++ = *in++ + *ref++; - } - for (i = len - bpp; i > 0; i--) - { - *out++ = *in++ + *ref++; - } - break; - case 3: - for (i = bpp; i > 0; i--) - { - *out++ = *in++ + (*ref++) / 2; - } - for (i = len - bpp; i > 0; i--) - { - *out = *in++ + (out[-bpp] + *ref++) / 2; - out++; - } - break; - case 4: - for (i = bpp; i > 0; i--) - { - *out++ = *in++ + paeth(0, *ref++, 0); - } - for (i = len - bpp; i > 0; i --) - { - *out = *in++ + paeth(out[-bpp], *ref, ref[-bpp]); - ref++; - out++; - } - break; - } -} - -static int -read_predict(fz_stream *stm, unsigned char *buf, int len) -{ - fz_predict *state = stm->state; - unsigned char *p = buf; - unsigned char *ep = buf + len; - int ispng = state->predictor >= 10; - int n; - - while (state->rp < state->wp && p < ep) - *p++ = *state->rp++; - - while (p < ep) - { - n = fz_read(state->chain, state->in, state->stride + ispng); - if (n == 0) - return p - buf; - - if (state->predictor == 1) - memcpy(state->out, state->in, n); - else if (state->predictor == 2) - fz_predict_tiff(state, state->out, state->in, n); - else - { - fz_predict_png(state, state->out, state->in + 1, n - 1, state->in[0]); - memcpy(state->ref, state->out, state->stride); - } - - state->rp = state->out; - state->wp = state->out + n - ispng; - - while (state->rp < state->wp && p < ep) - *p++ = *state->rp++; - } - - return p - buf; -} - -static void -close_predict(fz_context *ctx, void *state_) -{ - fz_predict *state = (fz_predict *)state_; - fz_close(state->chain); - fz_free(ctx, state->in); - fz_free(ctx, state->out); - fz_free(ctx, state->ref); - fz_free(ctx, state); -} - -/* Default values: predictor = 1, columns = 1, colors = 1, bpc = 8 */ -fz_stream * -fz_open_predict(fz_stream *chain, int predictor, int columns, int colors, int bpc) -{ - fz_context *ctx = chain->ctx; - fz_predict *state = NULL; - - fz_var(state); - - if (predictor < 1) - predictor = 1; - if (columns < 1) - columns = 1; - if (colors < 1) - colors = 1; - if (bpc < 1) - bpc = 8; - - fz_try(ctx) - { - state = fz_malloc_struct(ctx, fz_predict); - state->in = NULL; - state->out = NULL; - state->chain = chain; - - state->predictor = predictor; - state->columns = columns; - state->colors = colors; - state->bpc = bpc; - - if (state->predictor != 1 && state->predictor != 2 && - state->predictor != 10 && state->predictor != 11 && - state->predictor != 12 && state->predictor != 13 && - state->predictor != 14 && state->predictor != 15) - { - fz_warn(ctx, "invalid predictor: %d", state->predictor); - state->predictor = 1; - } - - state->stride = (state->bpc * state->colors * state->columns + 7) / 8; - state->bpp = (state->bpc * state->colors + 7) / 8; - - state->in = fz_malloc(ctx, state->stride + 1); - state->out = fz_malloc(ctx, state->stride); - state->ref = fz_malloc(ctx, state->stride); - state->rp = state->out; - state->wp = state->out; - - memset(state->ref, 0, state->stride); - } - fz_catch(ctx) - { - if (state) - { - fz_free(ctx, state->in); - fz_free(ctx, state->out); - } - fz_free(ctx, state); - fz_close(chain); - fz_rethrow(ctx); - } - - return fz_new_stream(ctx, state, read_predict, close_predict); -} diff --git a/fitz/image_jpeg.c b/fitz/image_jpeg.c deleted file mode 100644 index b968c0cf..00000000 --- a/fitz/image_jpeg.c +++ /dev/null @@ -1,111 +0,0 @@ -#include "mupdf/fitz.h" - -#include - -static void error_exit(j_common_ptr cinfo) -{ - char msg[JMSG_LENGTH_MAX]; - fz_context *ctx = (fz_context *)cinfo->client_data; - - cinfo->err->format_message(cinfo, msg); - fz_throw(ctx, FZ_ERROR_GENERIC, "jpeg error: %s", msg); -} - -static void init_source(j_decompress_ptr cinfo) -{ - /* nothing to do */ -} - -static void term_source(j_decompress_ptr cinfo) -{ - /* nothing to do */ -} - -static boolean fill_input_buffer(j_decompress_ptr cinfo) -{ - static unsigned char eoi[2] = { 0xFF, JPEG_EOI }; - struct jpeg_source_mgr *src = cinfo->src; - src->next_input_byte = eoi; - src->bytes_in_buffer = 2; - return 1; -} - -static void skip_input_data(j_decompress_ptr cinfo, long num_bytes) -{ - struct jpeg_source_mgr *src = cinfo->src; - if (num_bytes > 0) - { - size_t skip = (size_t)num_bytes; /* size_t may be 64bit */ - if (skip > src->bytes_in_buffer) - skip = (size_t)src->bytes_in_buffer; - src->next_input_byte += skip; - src->bytes_in_buffer -= skip; - } -} - -void -fz_load_jpeg_info(fz_context *ctx, unsigned char *rbuf, int rlen, int *xp, int *yp, int *xresp, int *yresp, fz_colorspace **cspacep) -{ - struct jpeg_decompress_struct cinfo; - struct jpeg_error_mgr err; - struct jpeg_source_mgr src; - - fz_try(ctx) - { - cinfo.client_data = ctx; - cinfo.err = jpeg_std_error(&err); - err.error_exit = error_exit; - - jpeg_create_decompress(&cinfo); - - cinfo.src = &src; - src.init_source = init_source; - src.fill_input_buffer = fill_input_buffer; - src.skip_input_data = skip_input_data; - src.resync_to_restart = jpeg_resync_to_restart; - src.term_source = term_source; - src.next_input_byte = rbuf; - src.bytes_in_buffer = rlen; - - jpeg_read_header(&cinfo, 1); - - if (cinfo.num_components == 1) - *cspacep = fz_device_gray(ctx); - else if (cinfo.num_components == 3) - *cspacep = fz_device_rgb(ctx); - else if (cinfo.num_components == 4) - *cspacep = fz_device_cmyk(ctx); - else - fz_throw(ctx, FZ_ERROR_GENERIC, "bad number of components in jpeg: %d", cinfo.num_components); - - *xp = cinfo.image_width; - *yp = cinfo.image_height; - - if (cinfo.density_unit == 1) - { - *xresp = cinfo.X_density; - *yresp = cinfo.Y_density; - } - else if (cinfo.density_unit == 2) - { - *xresp = cinfo.X_density * 254 / 100; - *yresp = cinfo.Y_density * 254 / 100; - } - else - { - *xresp = 0; - *yresp = 0; - } - - if (*xresp <= 0) *xresp = 72; - if (*yresp <= 0) *yresp = 72; - } - fz_always(ctx) - { - jpeg_destroy_decompress(&cinfo); - } - fz_catch(ctx) - { - fz_rethrow(ctx); - } -} diff --git a/fitz/image_jpx.c b/fitz/image_jpx.c deleted file mode 100644 index cd41277d..00000000 --- a/fitz/image_jpx.c +++ /dev/null @@ -1,253 +0,0 @@ -#include "mupdf/fitz.h" - -/* Without the definition of OPJ_STATIC, compilation fails on windows - * due to the use of __stdcall. We believe it is required on some - * linux toolchains too. */ -#define OPJ_STATIC -#ifndef _MSC_VER -#define OPJ_HAVE_STDINT_H -#endif - -#include - -static void fz_opj_error_callback(const char *msg, void *client_data) -{ - fz_context *ctx = (fz_context *)client_data; - fz_warn(ctx, "openjpeg error: %s", msg); -} - -static void fz_opj_warning_callback(const char *msg, void *client_data) -{ - fz_context *ctx = (fz_context *)client_data; - fz_warn(ctx, "openjpeg warning: %s", msg); -} - -static void fz_opj_info_callback(const char *msg, void *client_data) -{ - /* fz_warn("openjpeg info: %s", msg); */ -} - -typedef struct stream_block_s -{ - unsigned char *data; - int size; - int pos; -} stream_block; - -OPJ_SIZE_T stream_read(void * p_buffer, OPJ_SIZE_T p_nb_bytes, void * p_user_data) -{ - stream_block *sb = (stream_block *)p_user_data; - int len; - - len = sb->size - sb->pos; - if (len < 0) - len = 0; - if (len == 0) - return (OPJ_SIZE_T)-1; /* End of file! */ - if ((OPJ_SIZE_T)len > p_nb_bytes) - len = p_nb_bytes; - memcpy(p_buffer, sb->data + sb->pos, len); - sb->pos += len; - return len; -} - -OPJ_OFF_T stream_skip(OPJ_OFF_T skip, void * p_user_data) -{ - stream_block *sb = (stream_block *)p_user_data; - - if (skip > sb->size - sb->pos) - skip = sb->size - sb->pos; - sb->pos += skip; - return sb->pos; -} - -OPJ_BOOL stream_seek(OPJ_OFF_T seek_pos, void * p_user_data) -{ - stream_block *sb = (stream_block *)p_user_data; - - if (seek_pos > sb->size) - return OPJ_FALSE; - sb->pos = seek_pos; - return OPJ_TRUE; -} - -fz_pixmap * -fz_load_jpx(fz_context *ctx, unsigned char *data, int size, fz_colorspace *defcs, int indexed) -{ - fz_pixmap *img; - fz_colorspace *origcs; - opj_dparameters_t params; - opj_codec_t *codec; - opj_image_t *jpx; - opj_stream_t *stream; - fz_colorspace *colorspace; - unsigned char *p; - OPJ_CODEC_FORMAT format; - int a, n, w, h, depth, sgnd; - int x, y, k, v; - stream_block sb; - - if (size < 2) - fz_throw(ctx, FZ_ERROR_GENERIC, "not enough data to determine image format"); - - /* Check for SOC marker -- if found we have a bare J2K stream */ - if (data[0] == 0xFF && data[1] == 0x4F) - format = OPJ_CODEC_J2K; - else - format = OPJ_CODEC_JP2; - - opj_set_default_decoder_parameters(¶ms); - if (indexed) - params.flags |= OPJ_DPARAMETERS_IGNORE_PCLR_CMAP_CDEF_FLAG; - - codec = opj_create_decompress(format); - opj_set_info_handler(codec, fz_opj_info_callback, ctx); - opj_set_warning_handler(codec, fz_opj_warning_callback, ctx); - opj_set_error_handler(codec, fz_opj_error_callback, ctx); - if (!opj_setup_decoder(codec, ¶ms)) - { - fz_throw(ctx, FZ_ERROR_GENERIC, "j2k decode failed"); - } - - stream = opj_stream_default_create(OPJ_TRUE); - sb.data = data; - sb.pos = 0; - sb.size = size; - - opj_stream_set_read_function(stream, stream_read); - opj_stream_set_skip_function(stream, stream_skip); - opj_stream_set_seek_function(stream, stream_seek); - opj_stream_set_user_data(stream, &sb); - /* Set the length to avoid an assert */ - opj_stream_set_user_data_length(stream, size); - - if (!opj_read_header(stream, codec, &jpx)) - { - opj_stream_destroy(stream); - opj_destroy_codec(codec); - fz_throw(ctx, FZ_ERROR_GENERIC, "Failed to read JPX header"); - } - - if (!opj_decode(codec, stream, jpx)) - { - opj_stream_destroy(stream); - opj_destroy_codec(codec); - opj_image_destroy(jpx); - fz_throw(ctx, FZ_ERROR_GENERIC, "Failed to decode JPX image"); - } - - opj_stream_destroy(stream); - opj_destroy_codec(codec); - - /* jpx should never be NULL here, but check anyway */ - if (!jpx) - fz_throw(ctx, FZ_ERROR_GENERIC, "opj_decode failed"); - - for (k = 1; k < (int)jpx->numcomps; k++) - { - if (jpx->comps[k].w != jpx->comps[0].w) - { - opj_image_destroy(jpx); - fz_throw(ctx, FZ_ERROR_GENERIC, "image components have different width"); - } - if (jpx->comps[k].h != jpx->comps[0].h) - { - opj_image_destroy(jpx); - fz_throw(ctx, FZ_ERROR_GENERIC, "image components have different height"); - } - if (jpx->comps[k].prec != jpx->comps[0].prec) - { - opj_image_destroy(jpx); - fz_throw(ctx, FZ_ERROR_GENERIC, "image components have different precision"); - } - } - - n = jpx->numcomps; - w = jpx->comps[0].w; - h = jpx->comps[0].h; - depth = jpx->comps[0].prec; - sgnd = jpx->comps[0].sgnd; - - if (jpx->color_space == OPJ_CLRSPC_SRGB && n == 4) { n = 3; a = 1; } - else if (jpx->color_space == OPJ_CLRSPC_SYCC && n == 4) { n = 3; a = 1; } - else if (n == 2) { n = 1; a = 1; } - else if (n > 4) { n = 4; a = 1; } - else { a = 0; } - - origcs = defcs; - if (defcs) - { - if (defcs->n == n) - { - colorspace = defcs; - } - else - { - fz_warn(ctx, "jpx file and dict colorspaces do not match"); - defcs = NULL; - } - } - - if (!defcs) - { - switch (n) - { - case 1: colorspace = fz_device_gray(ctx); break; - case 3: colorspace = fz_device_rgb(ctx); break; - case 4: colorspace = fz_device_cmyk(ctx); break; - } - } - - fz_try(ctx) - { - img = fz_new_pixmap(ctx, colorspace, w, h); - } - fz_catch(ctx) - { - opj_image_destroy(jpx); - fz_rethrow_message(ctx, "out of memory loading jpx"); - } - - p = img->samples; - for (y = 0; y < h; y++) - { - for (x = 0; x < w; x++) - { - for (k = 0; k < n + a; k++) - { - v = jpx->comps[k].data[y * w + x]; - if (sgnd) - v = v + (1 << (depth - 1)); - if (depth > 8) - v = v >> (depth - 8); - *p++ = v; - } - if (!a) - *p++ = 255; - } - } - - opj_image_destroy(jpx); - - if (a) - { - if (n == 4) - { - fz_pixmap *tmp = fz_new_pixmap(ctx, fz_device_rgb(ctx), w, h); - fz_convert_pixmap(ctx, tmp, img); - fz_drop_pixmap(ctx, img); - img = tmp; - } - fz_premultiply_pixmap(ctx, img); - } - - if (origcs != defcs) - { - fz_pixmap *tmp = fz_new_pixmap(ctx, origcs, w, h); - fz_convert_pixmap(ctx, tmp, img); - fz_drop_pixmap(ctx, img); - img = tmp; - } - - return img; -} diff --git a/fitz/image_png.c b/fitz/image_png.c deleted file mode 100644 index ad22e128..00000000 --- a/fitz/image_png.c +++ /dev/null @@ -1,599 +0,0 @@ -#include "mupdf/fitz.h" - -#include - -struct info -{ - fz_context *ctx; - unsigned int width, height, depth, n; - int interlace, indexed; - unsigned int size; - unsigned char *samples; - unsigned char palette[256*4]; - int transparency; - int trns[3]; - int xres, yres; -}; - -static inline unsigned int getuint(unsigned char *p) -{ - return p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3]; -} - -static inline int getcomp(unsigned char *line, int x, int bpc) -{ - switch (bpc) - { - case 1: return (line[x >> 3] >> ( 7 - (x & 7) ) ) & 1; - case 2: return (line[x >> 2] >> ( ( 3 - (x & 3) ) << 1 ) ) & 3; - case 4: return (line[x >> 1] >> ( ( 1 - (x & 1) ) << 2 ) ) & 15; - case 8: return line[x]; - case 16: return line[x << 1] << 8 | line[(x << 1) + 1]; - } - return 0; -} - -static inline void putcomp(unsigned char *line, int x, int bpc, int value) -{ - int maxval = (1 << bpc) - 1; - - switch (bpc) - { - case 1: line[x >> 3] &= ~(maxval << (7 - (x & 7))); break; - case 2: line[x >> 2] &= ~(maxval << ((3 - (x & 3)) << 1)); break; - case 4: line[x >> 1] &= ~(maxval << ((1 - (x & 1)) << 2)); break; - } - - switch (bpc) - { - case 1: line[x >> 3] |= value << (7 - (x & 7)); break; - case 2: line[x >> 2] |= value << ((3 - (x & 3)) << 1); break; - case 4: line[x >> 1] |= value << ((1 - (x & 1)) << 2); break; - case 8: line[x] = value; break; - case 16: line[x << 1] = value >> 8; line[(x << 1) + 1] = value & 0xFF; break; - } -} - -static const unsigned char png_signature[8] = -{ - 137, 80, 78, 71, 13, 10, 26, 10 -}; - -static void *zalloc(void *opaque, unsigned int items, unsigned int size) -{ - return fz_malloc_array(opaque, items, size); -} - -static void zfree(void *opaque, void *address) -{ - fz_free(opaque, address); -} - -static inline int paeth(int a, int b, int c) -{ - /* The definitions of ac and bc are correct, not a typo. */ - int ac = b - c, bc = a - c, abcc = ac + bc; - int pa = (ac < 0 ? -ac : ac); - int pb = (bc < 0 ? -bc : bc); - int pc = (abcc < 0 ? -abcc : abcc); - return pa <= pb && pa <= pc ? a : pb <= pc ? b : c; -} - -static void -png_predict(unsigned char *samples, unsigned int width, unsigned int height, unsigned int n, unsigned int depth) -{ - unsigned int stride = (width * n * depth + 7) / 8; - unsigned int bpp = (n * depth + 7) / 8; - unsigned int i, row; - - for (row = 0; row < height; row ++) - { - unsigned char *src = samples + (unsigned int)((stride + 1) * row); - unsigned char *dst = samples + (unsigned int)(stride * row); - - unsigned char *a = dst; - unsigned char *b = dst - stride; - unsigned char *c = dst - stride; - - switch (*src++) - { - default: - case 0: /* None */ - for (i = 0; i < stride; i++) - *dst++ = *src++; - break; - - case 1: /* Sub */ - for (i = 0; i < bpp; i++) - *dst++ = *src++; - for (i = bpp; i < stride; i++) - *dst++ = *src++ + *a++; - break; - - case 2: /* Up */ - if (row == 0) - for (i = 0; i < stride; i++) - *dst++ = *src++; - else - for (i = 0; i < stride; i++) - *dst++ = *src++ + *b++; - break; - - case 3: /* Average */ - if (row == 0) - { - for (i = 0; i < bpp; i++) - *dst++ = *src++; - for (i = bpp; i < stride; i++) - *dst++ = *src++ + (*a++ >> 1); - } - else - { - for (i = 0; i < bpp; i++) - *dst++ = *src++ + (*b++ >> 1); - for (i = bpp; i < stride; i++) - *dst++ = *src++ + ((*b++ + *a++) >> 1); - } - break; - - case 4: /* Paeth */ - if (row == 0) - { - for (i = 0; i < bpp; i++) - *dst++ = *src++ + paeth(0, 0, 0); - for (i = bpp; i < stride; i++) - *dst++ = *src++ + paeth(*a++, 0, 0); - } - else - { - for (i = 0; i < bpp; i++) - *dst++ = *src++ + paeth(0, *b++, 0); - for (i = bpp; i < stride; i++) - *dst++ = *src++ + paeth(*a++, *b++, *c++); - } - break; - } - } -} - -static const unsigned int adam7_ix[7] = { 0, 4, 0, 2, 0, 1, 0 }; -static const unsigned int adam7_dx[7] = { 8, 8, 4, 4, 2, 2, 1 }; -static const unsigned int adam7_iy[7] = { 0, 0, 4, 0, 2, 0, 1 }; -static const unsigned int adam7_dy[7] = { 8, 8, 8, 4, 4, 2, 2 }; - -static void -png_deinterlace_passes(struct info *info, unsigned int *w, unsigned int *h, unsigned int *ofs) -{ - int p, bpp = info->depth * info->n; - ofs[0] = 0; - for (p = 0; p < 7; p++) - { - w[p] = (info->width + adam7_dx[p] - adam7_ix[p] - 1) / adam7_dx[p]; - h[p] = (info->height + adam7_dy[p] - adam7_iy[p] - 1) / adam7_dy[p]; - if (w[p] == 0) h[p] = 0; - if (h[p] == 0) w[p] = 0; - if (w[p] && h[p]) - ofs[p + 1] = ofs[p] + h[p] * (1 + (w[p] * bpp + 7) / 8); - else - ofs[p + 1] = ofs[p]; - } -} - -static void -png_deinterlace(struct info *info, unsigned int *passw, unsigned int *passh, unsigned int *passofs) -{ - unsigned int n = info->n; - unsigned int depth = info->depth; - unsigned int stride = (info->width * n * depth + 7) / 8; - unsigned char *output; - unsigned int p, x, y, k; - - output = fz_malloc_array(info->ctx, info->height, stride); - - for (p = 0; p < 7; p++) - { - unsigned char *sp = info->samples + (passofs[p]); - unsigned int w = passw[p]; - unsigned int h = passh[p]; - - png_predict(sp, w, h, n, depth); - for (y = 0; y < h; y++) - { - for (x = 0; x < w; x++) - { - int outx = x * adam7_dx[p] + adam7_ix[p]; - int outy = y * adam7_dy[p] + adam7_iy[p]; - unsigned char *dp = output + outy * stride; - for (k = 0; k < n; k++) - { - int v = getcomp(sp, x * n + k, depth); - putcomp(dp, outx * n + k, depth, v); - } - } - sp += (w * depth * n + 7) / 8; - } - } - - fz_free(info->ctx, info->samples); - info->samples = output; -} - -static void -png_read_ihdr(struct info *info, unsigned char *p, unsigned int size) -{ - int color, compression, filter; - - if (size != 13) - fz_throw(info->ctx, FZ_ERROR_GENERIC, "IHDR chunk is the wrong size"); - - info->width = getuint(p + 0); - info->height = getuint(p + 4); - info->depth = p[8]; - - color = p[9]; - compression = p[10]; - filter = p[11]; - info->interlace = p[12]; - - if (info->width <= 0) - fz_throw(info->ctx, FZ_ERROR_GENERIC, "image width must be > 0"); - if (info->height <= 0) - fz_throw(info->ctx, FZ_ERROR_GENERIC, "image height must be > 0"); - - if (info->depth != 1 && info->depth != 2 && info->depth != 4 && - info->depth != 8 && info->depth != 16) - fz_throw(info->ctx, FZ_ERROR_GENERIC, "image bit depth must be one of 1, 2, 4, 8, 16"); - if (color == 2 && info->depth < 8) - fz_throw(info->ctx, FZ_ERROR_GENERIC, "illegal bit depth for truecolor"); - if (color == 3 && info->depth > 8) - fz_throw(info->ctx, FZ_ERROR_GENERIC, "illegal bit depth for indexed"); - if (color == 4 && info->depth < 8) - fz_throw(info->ctx, FZ_ERROR_GENERIC, "illegal bit depth for grayscale with alpha"); - if (color == 6 && info->depth < 8) - fz_throw(info->ctx, FZ_ERROR_GENERIC, "illegal bit depth for truecolor with alpha"); - - info->indexed = 0; - if (color == 0) /* gray */ - info->n = 1; - else if (color == 2) /* rgb */ - info->n = 3; - else if (color == 4) /* gray alpha */ - info->n = 2; - else if (color == 6) /* rgb alpha */ - info->n = 4; - else if (color == 3) /* indexed */ - { - info->indexed = 1; - info->n = 1; - } - else - fz_throw(info->ctx, FZ_ERROR_GENERIC, "unknown color type"); - - if (compression != 0) - fz_throw(info->ctx, FZ_ERROR_GENERIC, "unknown compression method"); - if (filter != 0) - fz_throw(info->ctx, FZ_ERROR_GENERIC, "unknown filter method"); - if (info->interlace != 0 && info->interlace != 1) - fz_throw(info->ctx, FZ_ERROR_GENERIC, "interlace method not supported"); -} - -static void -png_read_plte(struct info *info, unsigned char *p, unsigned int size) -{ - int n = size / 3; - int i; - - if (n > 256) - { - fz_warn(info->ctx, "too many samples in palette"); - n = 256; - } - - for (i = 0; i < n; i++) - { - info->palette[i * 4] = p[i * 3]; - info->palette[i * 4 + 1] = p[i * 3 + 1]; - info->palette[i * 4 + 2] = p[i * 3 + 2]; - } - - /* Fill in any missing palette entries */ - for (; i < 256; i++) - { - info->palette[i * 4] = 0; - info->palette[i * 4 + 1] = 0; - info->palette[i * 4 + 2] = 0; - } -} - -static void -png_read_trns(struct info *info, unsigned char *p, unsigned int size) -{ - unsigned int i; - - info->transparency = 1; - - if (info->indexed) - { - if (size > 256) - { - fz_warn(info->ctx, "too many samples in transparency table"); - size = 256; - } - for (i = 0; i < size; i++) - info->palette[i * 4 + 3] = p[i]; - /* Fill in any missing entries */ - for (; i < 256; i++) - info->palette[i * 4 + 3] = 255; - } - else - { - if (size != info->n * 2) - fz_throw(info->ctx, FZ_ERROR_GENERIC, "tRNS chunk is the wrong size"); - for (i = 0; i < info->n; i++) - info->trns[i] = (p[i * 2] << 8 | p[i * 2 + 1]) & ((1 << info->depth) - 1); - } -} - -static void -png_read_idat(struct info *info, unsigned char *p, unsigned int size, z_stream *stm) -{ - int code; - - stm->next_in = p; - stm->avail_in = size; - - code = inflate(stm, Z_SYNC_FLUSH); - if (code != Z_OK && code != Z_STREAM_END) - fz_throw(info->ctx, FZ_ERROR_GENERIC, "zlib error: %s", stm->msg); - if (stm->avail_in != 0) - { - if (stm->avail_out == 0) - fz_throw(info->ctx, FZ_ERROR_GENERIC, "ran out of output before input"); - fz_throw(info->ctx, FZ_ERROR_GENERIC, "inflate did not consume buffer (%d remaining)", stm->avail_in); - } -} - -static void -png_read_phys(struct info *info, unsigned char *p, unsigned int size) -{ - if (size != 9) - fz_throw(info->ctx, FZ_ERROR_GENERIC, "pHYs chunk is the wrong size"); - if (p[8] == 1) - { - info->xres = getuint(p) * 254 / 10000; - info->yres = getuint(p + 4) * 254 / 10000; - } -} - -static void -png_read_image(fz_context *ctx, struct info *info, unsigned char *p, unsigned int total) -{ - unsigned int passw[7], passh[7], passofs[8]; - unsigned int code, size; - z_stream stm; - - memset(info, 0, sizeof (struct info)); - info->ctx = ctx; - memset(info->palette, 255, sizeof(info->palette)); - info->xres = 96; - info->yres = 96; - - /* Read signature */ - - if (total < 8 + 12 || memcmp(p, png_signature, 8)) - fz_throw(ctx, FZ_ERROR_GENERIC, "not a png image (wrong signature)"); - - p += 8; - total -= 8; - - /* Read IHDR chunk (must come first) */ - - size = getuint(p); - if (total < 12 || size > total - 12) - fz_throw(ctx, FZ_ERROR_GENERIC, "premature end of data in png image"); - - if (!memcmp(p + 4, "IHDR", 4)) - png_read_ihdr(info, p + 8, size); - else - fz_throw(ctx, FZ_ERROR_GENERIC, "png file must start with IHDR chunk"); - - p += size + 12; - total -= size + 12; - - /* Prepare output buffer */ - - if (!info->interlace) - { - info->size = info->height * (1 + (info->width * info->n * info->depth + 7) / 8); - } - else - { - png_deinterlace_passes(info, passw, passh, passofs); - info->size = passofs[7]; - } - - info->samples = fz_malloc(ctx, info->size); - - stm.zalloc = zalloc; - stm.zfree = zfree; - stm.opaque = ctx; - - stm.next_out = info->samples; - stm.avail_out = info->size; - - code = inflateInit(&stm); - if (code != Z_OK) - { - fz_free(ctx, info->samples); - fz_throw(ctx, FZ_ERROR_GENERIC, "zlib error: %s", stm.msg); - } - - fz_try(ctx) - { - /* Read remaining chunks until IEND */ - while (total > 8) - { - size = getuint(p); - - if (total < 12 || size > total - 12) - fz_throw(ctx, FZ_ERROR_GENERIC, "premature end of data in png image"); - - if (!memcmp(p + 4, "PLTE", 4)) - png_read_plte(info, p + 8, size); - if (!memcmp(p + 4, "tRNS", 4)) - png_read_trns(info, p + 8, size); - if (!memcmp(p + 4, "pHYs", 4)) - png_read_phys(info, p + 8, size); - if (!memcmp(p + 4, "IDAT", 4)) - png_read_idat(info, p + 8, size, &stm); - if (!memcmp(p + 4, "IEND", 4)) - break; - - p += size + 12; - total -= size + 12; - } - } - fz_catch(ctx) - { - inflateEnd(&stm); - fz_free(ctx, info->samples); - fz_rethrow(ctx); - } - - code = inflateEnd(&stm); - if (code != Z_OK) - { - fz_free(ctx, info->samples); - fz_throw(ctx, FZ_ERROR_GENERIC, "zlib error: %s", stm.msg); - } - - /* Apply prediction filter and deinterlacing */ - fz_try(ctx) - { - if (!info->interlace) - png_predict(info->samples, info->width, info->height, info->n, info->depth); - else - png_deinterlace(info, passw, passh, passofs); - } - fz_catch(ctx) - { - fz_free(ctx, info->samples); - fz_rethrow(ctx); - } -} - -static fz_pixmap * -png_expand_palette(fz_context *ctx, struct info *info, fz_pixmap *src) -{ - fz_pixmap *dst = fz_new_pixmap(ctx, fz_device_rgb(ctx), src->w, src->h); - unsigned char *sp = src->samples; - unsigned char *dp = dst->samples; - unsigned int x, y; - - dst->xres = src->xres; - dst->yres = src->yres; - - for (y = info->height; y > 0; y--) - { - for (x = info->width; x > 0; x--) - { - int v = *sp << 2; - *dp++ = info->palette[v]; - *dp++ = info->palette[v + 1]; - *dp++ = info->palette[v + 2]; - *dp++ = info->palette[v + 3]; - sp += 2; - } - } - - fz_drop_pixmap(info->ctx, src); - return dst; -} - -static void -png_mask_transparency(struct info *info, fz_pixmap *dst) -{ - unsigned int stride = (info->width * info->n * info->depth + 7) / 8; - unsigned int depth = info->depth; - unsigned int n = info->n; - unsigned int x, y, k, t; - - for (y = 0; y < info->height; y++) - { - unsigned char *sp = info->samples + (unsigned int)(y * stride); - unsigned char *dp = dst->samples + (unsigned int)(y * dst->w * dst->n); - for (x = 0; x < info->width; x++) - { - t = 1; - for (k = 0; k < n; k++) - if (getcomp(sp, x * n + k, depth) != info->trns[k]) - t = 0; - if (t) - dp[x * dst->n + dst->n - 1] = 0; - } - } -} - -fz_pixmap * -fz_load_png(fz_context *ctx, unsigned char *p, int total) -{ - fz_pixmap *image; - fz_colorspace *colorspace; - struct info png; - int stride; - - png_read_image(ctx, &png, p, total); - - if (png.n == 3 || png.n == 4) - colorspace = fz_device_rgb(ctx); - else - colorspace = fz_device_gray(ctx); - - stride = (png.width * png.n * png.depth + 7) / 8; - - fz_try(ctx) - { - image = fz_new_pixmap(ctx, colorspace, png.width, png.height); - } - fz_catch(ctx) - { - fz_free(png.ctx, png.samples); - fz_rethrow_message(ctx, "out of memory loading png"); - } - - image->xres = png.xres; - image->yres = png.yres; - - fz_unpack_tile(image, png.samples, png.n, png.depth, stride, png.indexed); - - if (png.indexed) - image = png_expand_palette(ctx, &png, image); - else if (png.transparency) - png_mask_transparency(&png, image); - - if (png.transparency || png.n == 2 || png.n == 4) - fz_premultiply_pixmap(png.ctx, image); - - fz_free(png.ctx, png.samples); - - return image; -} - -void -fz_load_png_info(fz_context *ctx, unsigned char *p, int total, int *wp, int *hp, int *xresp, int *yresp, fz_colorspace **cspacep) -{ - struct info png; - - png_read_image(ctx, &png, p, total); - - if (png.n == 3 || png.n == 4) - *cspacep = fz_device_rgb(ctx); - else - *cspacep = fz_device_gray(ctx); - - *wp = png.width; - *hp = png.height; - *xresp = png.xres; - *yresp = png.xres; - fz_free(png.ctx, png.samples); -} diff --git a/fitz/image_tiff.c b/fitz/image_tiff.c deleted file mode 100644 index 5806bc00..00000000 --- a/fitz/image_tiff.c +++ /dev/null @@ -1,867 +0,0 @@ -#include "mupdf/fitz.h" - -/* - * TIFF image loader. Should be enough to support TIFF files in XPS. - * Baseline TIFF 6.0 plus CMYK, LZW, Flate and JPEG support. - * Limited bit depths (1,2,4,8). - * Limited planar configurations (1=chunky). - * No tiles (easy fix if necessary). - * TODO: RGBPal images - */ - -struct tiff -{ - fz_context *ctx; - - /* "file" */ - unsigned char *bp, *rp, *ep; - - /* byte order */ - unsigned order; - - /* where we can find the strips of image data */ - unsigned rowsperstrip; - unsigned *stripoffsets; - unsigned *stripbytecounts; - - /* colormap */ - unsigned *colormap; - - unsigned stripoffsetslen; - unsigned stripbytecountslen; - unsigned colormaplen; - - /* assorted tags */ - unsigned subfiletype; - unsigned photometric; - unsigned compression; - unsigned imagewidth; - unsigned imagelength; - unsigned samplesperpixel; - unsigned bitspersample; - unsigned planar; - unsigned extrasamples; - unsigned xresolution; - unsigned yresolution; - unsigned resolutionunit; - unsigned fillorder; - unsigned g3opts; - unsigned g4opts; - unsigned predictor; - - unsigned ycbcrsubsamp[2]; - - unsigned char *jpegtables; /* point into "file" buffer */ - unsigned jpegtableslen; - - unsigned char *profile; - int profilesize; - - /* decoded data */ - fz_colorspace *colorspace; - unsigned char *samples; - int stride; -}; - -enum -{ - TII = 0x4949, /* 'II' */ - TMM = 0x4d4d, /* 'MM' */ - TBYTE = 1, - TASCII = 2, - TSHORT = 3, - TLONG = 4, - TRATIONAL = 5 -}; - -#define NewSubfileType 254 -#define ImageWidth 256 -#define ImageLength 257 -#define BitsPerSample 258 -#define Compression 259 -#define PhotometricInterpretation 262 -#define FillOrder 266 -#define StripOffsets 273 -#define SamplesPerPixel 277 -#define RowsPerStrip 278 -#define StripByteCounts 279 -#define XResolution 282 -#define YResolution 283 -#define PlanarConfiguration 284 -#define T4Options 292 -#define T6Options 293 -#define ResolutionUnit 296 -#define Predictor 317 -#define ColorMap 320 -#define TileWidth 322 -#define TileLength 323 -#define TileOffsets 324 -#define TileByteCounts 325 -#define ExtraSamples 338 -#define JPEGTables 347 -#define YCbCrSubSampling 520 -#define ICCProfile 34675 - -static const unsigned char bitrev[256] = -{ - 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, - 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, - 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, - 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, - 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, - 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, - 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, - 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, - 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, - 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, - 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, - 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, - 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, - 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, - 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, - 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, - 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, - 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, - 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, - 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, - 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, - 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, - 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, - 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, - 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, - 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, - 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, - 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, - 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, - 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, - 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, - 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff -}; - -static void -fz_decode_tiff_uncompressed(struct tiff *tiff, fz_stream *stm, unsigned char *wp, int wlen) -{ - fz_read(stm, wp, wlen); - fz_close(stm); -} - -static void -fz_decode_tiff_packbits(struct tiff *tiff, fz_stream *chain, unsigned char *wp, int wlen) -{ - fz_stream *stm = fz_open_rld(chain); - fz_read(stm, wp, wlen); - fz_close(stm); -} - -static void -fz_decode_tiff_lzw(struct tiff *tiff, fz_stream *chain, unsigned char *wp, int wlen) -{ - fz_stream *stm = fz_open_lzwd(chain, 1); - fz_read(stm, wp, wlen); - fz_close(stm); -} - -static void -fz_decode_tiff_flate(struct tiff *tiff, fz_stream *chain, unsigned char *wp, int wlen) -{ - fz_stream *stm = fz_open_flated(chain); - fz_read(stm, wp, wlen); - fz_close(stm); -} - -static void -fz_decode_tiff_fax(struct tiff *tiff, int comp, fz_stream *chain, unsigned char *wp, int wlen) -{ - fz_stream *stm; - int black_is_1 = tiff->photometric == 0; - int k = comp == 4 ? -1 : 0; - int encoded_byte_align = comp == 2; - stm = fz_open_faxd(chain, - k, 0, encoded_byte_align, - tiff->imagewidth, tiff->imagelength, 0, black_is_1); - fz_read(stm, wp, wlen); - fz_close(stm); -} - -static void -fz_decode_tiff_jpeg(struct tiff *tiff, fz_stream *chain, unsigned char *wp, int wlen) -{ - fz_stream *stm = fz_open_dctd(chain, -1); - fz_read(stm, wp, wlen); - fz_close(stm); -} - -static inline int getcomp(unsigned char *line, int x, int bpc) -{ - switch (bpc) - { - case 1: return (line[x >> 3] >> ( 7 - (x & 7) ) ) & 1; - case 2: return (line[x >> 2] >> ( ( 3 - (x & 3) ) << 1 ) ) & 3; - case 4: return (line[x >> 1] >> ( ( 1 - (x & 1) ) << 2 ) ) & 15; - case 8: return line[x]; - case 16: return line[x << 1] << 8 | line[(x << 1) + 1]; - } - return 0; -} - -static inline void putcomp(unsigned char *line, int x, int bpc, int value) -{ - int maxval = (1 << bpc) - 1; - - switch (bpc) - { - case 1: line[x >> 3] &= ~(maxval << (7 - (x & 7))); break; - case 2: line[x >> 2] &= ~(maxval << ((3 - (x & 3)) << 1)); break; - case 4: line[x >> 1] &= ~(maxval << ((1 - (x & 1)) << 2)); break; - } - - switch (bpc) - { - case 1: line[x >> 3] |= value << (7 - (x & 7)); break; - case 2: line[x >> 2] |= value << ((3 - (x & 3)) << 1); break; - case 4: line[x >> 1] |= value << ((1 - (x & 1)) << 2); break; - case 8: line[x] = value; break; - case 16: line[x << 1] = value >> 8; line[(x << 1) + 1] = value & 0xFF; break; - } -} - -static void -fz_unpredict_tiff(unsigned char *line, int width, int comps, int bits) -{ - unsigned char left[32]; - int i, k, v; - - for (k = 0; k < comps; k++) - left[k] = 0; - - for (i = 0; i < width; i++) - { - for (k = 0; k < comps; k++) - { - v = getcomp(line, i * comps + k, bits); - v = v + left[k]; - v = v % (1 << bits); - putcomp(line, i * comps + k, bits, v); - left[k] = v; - } - } -} - -static void -fz_invert_tiff(unsigned char *line, int width, int comps, int bits, int alpha) -{ - int i, k, v; - int m = (1 << bits) - 1; - - for (i = 0; i < width; i++) - { - for (k = 0; k < comps; k++) - { - v = getcomp(line, i * comps + k, bits); - if (!alpha || k < comps - 1) - v = m - v; - putcomp(line, i * comps + k, bits, v); - } - } -} - -static void -fz_expand_tiff_colormap(struct tiff *tiff) -{ - int maxval = 1 << tiff->bitspersample; - unsigned char *samples; - unsigned char *src, *dst; - unsigned int x, y; - unsigned int stride; - - /* colormap has first all red, then all green, then all blue values */ - /* colormap values are 0..65535, bits is 4 or 8 */ - /* image can be with or without extrasamples: comps is 1 or 2 */ - - if (tiff->samplesperpixel != 1 && tiff->samplesperpixel != 2) - fz_throw(tiff->ctx, FZ_ERROR_GENERIC, "invalid number of samples for RGBPal"); - - if (tiff->bitspersample != 4 && tiff->bitspersample != 8) - fz_throw(tiff->ctx, FZ_ERROR_GENERIC, "invalid number of bits for RGBPal"); - - if (tiff->colormaplen < (unsigned)maxval * 3) - fz_throw(tiff->ctx, FZ_ERROR_GENERIC, "insufficient colormap data"); - - stride = tiff->imagewidth * (tiff->samplesperpixel + 2); - - samples = fz_malloc(tiff->ctx, stride * tiff->imagelength); - - for (y = 0; y < tiff->imagelength; y++) - { - src = tiff->samples + (unsigned int)(tiff->stride * y); - dst = samples + (unsigned int)(stride * y); - - for (x = 0; x < tiff->imagewidth; x++) - { - if (tiff->extrasamples) - { - int c = getcomp(src, x * 2, tiff->bitspersample); - int a = getcomp(src, x * 2 + 1, tiff->bitspersample); - *dst++ = tiff->colormap[c + 0] >> 8; - *dst++ = tiff->colormap[c + maxval] >> 8; - *dst++ = tiff->colormap[c + maxval * 2] >> 8; - *dst++ = a << (8 - tiff->bitspersample); - } - else - { - int c = getcomp(src, x, tiff->bitspersample); - *dst++ = tiff->colormap[c + 0] >> 8; - *dst++ = tiff->colormap[c + maxval] >> 8; - *dst++ = tiff->colormap[c + maxval * 2] >> 8; - } - } - } - - tiff->samplesperpixel += 2; - tiff->bitspersample = 8; - tiff->stride = stride; - fz_free(tiff->ctx, tiff->samples); - tiff->samples = samples; -} - -static void -fz_decode_tiff_strips(struct tiff *tiff) -{ - fz_stream *stm; - - /* switch on compression to create a filter */ - /* feed each strip to the filter */ - /* read out the data and pack the samples into a pixmap */ - - /* type 32773 / packbits -- nothing special (same row-padding as PDF) */ - /* type 2 / ccitt rle -- no EOL, no RTC, rows are byte-aligned */ - /* type 3 and 4 / g3 and g4 -- each strip starts new section */ - /* type 5 / lzw -- each strip is handled separately */ - - unsigned char *wp; - unsigned row; - unsigned strip; - unsigned i; - - if (!tiff->rowsperstrip || !tiff->stripoffsets || !tiff->stripbytecounts) - fz_throw(tiff->ctx, FZ_ERROR_GENERIC, "no image data in tiff; maybe it is tiled"); - - if (tiff->stripoffsetslen < (tiff->imagelength - 1) / tiff->rowsperstrip + 1 || - tiff->stripbytecountslen < (tiff->imagelength - 1) / tiff->rowsperstrip + 1) - fz_throw(tiff->ctx, FZ_ERROR_GENERIC, "insufficient strip offset data"); - - if (tiff->planar != 1) - fz_throw(tiff->ctx, FZ_ERROR_GENERIC, "image data is not in chunky format"); - - tiff->stride = (tiff->imagewidth * tiff->samplesperpixel * tiff->bitspersample + 7) / 8; - - switch (tiff->photometric) - { - case 0: /* WhiteIsZero -- inverted */ - tiff->colorspace = fz_device_gray(tiff->ctx); - break; - case 1: /* BlackIsZero */ - tiff->colorspace = fz_device_gray(tiff->ctx); - break; - case 2: /* RGB */ - tiff->colorspace = fz_device_rgb(tiff->ctx); - break; - case 3: /* RGBPal */ - tiff->colorspace = fz_device_rgb(tiff->ctx); - break; - case 5: /* CMYK */ - tiff->colorspace = fz_device_cmyk(tiff->ctx); - break; - case 6: /* YCbCr */ - /* it's probably a jpeg ... we let jpeg convert to rgb */ - tiff->colorspace = fz_device_rgb(tiff->ctx); - break; - default: - fz_throw(tiff->ctx, FZ_ERROR_GENERIC, "unknown photometric: %d", tiff->photometric); - } - - switch (tiff->resolutionunit) - { - case 2: - /* no unit conversion needed */ - break; - case 3: - tiff->xresolution = tiff->xresolution * 254 / 100; - tiff->yresolution = tiff->yresolution * 254 / 100; - break; - default: - tiff->xresolution = 96; - tiff->yresolution = 96; - break; - } - - /* Note xres and yres could be 0 even if unit was set. If so default to 96dpi. */ - if (tiff->xresolution == 0 || tiff->yresolution == 0) - { - tiff->xresolution = 96; - tiff->yresolution = 96; - } - - tiff->samples = fz_malloc_array(tiff->ctx, tiff->imagelength, tiff->stride); - memset(tiff->samples, 0x55, tiff->imagelength * tiff->stride); - wp = tiff->samples; - - strip = 0; - for (row = 0; row < tiff->imagelength; row += tiff->rowsperstrip) - { - unsigned offset = tiff->stripoffsets[strip]; - unsigned rlen = tiff->stripbytecounts[strip]; - unsigned wlen = tiff->stride * tiff->rowsperstrip; - unsigned char *rp = tiff->bp + offset; - - if (wp + wlen > tiff->samples + (unsigned int)(tiff->stride * tiff->imagelength)) - wlen = tiff->samples + (unsigned int)(tiff->stride * tiff->imagelength) - wp; - - if (rp + rlen > tiff->ep) - fz_throw(tiff->ctx, FZ_ERROR_GENERIC, "strip extends beyond the end of the file"); - - /* the bits are in un-natural order */ - if (tiff->fillorder == 2) - for (i = 0; i < rlen; i++) - rp[i] = bitrev[rp[i]]; - - /* the strip decoders will close this */ - stm = fz_open_memory(tiff->ctx, rp, rlen); - - switch (tiff->compression) - { - case 1: - fz_decode_tiff_uncompressed(tiff, stm, wp, wlen); - break; - case 2: - fz_decode_tiff_fax(tiff, 2, stm, wp, wlen); - break; - case 3: - fz_decode_tiff_fax(tiff, 3, stm, wp, wlen); - break; - case 4: - fz_decode_tiff_fax(tiff, 4, stm, wp, wlen); - break; - case 5: - fz_decode_tiff_lzw(tiff, stm, wp, wlen); - break; - case 6: - fz_throw(tiff->ctx, FZ_ERROR_GENERIC, "deprecated JPEG in TIFF compression not supported"); - break; - case 7: - fz_decode_tiff_jpeg(tiff, stm, wp, wlen); - break; - case 8: - fz_decode_tiff_flate(tiff, stm, wp, wlen); - break; - case 32773: - fz_decode_tiff_packbits(tiff, stm, wp, wlen); - break; - default: - fz_throw(tiff->ctx, FZ_ERROR_GENERIC, "unknown TIFF compression: %d", tiff->compression); - } - - /* scramble the bits back into original order */ - if (tiff->fillorder == 2) - for (i = 0; i < rlen; i++) - rp[i] = bitrev[rp[i]]; - - wp += tiff->stride * tiff->rowsperstrip; - strip ++; - } - - /* Predictor (only for LZW and Flate) */ - if ((tiff->compression == 5 || tiff->compression == 8) && tiff->predictor == 2) - { - unsigned char *p = tiff->samples; - for (i = 0; i < tiff->imagelength; i++) - { - fz_unpredict_tiff(p, tiff->imagewidth, tiff->samplesperpixel, tiff->bitspersample); - p += tiff->stride; - } - } - - /* RGBPal */ - if (tiff->photometric == 3 && tiff->colormap) - fz_expand_tiff_colormap(tiff); - - /* WhiteIsZero .. invert */ - if (tiff->photometric == 0) - { - unsigned char *p = tiff->samples; - for (i = 0; i < tiff->imagelength; i++) - { - fz_invert_tiff(p, tiff->imagewidth, tiff->samplesperpixel, tiff->bitspersample, tiff->extrasamples); - p += tiff->stride; - } - } - - /* Premultiplied transparency */ - if (tiff->extrasamples == 1) - { - /* In GhostXPS we undo the premultiplication here; muxps holds - * all our images premultiplied by default, so nothing to do. - */ - } - - /* Non-premultiplied transparency */ - if (tiff->extrasamples == 2) - { - /* Premultiplied files are corrected for elsewhere */ - } -} - -static inline int readbyte(struct tiff *tiff) -{ - if (tiff->rp < tiff->ep) - return *tiff->rp++; - return EOF; -} - -static inline unsigned readshort(struct tiff *tiff) -{ - unsigned a = readbyte(tiff); - unsigned b = readbyte(tiff); - if (tiff->order == TII) - return (b << 8) | a; - return (a << 8) | b; -} - -static inline unsigned readlong(struct tiff *tiff) -{ - unsigned a = readbyte(tiff); - unsigned b = readbyte(tiff); - unsigned c = readbyte(tiff); - unsigned d = readbyte(tiff); - if (tiff->order == TII) - return (d << 24) | (c << 16) | (b << 8) | a; - return (a << 24) | (b << 16) | (c << 8) | d; -} - -static void -fz_read_tiff_bytes(unsigned char *p, struct tiff *tiff, unsigned ofs, unsigned n) -{ - tiff->rp = tiff->bp + ofs; - if (tiff->rp > tiff->ep) - tiff->rp = tiff->bp; - - while (n--) - *p++ = readbyte(tiff); -} - -static void -fz_read_tiff_tag_value(unsigned *p, struct tiff *tiff, unsigned type, unsigned ofs, unsigned n) -{ - tiff->rp = tiff->bp + ofs; - if (tiff->rp > tiff->ep) - tiff->rp = tiff->bp; - - while (n--) - { - switch (type) - { - case TRATIONAL: - *p = readlong(tiff); - *p = *p / readlong(tiff); - p ++; - break; - case TBYTE: *p++ = readbyte(tiff); break; - case TSHORT: *p++ = readshort(tiff); break; - case TLONG: *p++ = readlong(tiff); break; - default: *p++ = 0; break; - } - } -} - -static void -fz_read_tiff_tag(struct tiff *tiff, unsigned offset) -{ - unsigned tag; - unsigned type; - unsigned count; - unsigned value; - - tiff->rp = tiff->bp + offset; - - tag = readshort(tiff); - type = readshort(tiff); - count = readlong(tiff); - - if ((type == TBYTE && count <= 4) || - (type == TSHORT && count <= 2) || - (type == TLONG && count <= 1)) - value = tiff->rp - tiff->bp; - else - value = readlong(tiff); - - switch (tag) - { - case NewSubfileType: - fz_read_tiff_tag_value(&tiff->subfiletype, tiff, type, value, 1); - break; - case ImageWidth: - fz_read_tiff_tag_value(&tiff->imagewidth, tiff, type, value, 1); - break; - case ImageLength: - fz_read_tiff_tag_value(&tiff->imagelength, tiff, type, value, 1); - break; - case BitsPerSample: - fz_read_tiff_tag_value(&tiff->bitspersample, tiff, type, value, 1); - break; - case Compression: - fz_read_tiff_tag_value(&tiff->compression, tiff, type, value, 1); - break; - case PhotometricInterpretation: - fz_read_tiff_tag_value(&tiff->photometric, tiff, type, value, 1); - break; - case FillOrder: - fz_read_tiff_tag_value(&tiff->fillorder, tiff, type, value, 1); - break; - case SamplesPerPixel: - fz_read_tiff_tag_value(&tiff->samplesperpixel, tiff, type, value, 1); - break; - case RowsPerStrip: - fz_read_tiff_tag_value(&tiff->rowsperstrip, tiff, type, value, 1); - break; - case XResolution: - fz_read_tiff_tag_value(&tiff->xresolution, tiff, type, value, 1); - break; - case YResolution: - fz_read_tiff_tag_value(&tiff->yresolution, tiff, type, value, 1); - break; - case PlanarConfiguration: - fz_read_tiff_tag_value(&tiff->planar, tiff, type, value, 1); - break; - case T4Options: - fz_read_tiff_tag_value(&tiff->g3opts, tiff, type, value, 1); - break; - case T6Options: - fz_read_tiff_tag_value(&tiff->g4opts, tiff, type, value, 1); - break; - case Predictor: - fz_read_tiff_tag_value(&tiff->predictor, tiff, type, value, 1); - break; - case ResolutionUnit: - fz_read_tiff_tag_value(&tiff->resolutionunit, tiff, type, value, 1); - break; - case YCbCrSubSampling: - fz_read_tiff_tag_value(tiff->ycbcrsubsamp, tiff, type, value, 2); - break; - case ExtraSamples: - fz_read_tiff_tag_value(&tiff->extrasamples, tiff, type, value, 1); - break; - - case ICCProfile: - tiff->profile = fz_malloc(tiff->ctx, count); - /* ICC profile data type is set to UNDEFINED. - * TBYTE reading not correct in fz_read_tiff_tag_value */ - fz_read_tiff_bytes(tiff->profile, tiff, value, count); - tiff->profilesize = count; - break; - - case JPEGTables: - fz_warn(tiff->ctx, "jpeg tables in tiff not implemented"); - tiff->jpegtables = tiff->bp + value; - tiff->jpegtableslen = count; - break; - - case StripOffsets: - tiff->stripoffsets = fz_malloc_array(tiff->ctx, count, sizeof(unsigned)); - fz_read_tiff_tag_value(tiff->stripoffsets, tiff, type, value, count); - tiff->stripoffsetslen = count; - break; - - case StripByteCounts: - tiff->stripbytecounts = fz_malloc_array(tiff->ctx, count, sizeof(unsigned)); - fz_read_tiff_tag_value(tiff->stripbytecounts, tiff, type, value, count); - tiff->stripbytecountslen = count; - break; - - case ColorMap: - tiff->colormap = fz_malloc_array(tiff->ctx, count, sizeof(unsigned)); - fz_read_tiff_tag_value(tiff->colormap, tiff, type, value, count); - tiff->colormaplen = count; - break; - - case TileWidth: - case TileLength: - case TileOffsets: - case TileByteCounts: - fz_throw(tiff->ctx, FZ_ERROR_GENERIC, "tiled tiffs not supported"); - - default: - /* printf("unknown tag: %d t=%d n=%d\n", tag, type, count); */ - break; - } -} - -static void -fz_swap_tiff_byte_order(unsigned char *buf, int n) -{ - int i, t; - for (i = 0; i < n; i++) - { - t = buf[i * 2 + 0]; - buf[i * 2 + 0] = buf[i * 2 + 1]; - buf[i * 2 + 1] = t; - } -} - -static void -fz_decode_tiff_header(fz_context *ctx, struct tiff *tiff, unsigned char *buf, int len) -{ - unsigned version; - unsigned offset; - unsigned count; - unsigned i; - - memset(tiff, 0, sizeof(struct tiff)); - tiff->ctx = ctx; - tiff->bp = buf; - tiff->rp = buf; - tiff->ep = buf + len; - - /* tag defaults, where applicable */ - tiff->bitspersample = 1; - tiff->compression = 1; - tiff->samplesperpixel = 1; - tiff->resolutionunit = 2; - tiff->rowsperstrip = 0xFFFFFFFF; - tiff->fillorder = 1; - tiff->planar = 1; - tiff->subfiletype = 0; - tiff->predictor = 1; - tiff->ycbcrsubsamp[0] = 2; - tiff->ycbcrsubsamp[1] = 2; - - /* - * Read IFH - */ - - /* get byte order marker */ - tiff->order = TII; - tiff->order = readshort(tiff); - if (tiff->order != TII && tiff->order != TMM) - fz_throw(tiff->ctx, FZ_ERROR_GENERIC, "not a TIFF file, wrong magic marker"); - - /* check version */ - version = readshort(tiff); - if (version != 42) - fz_throw(tiff->ctx, FZ_ERROR_GENERIC, "not a TIFF file, wrong version marker"); - - /* get offset of IFD */ - offset = readlong(tiff); - - /* - * Read IFD - */ - - tiff->rp = tiff->bp + offset; - - if (tiff->rp < tiff->bp || tiff->rp > tiff->ep) - fz_throw(tiff->ctx, FZ_ERROR_GENERIC, "invalid IFD offset %u", offset); - - count = readshort(tiff); - - if (count * 12 > (unsigned)(tiff->ep - tiff->rp)) - fz_throw(tiff->ctx, FZ_ERROR_GENERIC, "overlarge IFD entry count %u", count); - - offset += 2; - for (i = 0; i < count; i++) - { - fz_read_tiff_tag(tiff, offset); - offset += 12; - } -} - -fz_pixmap * -fz_load_tiff(fz_context *ctx, unsigned char *buf, int len) -{ - fz_pixmap *image; - struct tiff tiff; - - fz_try(ctx) - { - fz_decode_tiff_header(ctx, &tiff, buf, len); - - /* Decode the image strips */ - - if (tiff.rowsperstrip > tiff.imagelength) - tiff.rowsperstrip = tiff.imagelength; - - fz_decode_tiff_strips(&tiff); - - /* Byte swap 16-bit images to big endian if necessary */ - if (tiff.bitspersample == 16) - if (tiff.order == TII) - fz_swap_tiff_byte_order(tiff.samples, tiff.imagewidth * tiff.imagelength * tiff.samplesperpixel); - - /* Expand into fz_pixmap struct */ - image = fz_new_pixmap(tiff.ctx, tiff.colorspace, tiff.imagewidth, tiff.imagelength); - image->xres = tiff.xresolution; - image->yres = tiff.yresolution; - - fz_unpack_tile(image, tiff.samples, tiff.samplesperpixel, tiff.bitspersample, tiff.stride, 0); - - /* We should only do this on non-pre-multiplied images, but files in the wild are bad */ - if (tiff.extrasamples /* == 2 */) - { - /* CMYK is a subtractive colorspace, we want additive for premul alpha */ - if (image->n == 5) - { - fz_pixmap *rgb = fz_new_pixmap(tiff.ctx, fz_device_rgb(ctx), image->w, image->h); - fz_convert_pixmap(tiff.ctx, rgb, image); - rgb->xres = image->xres; - rgb->yres = image->yres; - fz_drop_pixmap(ctx, image); - image = rgb; - } - fz_premultiply_pixmap(ctx, image); - } - } - fz_always(ctx) - { - /* Clean up scratch memory */ - if (tiff.colormap) fz_free(ctx, tiff.colormap); - if (tiff.stripoffsets) fz_free(ctx, tiff.stripoffsets); - if (tiff.stripbytecounts) fz_free(ctx, tiff.stripbytecounts); - if (tiff.samples) fz_free(ctx, tiff.samples); - if (tiff.profile) fz_free(ctx, tiff.profile); - } - fz_catch(ctx) - { - fz_rethrow_message(ctx, "out of memory loading tiff"); - } - - return image; -} - -void -fz_load_tiff_info(fz_context *ctx, unsigned char *buf, int len, int *wp, int *hp, int *xresp, int *yresp, fz_colorspace **cspacep) -{ - struct tiff tiff; - - fz_try(ctx) - { - fz_decode_tiff_header(ctx, &tiff, buf, len); - - *wp = tiff.imagewidth; - *hp = tiff.imagelength; - *xresp = tiff.xresolution; - *yresp = tiff.yresolution; - *cspacep = tiff.colorspace; - } - fz_always(ctx) - { - /* Clean up scratch memory */ - if (tiff.colormap) fz_free(ctx, tiff.colormap); - if (tiff.stripoffsets) fz_free(ctx, tiff.stripoffsets); - if (tiff.stripbytecounts) fz_free(ctx, tiff.stripbytecounts); - if (tiff.samples) fz_free(ctx, tiff.samples); - if (tiff.profile) fz_free(ctx, tiff.profile); - } - fz_catch(ctx) - { - fz_rethrow_message(ctx, "out of memory loading tiff"); - } -} diff --git a/fitz/memento.c b/fitz/memento.c deleted file mode 100644 index 6a159f10..00000000 --- a/fitz/memento.c +++ /dev/null @@ -1,1535 +0,0 @@ -/* Copyright (C) 2001-2013 Artifex Software, Inc. - All Rights Reserved. - - This software is provided AS-IS with no warranty, either express or - implied. - - This software is distributed under license and may not be copied, modified - or distributed except as expressly authorized under the terms of that - license. Refer to licensing information at http://www.artifex.com - or contact Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134, - San Rafael, CA 94903, U.S.A., +1(415)492-9861, for further information. -*/ - -/* Inspired by Fortify by Simon P Bullen. */ - -/* Set the following if you're only looking for leaks, not memory overwrites - * to speed the operation */ -/* #define MEMENTO_LEAKONLY */ - -/* Don't keep blocks around if they'd mean losing more than a quarter of - * the freelist. */ -#define MEMENTO_FREELIST_MAX_SINGLE_BLOCK (MEMENTO_FREELIST_MAX/4) - -#define COMPILING_MEMENTO_C - -/* We have some GS specific tweaks; more for the GS build environment than - * anything else. */ -#undef MEMENTO_GS_HACKS - -#ifdef MEMENTO_GS_HACKS -/* For GS we include malloc_.h. Anyone else would just include memento.h */ -#include "malloc_.h" -#ifdef __MACH__ -#include -#else -#ifndef memset -void *memset(void *,int,size_t); -#endif -#endif -int atexit(void (*)(void)); -#else -#include "mupdf/memento.h" -#include -#include -#endif - -#ifdef MEMENTO_ANDROID -#include - -static int -android_fprintf(FILE *file, const char *fmt, ...) -{ - va_list args; - - va_start(args, fmt); - __android_log_vprint(ANDROID_LOG_ERROR,"memento", fmt, args); - va_end(args); -} - -#define fprintf android_fprintf -#define MEMENTO_STACKTRACE_METHOD 0 -#endif - -#ifndef MEMENTO_STACKTRACE_METHOD -#ifdef __GNUC__ -#define MEMENTO_STACKTRACE_METHOD 1 -#endif -#endif - -#if defined(__linux__) -#define MEMENTO_HAS_FORK -#elif defined(__APPLE__) && defined(__MACH__) -#define MEMENTO_HAS_FORK -#endif - -/* Define the underlying allocators, just in case */ -void *MEMENTO_UNDERLYING_MALLOC(size_t); -void MEMENTO_UNDERLYING_FREE(void *); -void *MEMENTO_UNDERLYING_REALLOC(void *,size_t); -void *MEMENTO_UNDERLYING_CALLOC(size_t,size_t); - -/* And some other standard functions we use. We don't include the header - * files, just in case they pull in unexpected others. */ -int atoi(const char *); -char *getenv(const char *); - -/* How far to search for pointers in each block when calculating nestings */ -/* mupdf needs at least 34000ish (sizeof(fz_shade))/ */ -#define MEMENTO_PTRSEARCH 65536 - -#ifndef MEMENTO_MAXPATTERN -#define MEMENTO_MAXPATTERN 0 -#endif - -#ifdef MEMENTO - -#ifdef MEMENTO_GS_HACKS -#include "valgrind.h" -#else -#ifdef HAVE_VALGRIND -#include "valgrind/memcheck.h" -#else -#define VALGRIND_MAKE_MEM_NOACCESS(p,s) do { } while (0==1) -#define VALGRIND_MAKE_MEM_UNDEFINED(p,s) do { } while (0==1) -#define VALGRIND_MAKE_MEM_DEFINED(p,s) do { } while (0==1) -#endif -#endif - -enum { - Memento_PreSize = 16, - Memento_PostSize = 16 -}; - -enum { - Memento_Flag_OldBlock = 1, - Memento_Flag_HasParent = 2, - Memento_Flag_BreakOnFree = 4, - Memento_Flag_BreakOnRealloc = 8 -}; - -/* When we list leaked blocks at the end of execution, we search for pointers - * between blocks in order to be able to give a nice nested view. - * Unfortunately, if you have are running your own allocator (such as - * ghostscripts chunk allocator) you can often find that the header of the - * block always contains pointers to next or previous blocks. This tends to - * mean the nesting displayed is "uninteresting" at best :) - * - * As a hack to get around this, we have a define MEMENTO_SKIP_SEARCH that - * indicates how many bytes to skip over at the start of the chunk. - * This may cause us to miss true nestings, but such is life... - */ -#ifndef MEMENTO_SEARCH_SKIP -#ifdef MEMENTO_GS_HACKS -#define MEMENTO_SEARCH_SKIP (2*sizeof(void *)) -#else -#define MEMENTO_SEARCH_SKIP 0 -#endif -#endif - -typedef struct Memento_BlkHeader Memento_BlkHeader; - -struct Memento_BlkHeader -{ - size_t rawsize; - int sequence; - int lastCheckedOK; - int flags; - Memento_BlkHeader *next; - Memento_BlkHeader *parent; /* Only used while printing out nested list */ - - const char *label; - - /* Entries for nesting display calculations */ - Memento_BlkHeader *child; - Memento_BlkHeader *sibling; - - char preblk[Memento_PreSize]; -}; - -/* In future this could (should) be a smarter data structure, like, say, - * splay trees. For now, we use a list. - */ -typedef struct Memento_Blocks -{ - Memento_BlkHeader *head; - Memento_BlkHeader **tail; -} Memento_Blocks; - -/* And our global structure */ -static struct { - int inited; - Memento_Blocks used; - Memento_Blocks free; - size_t freeListSize; - int sequence; - int paranoia; - int paranoidAt; - int countdown; - int lastChecked; - int breakAt; - int failAt; - int failing; - int nextFailAt; - int squeezeAt; - int squeezing; - int segv; - int pattern; - int nextPattern; - int patternBit; - size_t maxMemory; - size_t alloc; - size_t peakAlloc; - size_t totalAlloc; - size_t numMallocs; - size_t numFrees; - size_t numReallocs; -} globals; - -#define MEMENTO_EXTRASIZE (sizeof(Memento_BlkHeader) + Memento_PostSize) - -/* Round up size S to the next multiple of N (where N is a power of 2) */ -#define MEMENTO_ROUNDUP(S,N) ((S + N-1)&~(N-1)) - -#define MEMBLK_SIZE(s) MEMENTO_ROUNDUP(s + MEMENTO_EXTRASIZE, MEMENTO_MAXALIGN) - -#define MEMBLK_FROMBLK(B) (&((Memento_BlkHeader*)(void *)(B))[-1]) -#define MEMBLK_TOBLK(B) ((void*)(&((Memento_BlkHeader*)(void*)(B))[1])) -#define MEMBLK_POSTPTR(B) \ - (&((char *)(void *)(B))[(B)->rawsize + sizeof(Memento_BlkHeader)]) - -void Memento_breakpoint(void) -{ - /* A handy externally visible function for breakpointing */ -#if 0 /* Enable this to force automatic breakpointing */ -#ifdef DEBUG -#ifdef _MSC_VER - __asm int 3; -#endif -#endif -#endif -} - -static void Memento_addBlockHead(Memento_Blocks *blks, - Memento_BlkHeader *b, - int type) -{ - if (blks->tail == &blks->head) { - /* Adding into an empty list, means the tail changes too */ - blks->tail = &b->next; - } - b->next = blks->head; - blks->head = b; -#ifndef MEMENTO_LEAKONLY - memset(b->preblk, MEMENTO_PREFILL, Memento_PreSize); - memset(MEMBLK_POSTPTR(b), MEMENTO_POSTFILL, Memento_PostSize); -#endif - VALGRIND_MAKE_MEM_NOACCESS(MEMBLK_POSTPTR(b), Memento_PostSize); - if (type == 0) { /* malloc */ - VALGRIND_MAKE_MEM_UNDEFINED(MEMBLK_TOBLK(b), b->rawsize); - } else if (type == 1) { /* free */ - VALGRIND_MAKE_MEM_NOACCESS(MEMBLK_TOBLK(b), b->rawsize); - } - VALGRIND_MAKE_MEM_NOACCESS(b, sizeof(Memento_BlkHeader)); -} - -static void Memento_addBlockTail(Memento_Blocks *blks, - Memento_BlkHeader *b, - int type) -{ - VALGRIND_MAKE_MEM_DEFINED(blks->tail, sizeof(Memento_BlkHeader *)); - *blks->tail = b; - blks->tail = &b->next; - b->next = NULL; - VALGRIND_MAKE_MEM_NOACCESS(blks->tail, sizeof(Memento_BlkHeader *)); -#ifndef MEMENTO_LEAKONLY - memset(b->preblk, MEMENTO_PREFILL, Memento_PreSize); - memset(MEMBLK_POSTPTR(b), MEMENTO_POSTFILL, Memento_PostSize); -#endif - VALGRIND_MAKE_MEM_NOACCESS(MEMBLK_POSTPTR(b), Memento_PostSize); - if (type == 0) { /* malloc */ - VALGRIND_MAKE_MEM_UNDEFINED(MEMBLK_TOBLK(b), b->rawsize); - } else if (type == 1) { /* free */ - VALGRIND_MAKE_MEM_NOACCESS(MEMBLK_TOBLK(b), b->rawsize); - } - VALGRIND_MAKE_MEM_NOACCESS(b, sizeof(Memento_BlkHeader)); -} - -typedef struct BlkCheckData { - int found; - int preCorrupt; - int postCorrupt; - int freeCorrupt; - int index; -} BlkCheckData; - -static int Memento_Internal_checkAllocedBlock(Memento_BlkHeader *b, void *arg) -{ -#ifndef MEMENTO_LEAKONLY - int i; - char *p; - int corrupt = 0; - BlkCheckData *data = (BlkCheckData *)arg; - - p = b->preblk; - i = Memento_PreSize; - do { - corrupt |= (*p++ ^ (char)MEMENTO_PREFILL); - } while (--i); - if (corrupt) { - data->preCorrupt = 1; - } - p = MEMBLK_POSTPTR(b); - i = Memento_PreSize; - do { - corrupt |= (*p++ ^ (char)MEMENTO_POSTFILL); - } while (--i); - if (corrupt) { - data->postCorrupt = 1; - } - if ((data->freeCorrupt | data->preCorrupt | data->postCorrupt) == 0) { - b->lastCheckedOK = globals.sequence; - } - data->found |= 1; -#endif - return 0; -} - -static int Memento_Internal_checkFreedBlock(Memento_BlkHeader *b, void *arg) -{ -#ifndef MEMENTO_LEAKONLY - int i; - char *p; - BlkCheckData *data = (BlkCheckData *)arg; - - p = MEMBLK_TOBLK(b); - i = b->rawsize; - /* Attempt to speed this up by checking an (aligned) int at a time */ - do { - if (((size_t)p) & 1) { - if (*p++ != (char)MEMENTO_FREEFILL) - break; - i--; - if (i == 0) - break; - } - if ((i >= 2) && (((size_t)p) & 2)) { - if (*(short *)p != (short)(MEMENTO_FREEFILL | (MEMENTO_FREEFILL<<8))) - goto mismatch; - p += 2; - i -= 2; - if (i == 0) - break; - } - i -= 4; - while (i >= 0) { - if (*(int *)p != (MEMENTO_FREEFILL | - (MEMENTO_FREEFILL<<8) | - (MEMENTO_FREEFILL<<16) | - (MEMENTO_FREEFILL<<24))) - goto mismatch; - p += 4; - i -= 4; - } - i += 4; - if ((i >= 2) && (((size_t)p) & 2)) { - if (*(short *)p != (short)(MEMENTO_FREEFILL | (MEMENTO_FREEFILL<<8))) - goto mismatch; - p += 2; - i -= 2; - } -mismatch: - while (i) { - if (*p++ != (char)MEMENTO_FREEFILL) - break; - i--; - } - } while (0); - if (i) { - data->freeCorrupt = 1; - data->index = b->rawsize-i; - } - return Memento_Internal_checkAllocedBlock(b, arg); -#else - return 0; -#endif -} - -static void Memento_removeBlock(Memento_Blocks *blks, - Memento_BlkHeader *b) -{ - Memento_BlkHeader *head = blks->head; - Memento_BlkHeader *prev = NULL; - while ((head) && (head != b)) { - VALGRIND_MAKE_MEM_DEFINED(head, sizeof(*head)); - prev = head; - head = head->next; - VALGRIND_MAKE_MEM_NOACCESS(prev, sizeof(*prev)); - } - if (head == NULL) { - /* FAIL! Will have been reported to user earlier, so just exit. */ - return; - } - VALGRIND_MAKE_MEM_DEFINED(blks->tail, sizeof(*blks->tail)); - if (*blks->tail == head) { - /* Removing the tail of the list */ - if (prev == NULL) { - /* Which is also the head */ - blks->tail = &blks->head; - } else { - /* Which isn't the head */ - blks->tail = &prev->next; - } - } - if (prev == NULL) { - /* Removing from the head of the list */ - VALGRIND_MAKE_MEM_DEFINED(head, sizeof(*head)); - blks->head = head->next; - VALGRIND_MAKE_MEM_NOACCESS(head, sizeof(*head)); - } else { - /* Removing from not-the-head */ - VALGRIND_MAKE_MEM_DEFINED(head, sizeof(*head)); - VALGRIND_MAKE_MEM_DEFINED(prev, sizeof(*prev)); - prev->next = head->next; - VALGRIND_MAKE_MEM_NOACCESS(head, sizeof(*head)); - VALGRIND_MAKE_MEM_NOACCESS(prev, sizeof(*prev)); - } -} - -static int Memento_Internal_makeSpace(size_t space) -{ - /* If too big, it can never go on the freelist */ - if (space > MEMENTO_FREELIST_MAX_SINGLE_BLOCK) - return 0; - /* Pretend we added it on. */ - globals.freeListSize += space; - /* Ditch blocks until it fits within our limit */ - while (globals.freeListSize > MEMENTO_FREELIST_MAX) { - Memento_BlkHeader *head = globals.free.head; - VALGRIND_MAKE_MEM_DEFINED(head, sizeof(*head)); - globals.free.head = head->next; - globals.freeListSize -= MEMBLK_SIZE(head->rawsize); - MEMENTO_UNDERLYING_FREE(head); - } - /* Make sure we haven't just completely emptied the free list */ - /* (This should never happen, but belt and braces... */ - if (globals.free.head == NULL) - globals.free.tail = &globals.free.head; - return 1; -} - -static int Memento_appBlocks(Memento_Blocks *blks, - int (*app)(Memento_BlkHeader *, - void *), - void *arg) -{ - Memento_BlkHeader *head = blks->head; - Memento_BlkHeader *next; - int result; - while (head) { - VALGRIND_MAKE_MEM_DEFINED(head, sizeof(Memento_BlkHeader)); - VALGRIND_MAKE_MEM_DEFINED(MEMBLK_TOBLK(head), - head->rawsize + Memento_PostSize); - result = app(head, arg); - next = head->next; - VALGRIND_MAKE_MEM_NOACCESS(MEMBLK_POSTPTR(head), Memento_PostSize); - VALGRIND_MAKE_MEM_NOACCESS(head, sizeof(Memento_BlkHeader)); - if (result) - return result; - head = next; - } - return 0; -} - -static int Memento_appBlock(Memento_Blocks *blks, - int (*app)(Memento_BlkHeader *, - void *), - void *arg, - Memento_BlkHeader *b) -{ - Memento_BlkHeader *head = blks->head; - Memento_BlkHeader *next; - int result; - while (head && head != b) { - VALGRIND_MAKE_MEM_DEFINED(head, sizeof(Memento_BlkHeader)); - next = head->next; - VALGRIND_MAKE_MEM_NOACCESS(MEMBLK_POSTPTR(head), Memento_PostSize); - head = next; - } - if (head == b) { - VALGRIND_MAKE_MEM_DEFINED(head, sizeof(Memento_BlkHeader)); - VALGRIND_MAKE_MEM_DEFINED(MEMBLK_TOBLK(head), - head->rawsize + Memento_PostSize); - result = app(head, arg); - VALGRIND_MAKE_MEM_NOACCESS(MEMBLK_POSTPTR(head), Memento_PostSize); - VALGRIND_MAKE_MEM_NOACCESS(head, sizeof(Memento_BlkHeader)); - return result; - } - return 0; -} - -static void showBlock(Memento_BlkHeader *b, int space) -{ - fprintf(stderr, "0x%p:(size=%d,num=%d)", - MEMBLK_TOBLK(b), (int)b->rawsize, b->sequence); - if (b->label) - fprintf(stderr, "%c(%s)", space, b->label); -} - -static void blockDisplay(Memento_BlkHeader *b, int n) -{ - n++; - while (n > 40) - { - fprintf(stderr, "*"); - n -= 40; - } - while(n > 0) - { - int i = n; - if (i > 32) - i = 32; - n -= i; - fprintf(stderr, "%s", &" "[32-i]); - } - showBlock(b, '\t'); - fprintf(stderr, "\n"); -} - -static int Memento_listBlock(Memento_BlkHeader *b, - void *arg) -{ - int *counts = (int *)arg; - blockDisplay(b, 0); - counts[0]++; - counts[1]+= b->rawsize; - return 0; -} - -static void doNestedDisplay(Memento_BlkHeader *b, - int depth) -{ - /* Try and avoid recursion if we can help it */ - do { - blockDisplay(b, depth); - if (b->sibling) { - if (b->child) - doNestedDisplay(b->child, depth+1); - b = b->sibling; - } else { - b = b->child; - depth++; - } - } while (b); -} - -static int ptrcmp(const void *a_, const void *b_) -{ - const char **a = (const char **)a_; - const char **b = (const char **)b_; - return (int)(*a-*b); -} - -static -int Memento_listBlocksNested(void) -{ - int count, size, i; - Memento_BlkHeader *b; - void **blocks, *minptr, *maxptr; - long mask; - - /* Count the blocks */ - count = 0; - size = 0; - for (b = globals.used.head; b; b = b->next) { - size += b->rawsize; - count++; - } - - /* Make our block list */ - blocks = MEMENTO_UNDERLYING_MALLOC(sizeof(void *) * count); - if (blocks == NULL) - return 1; - - /* Populate our block list */ - b = globals.used.head; - minptr = maxptr = MEMBLK_TOBLK(b); - mask = (long)minptr; - for (i = 0; b; b = b->next, i++) { - void *p = MEMBLK_TOBLK(b); - mask &= (long)p; - if (p < minptr) - minptr = p; - if (p > maxptr) - maxptr = p; - blocks[i] = p; - b->flags &= ~Memento_Flag_HasParent; - b->child = NULL; - b->sibling = NULL; - b->parent = NULL; - } - qsort(blocks, count, sizeof(void *), ptrcmp); - - /* Now, calculate tree */ - for (b = globals.used.head; b; b = b->next) { - char *p = MEMBLK_TOBLK(b); - int end = (b->rawsize < MEMENTO_PTRSEARCH ? b->rawsize : MEMENTO_PTRSEARCH); - for (i = MEMENTO_SEARCH_SKIP; i < end; i += sizeof(void *)) { - void *q = *(void **)(&p[i]); - void **r; - - /* Do trivial checks on pointer */ - if ((mask & (int)q) != mask || q < minptr || q > maxptr) - continue; - - /* Search for pointer */ - r = bsearch(&q, blocks, count, sizeof(void *), ptrcmp); - if (r) { - /* Found child */ - Memento_BlkHeader *child = MEMBLK_FROMBLK(*r); - Memento_BlkHeader *parent; - - /* We're assuming tree structure, not graph - ignore second - * and subsequent pointers. */ - if (child->parent != NULL) - continue; - if (child->flags & Memento_Flag_HasParent) - continue; - - /* We're also assuming acyclicness here. If this is one of - * our parents, ignore it. */ - parent = b->parent; - while (parent != NULL && parent != child) - parent = parent->parent; - if (parent == child) - continue; - - child->sibling = b->child; - b->child = child; - child->parent = b; - child->flags |= Memento_Flag_HasParent; - } - } - } - - /* Now display with nesting */ - for (b = globals.used.head; b; b = b->next) { - if ((b->flags & Memento_Flag_HasParent) == 0) - doNestedDisplay(b, 0); - } - fprintf(stderr, " Total number of blocks = %d\n", count); - fprintf(stderr, " Total size of blocks = %d\n", size); - - MEMENTO_UNDERLYING_FREE(blocks); - return 0; -} - -void Memento_listBlocks(void) -{ - fprintf(stderr, "Allocated blocks:\n"); - if (Memento_listBlocksNested()) - { - int counts[2]; - counts[0] = 0; - counts[1] = 0; - Memento_appBlocks(&globals.used, Memento_listBlock, &counts[0]); - fprintf(stderr, " Total number of blocks = %d\n", counts[0]); - fprintf(stderr, " Total size of blocks = %d\n", counts[1]); - } -} - -static int Memento_listNewBlock(Memento_BlkHeader *b, - void *arg) -{ - if (b->flags & Memento_Flag_OldBlock) - return 0; - b->flags |= Memento_Flag_OldBlock; - return Memento_listBlock(b, arg); -} - -void Memento_listNewBlocks(void) { - int counts[2]; - counts[0] = 0; - counts[1] = 0; - fprintf(stderr, "Blocks allocated and still extant since last list:\n"); - Memento_appBlocks(&globals.used, Memento_listNewBlock, &counts[0]); - fprintf(stderr, " Total number of blocks = %d\n", counts[0]); - fprintf(stderr, " Total size of blocks = %d\n", counts[1]); -} - -static void Memento_endStats(void) -{ - fprintf(stderr, "Total memory malloced = %u bytes\n", (unsigned int)globals.totalAlloc); - fprintf(stderr, "Peak memory malloced = %u bytes\n", (unsigned int)globals.peakAlloc); - fprintf(stderr, "%u mallocs, %u frees, %u reallocs\n", (unsigned int)globals.numMallocs, - (unsigned int)globals.numFrees, (unsigned int)globals.numReallocs); - fprintf(stderr, "Average allocation size %u bytes\n", (unsigned int) - (globals.numMallocs != 0 ? globals.totalAlloc/globals.numMallocs: 0)); -} - -void Memento_stats(void) -{ - fprintf(stderr, "Current memory malloced = %u bytes\n", (unsigned int)globals.alloc); - Memento_endStats(); -} - -static void Memento_fin(void) -{ - Memento_checkAllMemory(); - Memento_endStats(); - if (globals.used.head != NULL) { - Memento_listBlocks(); - Memento_breakpoint(); - } - if (globals.segv) { - fprintf(stderr, "Memory dumped on SEGV while squeezing @ %d\n", globals.failAt); - } else if (globals.squeezing) { - if (globals.pattern == 0) - fprintf(stderr, "Memory squeezing @ %d complete\n", globals.squeezeAt); - else - fprintf(stderr, "Memory squeezing @ %d (%d) complete\n", globals.squeezeAt, globals.pattern); - } - if (globals.failing) - { - fprintf(stderr, "MEMENTO_FAILAT=%d\n", globals.failAt); - fprintf(stderr, "MEMENTO_PATTERN=%d\n", globals.pattern); - } - if (globals.nextFailAt != 0) - { - fprintf(stderr, "MEMENTO_NEXTFAILAT=%d\n", globals.nextFailAt); - fprintf(stderr, "MEMENTO_NEXTPATTERN=%d\n", globals.nextPattern); - } -} - -static void Memento_inited(void) -{ - /* A good place for a breakpoint */ -} - -static void Memento_init(void) -{ - char *env; - memset(&globals, 0, sizeof(globals)); - globals.inited = 1; - globals.used.head = NULL; - globals.used.tail = &globals.used.head; - globals.free.head = NULL; - globals.free.tail = &globals.free.head; - globals.sequence = 0; - globals.countdown = 1024; - - env = getenv("MEMENTO_FAILAT"); - globals.failAt = (env ? atoi(env) : 0); - - env = getenv("MEMENTO_PARANOIA"); - globals.paranoia = (env ? atoi(env) : 0); - if (globals.paranoia == 0) - globals.paranoia = 1024; - - env = getenv("MEMENTO_PARANOIDAT"); - globals.paranoidAt = (env ? atoi(env) : 0); - - env = getenv("MEMENTO_SQUEEZEAT"); - globals.squeezeAt = (env ? atoi(env) : 0); - - env = getenv("MEMENTO_PATTERN"); - globals.pattern = (env ? atoi(env) : 0); - - env = getenv("MEMENTO_MAXMEMORY"); - globals.maxMemory = (env ? atoi(env) : 0); - - atexit(Memento_fin); - - Memento_inited(); -} - -#ifdef MEMENTO_HAS_FORK -#include -#include -#ifdef MEMENTO_STACKTRACE_METHOD -#if MEMENTO_STACKTRACE_METHOD == 1 -#include -#endif -#endif - -/* FIXME: Find some portable way of getting this */ -/* MacOSX has 10240, Ubuntu seems to have 256 */ -#define OPEN_MAX 10240 - -/* stashed_map[j] = i means that filedescriptor i-1 was duplicated to j */ -int stashed_map[OPEN_MAX]; - -#ifdef MEMENTO_STACKTRACE_METHOD -#if MEMENTO_STACKTRACE_METHOD == 1 -extern size_t backtrace(void **, int); -extern void backtrace_symbols_fd(void **, size_t, int); -#endif -#endif - -static void Memento_signal(void) -{ - fprintf(stderr, "SEGV after Memory squeezing @ %d\n", globals.squeezeAt); - -#ifdef MEMENTO_STACKTRACE_METHOD -#if MEMENTO_STACKTRACE_METHOD == 1 - { - void *array[100]; - size_t size; - - size = backtrace(array, 100); - fprintf(stderr, "------------------------------------------------------------------------\n"); - fprintf(stderr, "Backtrace:\n"); - backtrace_symbols_fd(array, size, 2); - fprintf(stderr, "------------------------------------------------------------------------\n"); - } -#endif -#endif - - exit(1); -} - -static int squeeze(void) -{ - pid_t pid; - int i, status; - - if (globals.patternBit < 0) - return 1; - if (globals.squeezing && globals.patternBit >= MEMENTO_MAXPATTERN) - return 1; - - if (globals.patternBit == 0) - globals.squeezeAt = globals.sequence; - - if (!globals.squeezing) { - fprintf(stderr, "Memory squeezing @ %d\n", globals.squeezeAt); - } else - fprintf(stderr, "Memory squeezing @ %d (%x,%x)\n", globals.squeezeAt, globals.pattern, globals.patternBit); - - /* When we fork below, the child is going to snaffle all our file pointers - * and potentially corrupt them. Let's make copies of all of them before - * we fork, so we can restore them when we restart. */ - for (i = 0; i < OPEN_MAX; i++) { - if (stashed_map[i] == 0) { - int j = dup(i); - stashed_map[j] = i+1; - } - } - - pid = fork(); - if (pid == 0) { - /* Child */ - signal(SIGSEGV, Memento_signal); - /* In the child, we always fail the next allocation. */ - if (globals.patternBit == 0) { - globals.patternBit = 1; - } else - globals.patternBit <<= 1; - globals.squeezing = 1; - return 1; - } - - /* In the parent if we hit another allocation, pass it (and record the - * fact we passed it in the pattern. */ - globals.pattern |= globals.patternBit; - globals.patternBit <<= 1; - - /* Wait for pid to finish */ - waitpid(pid, &status, 0); - - if (status != 0) { - fprintf(stderr, "Child status=%d\n", status); - } - - /* Put the files back */ - for (i = 0; i < OPEN_MAX; i++) { - if (stashed_map[i] != 0) { - dup2(i, stashed_map[i]-1); - close(i); - stashed_map[i] = 0; - } - } - - return 0; -} -#else -#include - -static void Memento_signal(void) -{ - globals.segv = 1; - /* If we just return from this function the SEGV will be unhandled, and - * we'll launch into whatever JIT debugging system the OS provides. At - * least fprintf(stderr, something useful first. If MEMENTO_NOJIT is set, then - * just exit to avoid the JIT (and get the usual atexit handling). */ - if (getenv("MEMENTO_NOJIT")) - exit(1); - else - Memento_fin(); -} - -int squeeze(void) -{ - fprintf(stderr, "Memento memory squeezing disabled as no fork!\n"); - return 0; -} -#endif - -static void Memento_startFailing(void) -{ - if (!globals.failing) { - fprintf(stderr, "Starting to fail...\n"); - fflush(stderr); - globals.failing = 1; - globals.failAt = globals.sequence; - globals.nextFailAt = globals.sequence+1; - globals.pattern = 0; - globals.patternBit = 0; - signal(SIGSEGV, Memento_signal); - signal(SIGABRT, Memento_signal); - Memento_breakpoint(); - } -} - -static void Memento_event(void) -{ - globals.sequence++; - if ((globals.sequence >= globals.paranoidAt) && (globals.paranoidAt != 0)) { - globals.paranoia = 1; - globals.countdown = 1; - } - if (--globals.countdown == 0) { - Memento_checkAllMemory(); - globals.countdown = globals.paranoia; - } - - if (globals.sequence == globals.breakAt) { - fprintf(stderr, "Breaking at event %d\n", globals.breakAt); - Memento_breakpoint(); - } -} - -int Memento_breakAt(int event) -{ - globals.breakAt = event; - return event; -} - -void *Memento_label(void *ptr, const char *label) -{ - Memento_BlkHeader *block; - - if (ptr == NULL) - return NULL; - block = MEMBLK_FROMBLK(ptr); - block->label = label; - return ptr; -} - -int Memento_failThisEvent(void) -{ - int failThisOne; - - if (!globals.inited) - Memento_init(); - - Memento_event(); - - if ((globals.sequence >= globals.failAt) && (globals.failAt != 0)) - Memento_startFailing(); - if ((globals.sequence >= globals.squeezeAt) && (globals.squeezeAt != 0)) { - return squeeze(); - } - - if (!globals.failing) - return 0; - failThisOne = ((globals.patternBit & globals.pattern) == 0); - /* If we are failing, and we've reached the end of the pattern and we've - * still got bits available in the pattern word, and we haven't already - * set a nextPattern, then extend the pattern. */ - if (globals.failing && - ((~(globals.patternBit-1) & globals.pattern) == 0) && - (globals.patternBit != 0) && - globals.nextPattern == 0) - { - /* We'll fail this one, and set the 'next' one to pass it. */ - globals.nextFailAt = globals.failAt; - globals.nextPattern = globals.pattern | globals.patternBit; - } - globals.patternBit = (globals.patternBit ? globals.patternBit << 1 : 1); - - return failThisOne; -} - -void *Memento_malloc(size_t s) -{ - Memento_BlkHeader *memblk; - size_t smem = MEMBLK_SIZE(s); - - if (Memento_failThisEvent()) - return NULL; - - if (s == 0) - return NULL; - - globals.numMallocs++; - - if (globals.maxMemory != 0 && globals.alloc + s > globals.maxMemory) - return NULL; - - memblk = MEMENTO_UNDERLYING_MALLOC(smem); - if (memblk == NULL) - return NULL; - - globals.alloc += s; - globals.totalAlloc += s; - if (globals.peakAlloc < globals.alloc) - globals.peakAlloc = globals.alloc; -#ifndef MEMENTO_LEAKONLY - memset(MEMBLK_TOBLK(memblk), MEMENTO_ALLOCFILL, s); -#endif - memblk->rawsize = s; - memblk->sequence = globals.sequence; - memblk->lastCheckedOK = memblk->sequence; - memblk->flags = 0; - memblk->label = 0; - memblk->child = NULL; - memblk->sibling = NULL; - Memento_addBlockHead(&globals.used, memblk, 0); - return MEMBLK_TOBLK(memblk); -} - -void *Memento_calloc(size_t n, size_t s) -{ - void *block = Memento_malloc(n*s); - - if (block) - memset(block, 0, n*s); - return block; -} - -static int checkBlock(Memento_BlkHeader *memblk, const char *action) -{ -#ifndef MEMENTO_LEAKONLY - BlkCheckData data; - - memset(&data, 0, sizeof(data)); - Memento_appBlock(&globals.used, Memento_Internal_checkAllocedBlock, - &data, memblk); - if (!data.found) { - /* Failure! */ - fprintf(stderr, "Attempt to %s block ", action); - showBlock(memblk, 32); - Memento_breakpoint(); - return 1; - } else if (data.preCorrupt || data.postCorrupt) { - fprintf(stderr, "Block "); - showBlock(memblk, ' '); - fprintf(stderr, " found to be corrupted on %s!\n", action); - if (data.preCorrupt) { - fprintf(stderr, "Preguard corrupted\n"); - } - if (data.postCorrupt) { - fprintf(stderr, "Postguard corrupted\n"); - } - fprintf(stderr, "Block last checked OK at allocation %d. Now %d.\n", - memblk->lastCheckedOK, globals.sequence); - Memento_breakpoint(); - return 1; - } -#endif - return 0; -} - -void Memento_free(void *blk) -{ - Memento_BlkHeader *memblk; - - if (!globals.inited) - Memento_init(); - - Memento_event(); - - if (blk == NULL) - return; - - memblk = MEMBLK_FROMBLK(blk); - VALGRIND_MAKE_MEM_DEFINED(memblk, sizeof(*memblk)); - if (checkBlock(memblk, "free")) - return; - - if (memblk->flags & Memento_Flag_BreakOnFree) - Memento_breakpoint(); - - VALGRIND_MAKE_MEM_DEFINED(memblk, sizeof(*memblk)); - globals.alloc -= memblk->rawsize; - globals.numFrees++; - - Memento_removeBlock(&globals.used, memblk); - - VALGRIND_MAKE_MEM_DEFINED(memblk, sizeof(*memblk)); - if (Memento_Internal_makeSpace(MEMBLK_SIZE(memblk->rawsize))) { - VALGRIND_MAKE_MEM_DEFINED(memblk, sizeof(*memblk)); - VALGRIND_MAKE_MEM_DEFINED(MEMBLK_TOBLK(memblk), - memblk->rawsize + Memento_PostSize); -#ifndef MEMENTO_LEAKONLY - memset(MEMBLK_TOBLK(memblk), MEMENTO_FREEFILL, memblk->rawsize); -#endif - Memento_addBlockTail(&globals.free, memblk, 1); - } else { - MEMENTO_UNDERLYING_FREE(memblk); - } -} - -void *Memento_realloc(void *blk, size_t newsize) -{ - Memento_BlkHeader *memblk, *newmemblk; - size_t newsizemem; - int flags; - - if (blk == NULL) - return Memento_malloc(newsize); - if (newsize == 0) { - Memento_free(blk); - return NULL; - } - - if (Memento_failThisEvent()) - return NULL; - - memblk = MEMBLK_FROMBLK(blk); - if (checkBlock(memblk, "realloc")) - return NULL; - - if (memblk->flags & Memento_Flag_BreakOnRealloc) - Memento_breakpoint(); - - if (globals.maxMemory != 0 && globals.alloc - memblk->rawsize + newsize > globals.maxMemory) - return NULL; - - newsizemem = MEMBLK_SIZE(newsize); - Memento_removeBlock(&globals.used, memblk); - flags = memblk->flags; - newmemblk = MEMENTO_UNDERLYING_REALLOC(memblk, newsizemem); - if (newmemblk == NULL) - { - Memento_addBlockHead(&globals.used, memblk, 2); - return NULL; - } - globals.numReallocs++; - globals.totalAlloc += newsize; - globals.alloc -= newmemblk->rawsize; - globals.alloc += newsize; - if (globals.peakAlloc < globals.alloc) - globals.peakAlloc = globals.alloc; - newmemblk->flags = flags; - if (newmemblk->rawsize < newsize) { - char *newbytes = ((char *)MEMBLK_TOBLK(newmemblk))+newmemblk->rawsize; -#ifndef MEMENTO_LEAKONLY - memset(newbytes, MEMENTO_ALLOCFILL, newsize - newmemblk->rawsize); -#endif - VALGRIND_MAKE_MEM_UNDEFINED(newbytes, newsize - newmemblk->rawsize); - } - newmemblk->rawsize = newsize; -#ifndef MEMENTO_LEAKONLY - memset(newmemblk->preblk, MEMENTO_PREFILL, Memento_PreSize); - memset(MEMBLK_POSTPTR(newmemblk), MEMENTO_POSTFILL, Memento_PostSize); -#endif - Memento_addBlockHead(&globals.used, newmemblk, 2); - return MEMBLK_TOBLK(newmemblk); -} - -int Memento_checkBlock(void *blk) -{ - Memento_BlkHeader *memblk; - - if (blk == NULL) - return 0; - memblk = MEMBLK_FROMBLK(blk); - return checkBlock(memblk, "check"); -} - -static int Memento_Internal_checkAllAlloced(Memento_BlkHeader *memblk, void *arg) -{ - BlkCheckData *data = (BlkCheckData *)arg; - - Memento_Internal_checkAllocedBlock(memblk, data); - if (data->preCorrupt || data->postCorrupt) { - if ((data->found & 2) == 0) { - fprintf(stderr, "Allocated blocks:\n"); - data->found |= 2; - } - fprintf(stderr, " Block "); - showBlock(memblk, ' '); - if (data->preCorrupt) { - fprintf(stderr, " Preguard "); - } - if (data->postCorrupt) { - fprintf(stderr, "%s Postguard ", - (data->preCorrupt ? "&" : "")); - } - fprintf(stderr, "corrupted.\n " - "Block last checked OK at allocation %d. Now %d.\n", - memblk->lastCheckedOK, globals.sequence); - data->preCorrupt = 0; - data->postCorrupt = 0; - data->freeCorrupt = 0; - } - else - memblk->lastCheckedOK = globals.sequence; - return 0; -} - -static int Memento_Internal_checkAllFreed(Memento_BlkHeader *memblk, void *arg) -{ - BlkCheckData *data = (BlkCheckData *)arg; - - Memento_Internal_checkFreedBlock(memblk, data); - if (data->preCorrupt || data->postCorrupt || data->freeCorrupt) { - if ((data->found & 4) == 0) { - fprintf(stderr, "Freed blocks:\n"); - data->found |= 4; - } - fprintf(stderr, " "); - showBlock(memblk, ' '); - if (data->freeCorrupt) { - fprintf(stderr, " index %d (address 0x%p) onwards", data->index, - &((char *)MEMBLK_TOBLK(memblk))[data->index]); - if (data->preCorrupt) { - fprintf(stderr, "+ preguard"); - } - if (data->postCorrupt) { - fprintf(stderr, "+ postguard"); - } - } else { - if (data->preCorrupt) { - fprintf(stderr, " preguard"); - } - if (data->postCorrupt) { - fprintf(stderr, "%s Postguard", - (data->preCorrupt ? "+" : "")); - } - } - fprintf(stderr, " corrupted.\n" - " Block last checked OK at allocation %d. Now %d.\n", - memblk->lastCheckedOK, globals.sequence); - data->preCorrupt = 0; - data->postCorrupt = 0; - data->freeCorrupt = 0; - } - else - memblk->lastCheckedOK = globals.sequence; - return 0; -} - -int Memento_checkAllMemory(void) -{ -#ifndef MEMENTO_LEAKONLY - BlkCheckData data; - - memset(&data, 0, sizeof(data)); - Memento_appBlocks(&globals.used, Memento_Internal_checkAllAlloced, &data); - Memento_appBlocks(&globals.free, Memento_Internal_checkAllFreed, &data); - if (data.found & 6) { - Memento_breakpoint(); - return 1; - } -#endif - return 0; -} - -int Memento_setParanoia(int i) -{ - globals.paranoia = i; - globals.countdown = globals.paranoia; - return i; -} - -int Memento_paranoidAt(int i) -{ - globals.paranoidAt = i; - return i; -} - -int Memento_getBlockNum(void *b) -{ - Memento_BlkHeader *memblk; - if (b == NULL) - return 0; - memblk = MEMBLK_FROMBLK(b); - return (memblk->sequence); -} - -int Memento_check(void) -{ - int result; - - fprintf(stderr, "Checking memory\n"); - result = Memento_checkAllMemory(); - fprintf(stderr, "Memory checked!\n"); - return result; -} - -typedef struct findBlkData { - void *addr; - Memento_BlkHeader *blk; - int flags; -} findBlkData; - -static int Memento_containsAddr(Memento_BlkHeader *b, - void *arg) -{ - findBlkData *data = (findBlkData *)arg; - char *blkend = &((char *)MEMBLK_TOBLK(b))[b->rawsize]; - if ((MEMBLK_TOBLK(b) <= data->addr) && - ((void *)blkend > data->addr)) { - data->blk = b; - data->flags = 1; - return 1; - } - if (((void *)b <= data->addr) && - (MEMBLK_TOBLK(b) > data->addr)) { - data->blk = b; - data->flags = 2; - return 1; - } - if (((void *)blkend <= data->addr) && - ((void *)(blkend + Memento_PostSize) > data->addr)) { - data->blk = b; - data->flags = 3; - return 1; - } - return 0; -} - -int Memento_find(void *a) -{ - findBlkData data; - - data.addr = a; - data.blk = NULL; - data.flags = 0; - Memento_appBlocks(&globals.used, Memento_containsAddr, &data); - if (data.blk != NULL) { - fprintf(stderr, "Address 0x%p is in %sallocated block ", - data.addr, - (data.flags == 1 ? "" : (data.flags == 2 ? - "preguard of " : "postguard of "))); - showBlock(data.blk, ' '); - fprintf(stderr, "\n"); - return data.blk->sequence; - } - data.blk = NULL; - data.flags = 0; - Memento_appBlocks(&globals.free, Memento_containsAddr, &data); - if (data.blk != NULL) { - fprintf(stderr, "Address 0x%p is in %sfreed block ", - data.addr, - (data.flags == 1 ? "" : (data.flags == 2 ? - "preguard of " : "postguard of "))); - showBlock(data.blk, ' '); - fprintf(stderr, "\n"); - return data.blk->sequence; - } - return 0; -} - -void Memento_breakOnFree(void *a) -{ - findBlkData data; - - data.addr = a; - data.blk = NULL; - data.flags = 0; - Memento_appBlocks(&globals.used, Memento_containsAddr, &data); - if (data.blk != NULL) { - fprintf(stderr, "Will stop when address 0x%p (in %sallocated block ", - data.addr, - (data.flags == 1 ? "" : (data.flags == 2 ? - "preguard of " : "postguard of "))); - showBlock(data.blk, ' '); - fprintf(stderr, ") is freed\n"); - data.blk->flags |= Memento_Flag_BreakOnFree; - return; - } - data.blk = NULL; - data.flags = 0; - Memento_appBlocks(&globals.free, Memento_containsAddr, &data); - if (data.blk != NULL) { - fprintf(stderr, "Can't stop on free; address 0x%p is in %sfreed block ", - data.addr, - (data.flags == 1 ? "" : (data.flags == 2 ? - "preguard of " : "postguard of "))); - showBlock(data.blk, ' '); - fprintf(stderr, "\n"); - return; - } - fprintf(stderr, "Can't stop on free; address 0x%p is not in a known block.\n", a); -} - -void Memento_breakOnRealloc(void *a) -{ - findBlkData data; - - data.addr = a; - data.blk = NULL; - data.flags = 0; - Memento_appBlocks(&globals.used, Memento_containsAddr, &data); - if (data.blk != NULL) { - fprintf(stderr, "Will stop when address 0x%p (in %sallocated block ", - data.addr, - (data.flags == 1 ? "" : (data.flags == 2 ? - "preguard of " : "postguard of "))); - showBlock(data.blk, ' '); - fprintf(stderr, ") is freed (or realloced)\n"); - data.blk->flags |= Memento_Flag_BreakOnFree | Memento_Flag_BreakOnRealloc; - return; - } - data.blk = NULL; - data.flags = 0; - Memento_appBlocks(&globals.free, Memento_containsAddr, &data); - if (data.blk != NULL) { - fprintf(stderr, "Can't stop on free/realloc; address 0x%p is in %sfreed block ", - data.addr, - (data.flags == 1 ? "" : (data.flags == 2 ? - "preguard of " : "postguard of "))); - showBlock(data.blk, ' '); - fprintf(stderr, "\n"); - return; - } - fprintf(stderr, "Can't stop on free/realloc; address 0x%p is not in a known block.\n", a); -} - -int Memento_failAt(int i) -{ - globals.failAt = i; - if ((globals.sequence > globals.failAt) && - (globals.failing != 0)) - Memento_startFailing(); - return i; -} - -size_t Memento_setMax(size_t max) -{ - globals.maxMemory = max; - return max; -} - -#else - -/* Just in case anyone has left some debugging code in... */ -void (Memento_breakpoint)(void) -{ -} - -int (Memento_checkBlock)(void *b) -{ - return 0; -} - -int (Memento_checkAllMemory)(void) -{ - return 0; -} - -int (Memento_check)(void) -{ - return 0; -} - -int (Memento_setParanoia)(int i) -{ - return 0; -} - -int (Memento_paranoidAt)(int i) -{ - return 0; -} - -int (Memento_breakAt)(int i) -{ - return 0; -} - -int (Memento_getBlockNum)(void *i) -{ - return 0; -} - -int (Memento_find)(void *a) -{ - return 0; -} - -int (Memento_failAt)(int i) -{ - return 0; -} - -void (Memento_breakOnFree)(void *a) -{ -} - -void (Memento_breakOnRealloc)(void *a) -{ -} - -#undef Memento_malloc -#undef Memento_free -#undef Memento_realloc -#undef Memento_calloc - -void *Memento_malloc(size_t size) -{ - return MEMENTO_UNDERLYING_MALLOC(size); -} - -void Memento_free(void *b) -{ - MEMENTO_UNDERLYING_FREE(b); -} - -void *Memento_realloc(void *b, size_t s) -{ - return MEMENTO_UNDERLYING_REALLOC(b, s); -} - -void *Memento_calloc(size_t n, size_t s) -{ - return MEMENTO_UNDERLYING_CALLOC(n, s); -} - -void (Memento_listBlocks)(void) -{ -} - -void (Memento_listNewBlocks)(void) -{ -} - -size_t (Memento_setMax)(size_t max) -{ - return 0; -} - -void (Memento_stats)(void) -{ -} - -void *(Memento_label)(void *ptr, const char *label) -{ - return ptr; -} - -#endif diff --git a/fitz/res_bitmap.c b/fitz/res_bitmap.c deleted file mode 100644 index 6357f7d7..00000000 --- a/fitz/res_bitmap.c +++ /dev/null @@ -1,123 +0,0 @@ -#include "mupdf/fitz.h" - -fz_bitmap * -fz_new_bitmap(fz_context *ctx, int w, int h, int n, int xres, int yres) -{ - fz_bitmap *bit; - - bit = fz_malloc_struct(ctx, fz_bitmap); - bit->refs = 1; - bit->w = w; - bit->h = h; - bit->n = n; - bit->xres = xres; - bit->yres = yres; - /* Span is 32 bit aligned. We may want to make this 64 bit if we - * use SSE2 etc. */ - bit->stride = ((n * w + 31) & ~31) >> 3; - - bit->samples = fz_malloc_array(ctx, h, bit->stride); - - return bit; -} - -fz_bitmap * -fz_keep_bitmap(fz_context *ctx, fz_bitmap *bit) -{ - if (bit) - bit->refs++; - return bit; -} - -void -fz_drop_bitmap(fz_context *ctx, fz_bitmap *bit) -{ - if (bit && --bit->refs == 0) - { - fz_free(ctx, bit->samples); - fz_free(ctx, bit); - } -} - -void -fz_clear_bitmap(fz_context *ctx, fz_bitmap *bit) -{ - memset(bit->samples, 0, bit->stride * bit->h); -} - -/* - * Write bitmap to PBM file - */ - -void -fz_write_pbm(fz_context *ctx, fz_bitmap *bitmap, char *filename) -{ - FILE *fp; - unsigned char *p; - int h, bytestride; - - fp = fopen(filename, "wb"); - if (!fp) - fz_throw(ctx, FZ_ERROR_GENERIC, "cannot open file '%s': %s", filename, strerror(errno)); - - assert(bitmap->n == 1); - - fprintf(fp, "P4\n%d %d\n", bitmap->w, bitmap->h); - - p = bitmap->samples; - - h = bitmap->h; - bytestride = (bitmap->w + 7) >> 3; - while (h--) - { - fwrite(p, 1, bytestride, fp); - p += bitmap->stride; - } - - 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) - *stride = bit->stride; -} diff --git a/fitz/res_colorspace.c b/fitz/res_colorspace.c deleted file mode 100644 index 07da5a95..00000000 --- a/fitz/res_colorspace.c +++ /dev/null @@ -1,1277 +0,0 @@ -#include "mupdf/fitz.h" - -#define SLOWCMYK - -void -fz_free_colorspace_imp(fz_context *ctx, fz_storable *cs_) -{ - fz_colorspace *cs = (fz_colorspace *)cs_; - - if (cs->free_data && cs->data) - cs->free_data(ctx, cs); - fz_free(ctx, cs); -} - -fz_colorspace * -fz_new_colorspace(fz_context *ctx, char *name, int n) -{ - fz_colorspace *cs = fz_malloc(ctx, sizeof(fz_colorspace)); - FZ_INIT_STORABLE(cs, 1, fz_free_colorspace_imp); - cs->size = sizeof(fz_colorspace); - fz_strlcpy(cs->name, name, sizeof cs->name); - cs->n = n; - cs->to_rgb = NULL; - cs->from_rgb = NULL; - cs->free_data = NULL; - cs->data = NULL; - return cs; -} - -fz_colorspace * -fz_keep_colorspace(fz_context *ctx, fz_colorspace *cs) -{ - return (fz_colorspace *)fz_keep_storable(ctx, &cs->storable); -} - -void -fz_drop_colorspace(fz_context *ctx, fz_colorspace *cs) -{ - fz_drop_storable(ctx, &cs->storable); -} - -/* Device colorspace definitions */ - -static void gray_to_rgb(fz_context *ctx, fz_colorspace *cs, float *gray, float *rgb) -{ - rgb[0] = gray[0]; - rgb[1] = gray[0]; - rgb[2] = gray[0]; -} - -static void rgb_to_gray(fz_context *ctx, fz_colorspace *cs, float *rgb, float *gray) -{ - float r = rgb[0]; - float g = rgb[1]; - float b = rgb[2]; - gray[0] = r * 0.3f + g * 0.59f + b * 0.11f; -} - -static void rgb_to_rgb(fz_context *ctx, fz_colorspace *cs, float *rgb, float *xyz) -{ - xyz[0] = rgb[0]; - xyz[1] = rgb[1]; - xyz[2] = rgb[2]; -} - -static void bgr_to_rgb(fz_context *ctx, fz_colorspace *cs, float *bgr, float *rgb) -{ - rgb[0] = bgr[2]; - rgb[1] = bgr[1]; - rgb[2] = bgr[0]; -} - -static void rgb_to_bgr(fz_context *ctx, fz_colorspace *cs, float *rgb, float *bgr) -{ - bgr[0] = rgb[2]; - bgr[1] = rgb[1]; - bgr[2] = rgb[0]; -} - -static void cmyk_to_rgb(fz_context *ctx, fz_colorspace *cs, float *cmyk, float *rgb) -{ -#ifdef SLOWCMYK /* from poppler */ - float c = cmyk[0], m = cmyk[1], y = cmyk[2], k = cmyk[3]; - float r, g, b, x; - float cm = c * m; - float c1m = m - cm; - float cm1 = c - cm; - float c1m1 = 1 - m - cm1; - float c1m1y = c1m1 * y; - float c1m1y1 = c1m1 - c1m1y; - float c1my = c1m * y; - float c1my1 = c1m - c1my; - float cm1y = cm1 * y; - float cm1y1 = cm1 - cm1y; - float cmy = cm * y; - float cmy1 = cm - cmy; - - /* this is a matrix multiplication, unrolled for performance */ - x = c1m1y1 * k; /* 0 0 0 1 */ - r = g = b = c1m1y1 - x; /* 0 0 0 0 */ - r += 0.1373 * x; - g += 0.1216 * x; - b += 0.1255 * x; - - x = c1m1y * k; /* 0 0 1 1 */ - r += 0.1098 * x; - g += 0.1020 * x; - x = c1m1y - x; /* 0 0 1 0 */ - r += x; - g += 0.9490 * x; - - x = c1my1 * k; /* 0 1 0 1 */ - r += 0.1412 * x; - x = c1my1 - x; /* 0 1 0 0 */ - r += 0.9255 * x; - b += 0.5490 * x; - - x = c1my * k; /* 0 1 1 1 */ - r += 0.1333 * x; - x = c1my - x; /* 0 1 1 0 */ - r += 0.9294 * x; - g += 0.1098 * x; - b += 0.1412 * x; - - x = cm1y1 * k; /* 1 0 0 1 */ - g += 0.0588 * x; - b += 0.1412 * x; - x = cm1y1 - x; /* 1 0 0 0 */ - g += 0.6784 * x; - b += 0.9373 * x; - - x = cm1y * k; /* 1 0 1 1 */ - g += 0.0745 * x; - x = cm1y - x; /* 1 0 1 0 */ - g += 0.6510 * x; - b += 0.3137 * x; - - x = cmy1 * k; /* 1 1 0 1 */ - b += 0.0078 * x; - x = cmy1 - x; /* 1 1 0 0 */ - r += 0.1804 * x; - g += 0.1922 * x; - b += 0.5725 * x; - - x = cmy * (1-k); /* 1 1 1 0 */ - r += 0.2118 * x; - g += 0.2119 * x; - b += 0.2235 * x; - rgb[0] = fz_clamp(r, 0, 1); - rgb[1] = fz_clamp(g, 0, 1); - rgb[2] = fz_clamp(b, 0, 1); -#else - rgb[0] = 1 - fz_min(1, cmyk[0] + cmyk[3]); - rgb[1] = 1 - fz_min(1, cmyk[1] + cmyk[3]); - rgb[2] = 1 - fz_min(1, cmyk[2] + cmyk[3]); -#endif -} - -static void rgb_to_cmyk(fz_context *ctx, fz_colorspace *cs, float *rgb, float *cmyk) -{ - float c, m, y, k; - c = 1 - rgb[0]; - m = 1 - rgb[1]; - y = 1 - rgb[2]; - k = fz_min(c, fz_min(m, y)); - cmyk[0] = c - k; - cmyk[1] = m - k; - cmyk[2] = y - k; - cmyk[3] = k; -} - -static fz_colorspace k_default_gray = { {-1, fz_free_colorspace_imp}, 0, "DeviceGray", 1, gray_to_rgb, rgb_to_gray }; -static fz_colorspace k_default_rgb = { {-1, fz_free_colorspace_imp}, 0, "DeviceRGB", 3, rgb_to_rgb, rgb_to_rgb }; -static fz_colorspace k_default_bgr = { {-1, fz_free_colorspace_imp}, 0, "DeviceRGB", 3, bgr_to_rgb, rgb_to_bgr }; -static fz_colorspace k_default_cmyk = { {-1, fz_free_colorspace_imp}, 0, "DeviceCMYK", 4, cmyk_to_rgb, rgb_to_cmyk }; - -static fz_colorspace *fz_default_gray = &k_default_gray; -static fz_colorspace *fz_default_rgb = &k_default_rgb; -static fz_colorspace *fz_default_bgr = &k_default_bgr; -static fz_colorspace *fz_default_cmyk = &k_default_cmyk; - -struct fz_colorspace_context_s -{ - int ctx_refs; - fz_colorspace *gray, *rgb, *bgr, *cmyk; -}; - -void fz_new_colorspace_context(fz_context *ctx) -{ - ctx->colorspace = fz_malloc_struct(ctx, fz_colorspace_context); - ctx->colorspace->ctx_refs = 1; - ctx->colorspace->gray = fz_default_gray; - ctx->colorspace->rgb = fz_default_rgb; - ctx->colorspace->bgr = fz_default_bgr; - ctx->colorspace->cmyk = fz_default_cmyk; -} - -fz_colorspace_context * -fz_keep_colorspace_context(fz_context *ctx) -{ - if (!ctx || !ctx->colorspace) - return NULL; - fz_lock(ctx, FZ_LOCK_ALLOC); - ctx->colorspace->ctx_refs++; - fz_unlock(ctx, FZ_LOCK_ALLOC); - return ctx->colorspace; -} - -void fz_drop_colorspace_context(fz_context *ctx) -{ - int drop; - if (!ctx || !ctx->colorspace) - return; - fz_lock(ctx, FZ_LOCK_ALLOC); - drop = --ctx->colorspace->ctx_refs; - fz_unlock(ctx, FZ_LOCK_ALLOC); - if (drop == 0) - fz_free(ctx, ctx->colorspace); -} - -fz_colorspace * -fz_device_gray(fz_context *ctx) -{ - return ctx->colorspace->gray; -} - -fz_colorspace * -fz_device_rgb(fz_context *ctx) -{ - return ctx->colorspace->rgb; -} - -fz_colorspace * -fz_device_bgr(fz_context *ctx) -{ - return ctx->colorspace->bgr; -} - -fz_colorspace * -fz_device_cmyk(fz_context *ctx) -{ - return ctx->colorspace->cmyk; -} - -fz_colorspace * -fz_lookup_device_colorspace(fz_context *ctx, char *name) -{ - if (!strcmp(name, "DeviceGray")) - return fz_device_gray(ctx); - if (!strcmp(name, "DeviceRGB")) - return fz_device_rgb(ctx); - if (!strcmp(name, "DeviceBGR")) - return fz_device_bgr(ctx); - if (!strcmp(name, "DeviceCMYK")) - return fz_device_cmyk(ctx); - assert(!"unknown device colorspace"); - return NULL; -} - -void -fz_set_device_gray(fz_context *ctx, fz_colorspace *cs) -{ - fz_drop_colorspace(ctx, ctx->colorspace->gray); - ctx->colorspace->gray = fz_keep_colorspace(ctx, cs); -} - -void -fz_set_device_rgb(fz_context *ctx, fz_colorspace *cs) -{ - fz_drop_colorspace(ctx, ctx->colorspace->rgb); - ctx->colorspace->rgb = fz_keep_colorspace(ctx, cs); -} - -void -fz_set_device_bgr(fz_context *ctx, fz_colorspace *cs) -{ - fz_drop_colorspace(ctx, ctx->colorspace->bgr); - ctx->colorspace->bgr = fz_keep_colorspace(ctx, cs); -} - -void -fz_set_device_cmyk(fz_context *ctx, fz_colorspace *cs) -{ - fz_drop_colorspace(ctx, ctx->colorspace->cmyk); - ctx->colorspace->cmyk = fz_keep_colorspace(ctx, cs); -} - -int -fz_colorspace_is_indexed(fz_colorspace *cs) -{ - return (cs && !strcmp(cs->name, "Indexed")); -} - -/* Fast pixmap color conversions */ - -static void fast_gray_to_rgb(fz_pixmap *dst, fz_pixmap *src) -{ - unsigned char *s = src->samples; - unsigned char *d = dst->samples; - int n = src->w * src->h; - while (n--) - { - d[0] = s[0]; - d[1] = s[0]; - d[2] = s[0]; - d[3] = s[1]; - s += 2; - d += 4; - } -} - -static void fast_gray_to_cmyk(fz_pixmap *dst, fz_pixmap *src) -{ - unsigned char *s = src->samples; - unsigned char *d = dst->samples; - int n = src->w * src->h; - while (n--) - { - d[0] = 0; - d[1] = 0; - d[2] = 0; - d[3] = s[0]; - d[4] = s[1]; - s += 2; - d += 5; - } -} - -static void fast_rgb_to_gray(fz_pixmap *dst, fz_pixmap *src) -{ - unsigned char *s = src->samples; - unsigned char *d = dst->samples; - int n = src->w * src->h; - while (n--) - { - d[0] = ((s[0]+1) * 77 + (s[1]+1) * 150 + (s[2]+1) * 28) >> 8; - d[1] = s[3]; - s += 4; - d += 2; - } -} - -static void fast_bgr_to_gray(fz_pixmap *dst, fz_pixmap *src) -{ - unsigned char *s = src->samples; - unsigned char *d = dst->samples; - int n = src->w * src->h; - while (n--) - { - d[0] = ((s[0]+1) * 28 + (s[1]+1) * 150 + (s[2]+1) * 77) >> 8; - d[1] = s[3]; - s += 4; - d += 2; - } -} - -static void fast_rgb_to_cmyk(fz_pixmap *dst, fz_pixmap *src) -{ - unsigned char *s = src->samples; - unsigned char *d = dst->samples; - int n = src->w * src->h; - while (n--) - { - unsigned char c = 255 - s[0]; - unsigned char m = 255 - s[1]; - unsigned char y = 255 - s[2]; - unsigned char k = (unsigned char)fz_mini(c, fz_mini(m, y)); - d[0] = c - k; - d[1] = m - k; - d[2] = y - k; - d[3] = k; - d[4] = s[3]; - s += 4; - d += 5; - } -} - -static void fast_bgr_to_cmyk(fz_pixmap *dst, fz_pixmap *src) -{ - unsigned char *s = src->samples; - unsigned char *d = dst->samples; - int n = src->w * src->h; - while (n--) - { - unsigned char c = 255 - s[2]; - unsigned char m = 255 - s[1]; - unsigned char y = 255 - s[0]; - unsigned char k = (unsigned char)fz_mini(c, fz_mini(m, y)); - d[0] = c - k; - d[1] = m - k; - d[2] = y - k; - d[3] = k; - d[4] = s[3]; - s += 4; - d += 5; - } -} - -static void fast_cmyk_to_gray(fz_pixmap *dst, fz_pixmap *src) -{ - unsigned char *s = src->samples; - unsigned char *d = dst->samples; - int n = src->w * src->h; - while (n--) - { - unsigned char c = fz_mul255(s[0], 77); - unsigned char m = fz_mul255(s[1], 150); - unsigned char y = fz_mul255(s[2], 28); - d[0] = 255 - (unsigned char)fz_mini(c + m + y + s[3], 255); - d[1] = s[4]; - s += 5; - d += 2; - } -} - -#ifdef ARCH_ARM -static void -fast_cmyk_to_rgb_ARM(unsigned char *dst, unsigned char *src, int n) -__attribute__((naked)); - -static void -fast_cmyk_to_rgb_ARM(unsigned char *dst, unsigned char *src, int n) -{ - asm volatile( - ENTER_ARM - "stmfd r13!,{r4-r11,r14} \n" - "@ r0 = dst \n" - "@ r1 = src \n" - "@ r2 = n \n" - "mov r12, #0 @ r12= CMYK = 0 \n" - "b 2f @ enter loop \n" - "1: @ White or Black \n" - "@ Cunning trick: On entry r11 = 0 if black, r11 = FF if white \n" - "ldrb r7, [r1],#1 @ r8 = s[4] \n" - "strb r11,[r0],#1 @ d[0] = r \n" - "strb r11,[r0],#1 @ d[1] = g \n" - "strb r11,[r0],#1 @ d[2] = b \n" - "strb r7, [r0],#1 @ d[3] = s[4] \n" - "subs r2, r2, #1 @ r2 = n-- \n" - "beq 9f \n" - "2: @ Main loop starts here \n" - "ldrb r3, [r1], #4 @ r3 = c \n" - "ldrb r6, [r1, #-1] @ r6 = k \n" - "ldrb r5, [r1, #-2] @ r5 = y \n" - "ldrb r4, [r1, #-3] @ r4 = m \n" - "eors r11,r6, #0xFF @ if (k == 255) \n" - "beq 1b @ goto black \n" - "orr r7, r3, r4, LSL #8 \n" - "orr r14,r5, r6, LSL #8 \n" - "orrs r7, r7, r14,LSL #16 @ r7 = cmyk \n" - "beq 1b @ if (cmyk == 0) white \n" - "@ At this point, we have to decode a new pixel \n" - "@ r0 = dst r1 = src r2 = n r7 = cmyk \n" - "3: @ unmatched \n" - "stmfd r13!,{r0-r1,r7} @ stash regs for space \n" - "add r3, r3, r3, LSR #7 @ r3 = c += c>>7 \n" - "add r4, r4, r4, LSR #7 @ r4 = m += m>>7 \n" - "add r5, r5, r5, LSR #7 @ r5 = y += y>>7 \n" - "add r6, r6, r6, LSR #7 @ r6 = k += k>>7 \n" - "mov r5, r5, LSR #1 @ sacrifice 1 bit of Y \n" - "mul r8, r3, r4 @ r8 = cm = c * m \n" - "rsb r9, r8, r4, LSL #8 @ r9 = c1m = (m<<8) - cm \n" - "rsb r3, r8, r3, LSL #8 @ r3 = cm1 = (c<<8) - cm \n" - "rsb r4, r4, #0x100 @ r4 = 256-m \n" - "rsb r4, r3, r4, LSL #8 @ r4 = c1m1 =((256-m)<<8)-cm1 \n" - "mul r7, r4, r5 @ r7 = c1m1y = c1m1 * y \n" - "rsb r4, r7, r4, LSL #7 @ r4 = c1m1y1 = (c1m1<<7)-c1m1y \n" - "mul r10,r9, r5 @ r10= c1my = c1m * y \n" - "rsb r9, r10,r9, LSL #7 @ r9 = c1my1 = (c1m<<7) - c1my \n" - "mul r11,r3, r5 @ r11= cm1y = cm1 * y \n" - "rsb r3, r11,r3, LSL #7 @ r3 = cm1y1 = (cm1<<7) - cm1y \n" - "mul r5, r8, r5 @ r5 = cmy = cm * y \n" - "rsb r8, r5, r8, LSL #7 @ r8 = cmy1 = (cm<<7) - cmy \n" - "@ Register recap: \n" - "@ r3 = cm1y1 \n" - "@ r4 = c1m1y1 \n" - "@ r5 = cmy \n" - "@ r6 = k \n" - "@ r7 = c1m1y \n" - "@ r8 = cmy1 \n" - "@ r9 = c1my1 \n" - "@ r10= c1my \n" - "@ r11= cm1y \n" - "@ The actual matrix multiplication \n" - "mul r14,r4, r6 @ r14= x1 = c1m1y1 * k \n" - "rsb r4, r14,r4, LSL #8 @ r4 = x0 = (c1m1y1<<8) - x1 \n" - "add r4, r4, r14,LSR #8-5 @ r4 = b = x0 + 32*(x1>>8) \n" - "sub r1, r4, r14,LSR #8 @ r1 = g = x0 + 31*(x1>>8) \n" - "add r0, r1, r14,LSR #8-2 @ r0 = r = x0 + 35*(x1>>8) \n" - " \n" - "mul r14,r7, r6 @ r14= x1 = c1m1y * k \n" - "rsb r7, r14,r7, LSL #8 @ r7 = x0 = (c1m1y<<8) - x1 \n" - "add r0, r0, r7 @ r0 = r += x0 \n" - "add r1, r1, r7 @ r1 = g += (x0>>8 * 256) \n" - "sub r1, r1, r7, LSR #8-3 @ 248 \n" - "sub r1, r1, r7, LSR #8-2 @ 244 \n" - "sub r1, r1, r7, LSR #8 @ 243 \n" - "sub r7, r14,r14,LSR #3 @ r7 = 28*(x1>>5) \n" - "add r0, r0, r7, LSR #8-5 @ r0 = r += 28 * x1 \n" - "sub r7, r7, r14,LSR #4 @ r7 = 26*(x1>>5) \n" - "add r1, r1, r7, LSR #8-5 @ r1 = g += 26 * x1 \n" - " \n" - "mul r14,r9, r6 @ r14= x1 = c1my1 * k \n" - "sub r9, r9, r14,LSR #8 @ r9 = x0>>8 = c1my1 - (x1>>8) \n" - "add r0, r0, r14,LSR #8-5 @ r0 = r += (x1>>8)*32 \n" - "add r0, r0, r14,LSR #8-2 @ r0 = r += (x1>>8)*36 \n" - "mov r14,#237 @ r14= 237 \n" - "mla r0,r14,r9,r0 @ r14= r += x0*237 \n" - "mov r14,#141 @ r14= 141 \n" - "mla r4,r14,r9,r4 @ r14= b += x0*141 \n" - " \n" - "mul r14,r10,r6 @ r14= x1 = c1my * k \n" - "sub r10,r10,r14,LSR #8 @ r10= x0>>8 = c1my - (x1>>8) \n" - "add r0, r0, r14,LSR #8-5 @ r0 = r += 32 * x1 \n" - "add r0, r0, r14,LSR #8-1 @ r0 = r += 34 * x1 \n" - "mov r14,#238 @ r14= 238 \n" - "mla r0,r14,r10,r0 @ r0 = r += 238 * x0 \n" - "mov r14,#28 @ r14= 28 \n" - "mla r1,r14,r10,r1 @ r1 = g += 28 * x0 \n" - "mov r14,#36 @ r14= 36 \n" - "mla r4,r14,r10,r4 @ r4 = b += 36 * x0 \n" - " \n" - "mul r14,r3, r6 @ r14= x1 = cm1y1 * k \n" - "sub r3, r3, r14,LSR #8 @ r3 = x1>>8 = cm1y1 - (x1>>8) \n" - "add r1, r1, r14,LSR #8-4 @ r1 = g += 16*x1 \n" - "sub r1, r1, r14,LSR #8 @ 15*x1 \n" - "add r4, r4, r14,LSR #8-5 @ r4 = b += 32*x1 \n" - "add r4, r4, r14,LSR #8-2 @ 36*x1 \n" - "mov r14,#174 @ r14= 174 \n" - "mla r1, r14,r3, r1 @ r1 = g += 174 * x0 \n" - "mov r14,#240 @ r14= 240 \n" - "mla r4, r14,r3, r4 @ r4 = b += 240 * x0 \n" - " \n" - "mul r14,r11,r6 @ r14= x1 = cm1y * k \n" - "sub r11,r11,r14,LSR #8 @ r11= x0>>8 = cm1y - (x1>>8) \n" - "add r1, r1, r14,LSR #8-4 @ r1 = g += x1 * 16 \n" - "add r1, r1, r14,LSR #8 @ x1 * 17 \n" - "add r1, r1, r14,LSR #8-1 @ x1 * 19 \n" - "mov r14,#167 @ r14 = 167 \n" - "mla r1, r14,r11,r1 @ r1 = g += 167 * x0 \n" - "mov r14,#80 @ r14 = 80 \n" - "mla r4, r14,r11,r4 @ r4 = b += 80 * x0 \n" - " \n" - "mul r14,r8, r6 @ r14= x1 = cmy1 * k \n" - "sub r8, r8, r14,LSR #8 @ r8 = x0>>8 = cmy1 - (x1>>8) \n" - "add r4, r4, r14,LSR #8-1 @ r4 = b += x1 * 2 \n" - "mov r14,#46 @ r14=46 \n" - "mla r0, r14,r8, r0 @ r0 = r += 46 * x0 \n" - "mov r14,#49 @ r14=49 \n" - "mla r1, r14,r8, r1 @ r1 = g += 49 * x0 \n" - "mov r14,#147 @ r14=147 \n" - "mla r4, r14,r8, r4 @ r4 = b += 147 * x0 \n" - " \n" - "rsb r6, r6, #256 @ r6 = k = 256-k \n" - "mul r14,r5, r6 @ r14= x0 = cmy * (256-k) \n" - "mov r11,#54 @ r11= 54 \n" - "mov r14,r14,LSR #8 @ r14= (x0>>8) \n" - "mov r8,#57 @ r8 = 57 \n" - "mla r0,r14,r11,r0 @ r0 = r += 54*x0 \n" - "mla r1,r14,r11,r1 @ r1 = g += 54*x0 \n" - "mla r4,r14,r8, r4 @ r4 = b += 57*x0 \n" - " \n" - "sub r8, r0, r0, LSR #8 @ r8 = r -= (r>>8) \n" - "sub r9, r1, r1, LSR #8 @ r9 = g -= (r>>8) \n" - "sub r10,r4, r4, LSR #8 @ r10= b -= (r>>8) \n" - "ldmfd r13!,{r0-r1,r12} \n" - "mov r8, r8, LSR #23 @ r8 = r>>23 \n" - "mov r9, r9, LSR #23 @ r9 = g>>23 \n" - "mov r10,r10,LSR #23 @ r10= b>>23 \n" - "ldrb r14,[r1],#1 @ r8 = s[4] \n" - "strb r8, [r0],#1 @ d[0] = r \n" - "strb r9, [r0],#1 @ d[1] = g \n" - "strb r10,[r0],#1 @ d[2] = b \n" - "strb r14,[r0],#1 @ d[3] = s[4] \n" - "subs r2, r2, #1 @ r2 = n-- \n" - "beq 9f \n" - "@ At this point, we've just decoded a pixel \n" - "@ r0 = dst r1 = src r2 = n r8 = r r9 = g r10= b r12= CMYK \n" - "4: \n" - "ldrb r3, [r1], #4 @ r3 = c \n" - "ldrb r6, [r1, #-1] @ r6 = k \n" - "ldrb r5, [r1, #-2] @ r5 = y \n" - "ldrb r4, [r1, #-3] @ r4 = m \n" - "eors r11,r6, #0xFF @ if (k == 255) \n" - "beq 1b @ goto black \n" - "orr r7, r3, r4, LSL #8 \n" - "orr r14,r5, r6, LSL #8 \n" - "orrs r7, r7, r14,LSL #16 @ r7 = cmyk \n" - "beq 1b @ if (cmyk == 0) white \n" - "cmp r7, r12 @ if (cmyk != CMYK) \n" - "bne 3b @ not the same, loop \n" - "@ If we get here, we just matched a pixel we have just decoded \n" - "ldrb r3, [r1],#1 @ r8 = s[4] \n" - "strb r8, [r0],#1 @ d[0] = r \n" - "strb r9, [r0],#1 @ d[1] = g \n" - "strb r10,[r0],#1 @ d[2] = b \n" - "strb r3, [r0],#1 @ d[3] = s[4] \n" - "subs r2, r2, #1 @ r2 = n-- \n" - "bne 4b \n" - "9: \n" - "ldmfd r13!,{r4-r11,PC} @ pop, return to thumb \n" - ENTER_THUMB - ); -} -#endif - -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; - int n = src->w * src->h; -#ifdef ARCH_ARM - fast_cmyk_to_rgb_ARM(d, s, n); -#else - unsigned int C,M,Y,K,r,g,b; - - C = 0; - M = 0; - Y = 0; - K = 0; - r = 255; - g = 255; - b = 255; - - while (n--) - { -#ifdef SLOWCMYK - unsigned int c = s[0]; - unsigned int m = s[1]; - unsigned int y = s[2]; - unsigned int k = s[3]; - unsigned int cm, c1m, cm1, c1m1, c1m1y, c1m1y1, c1my, c1my1, cm1y, cm1y1, cmy, cmy1; - unsigned int x0, x1; - - if (c == C && m == M && y == Y && k == K) - { - /* Nothing to do */ - } - else if (k == 0 && c == 0 && m == 0 && y == 0) - { - r = g = b = 255; - } - else if (k == 255) - { - r = g = b = 0; - } - else - { - c += c>>7; - m += m>>7; - y += y>>7; - k += k>>7; - y >>= 1; /* Ditch 1 bit of Y to avoid overflow */ - cm = c * m; - c1m = (m<<8) - cm; - cm1 = (c<<8) - cm; - c1m1 = ((256 - m)<<8) - cm1; - c1m1y = c1m1 * y; - c1m1y1 = (c1m1<<7) - c1m1y; - c1my = c1m * y; - c1my1 = (c1m<<7) - c1my; - cm1y = cm1 * y; - cm1y1 = (cm1<<7) - cm1y; - cmy = cm * y; - cmy1 = (cm<<7) - cmy; - - /* this is a matrix multiplication, unrolled for performance */ - x1 = c1m1y1 * k; /* 0 0 0 1 */ - x0 = (c1m1y1<<8) - x1; /* 0 0 0 0 */ - x1 = x1>>8; /* From 23 fractional bits to 15 */ - r = g = b = x0; - r += 35 * x1; /* 0.1373 */ - g += 31 * x1; /* 0.1216 */ - b += 32 * x1; /* 0.1255 */ - - x1 = c1m1y * k; /* 0 0 1 1 */ - x0 = (c1m1y<<8) - x1; /* 0 0 1 0 */ - x1 >>= 8; /* From 23 fractional bits to 15 */ - r += 28 * x1; /* 0.1098 */ - g += 26 * x1; /* 0.1020 */ - r += x0; - x0 >>= 8; /* From 23 fractional bits to 15 */ - g += 243 * x0; /* 0.9490 */ - - x1 = c1my1 * k; /* 0 1 0 1 */ - x0 = (c1my1<<8) - x1; /* 0 1 0 0 */ - x1 >>= 8; /* From 23 fractional bits to 15 */ - x0 >>= 8; /* From 23 fractional bits to 15 */ - r += 36 * x1; /* 0.1412 */ - r += 237 * x0; /* 0.9255 */ - b += 141 * x0; /* 0.5490 */ - - x1 = c1my * k; /* 0 1 1 1 */ - x0 = (c1my<<8) - x1; /* 0 1 1 0 */ - x1 >>= 8; /* From 23 fractional bits to 15 */ - x0 >>= 8; /* From 23 fractional bits to 15 */ - r += 34 * x1; /* 0.1333 */ - r += 238 * x0; /* 0.9294 */ - g += 28 * x0; /* 0.1098 */ - b += 36 * x0; /* 0.1412 */ - - x1 = cm1y1 * k; /* 1 0 0 1 */ - x0 = (cm1y1<<8) - x1; /* 1 0 0 0 */ - x1 >>= 8; /* From 23 fractional bits to 15 */ - x0 >>= 8; /* From 23 fractional bits to 15 */ - g += 15 * x1; /* 0.0588 */ - b += 36 * x1; /* 0.1412 */ - g += 174 * x0; /* 0.6784 */ - b += 240 * x0; /* 0.9373 */ - - x1 = cm1y * k; /* 1 0 1 1 */ - x0 = (cm1y<<8) - x1; /* 1 0 1 0 */ - x1 >>= 8; /* From 23 fractional bits to 15 */ - x0 >>= 8; /* From 23 fractional bits to 15 */ - g += 19 * x1; /* 0.0745 */ - g += 167 * x0; /* 0.6510 */ - b += 80 * x0; /* 0.3137 */ - - x1 = cmy1 * k; /* 1 1 0 1 */ - x0 = (cmy1<<8) - x1; /* 1 1 0 0 */ - x1 >>= 8; /* From 23 fractional bits to 15 */ - x0 >>= 8; /* From 23 fractional bits to 15 */ - b += 2 * x1; /* 0.0078 */ - r += 46 * x0; /* 0.1804 */ - g += 49 * x0; /* 0.1922 */ - b += 147 * x0; /* 0.5725 */ - - x0 = cmy * (256-k); /* 1 1 1 0 */ - x0 >>= 8; /* From 23 fractional bits to 15 */ - r += 54 * x0; /* 0.2118 */ - g += 54 * x0; /* 0.2119 */ - b += 57 * x0; /* 0.2235 */ - - r -= (r>>8); - g -= (g>>8); - b -= (b>>8); - r = r>>23; - g = g>>23; - b = b>>23; - C = c; - M = m; - Y = y; - K = k; - } - d[0] = r; - d[1] = g; - d[2] = b; -#else - d[0] = 255 - (unsigned char)fz_mini(s[0] + s[3], 255); - d[1] = 255 - (unsigned char)fz_mini(s[1] + s[3], 255); - d[2] = 255 - (unsigned char)fz_mini(s[2] + s[3], 255); -#endif - d[3] = s[4]; - s += 5; - d += 4; - } -#endif -} - -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; - int n = src->w * src->h; - while (n--) - { -#ifdef SLOWCMYK - float cmyk[4], rgb[3]; - cmyk[0] = s[0] / 255.0f; - cmyk[1] = s[1] / 255.0f; - cmyk[2] = s[2] / 255.0f; - cmyk[3] = s[3] / 255.0f; - cmyk_to_rgb(ctx, NULL, cmyk, rgb); - d[0] = rgb[2] * 255; - d[1] = rgb[1] * 255; - d[2] = rgb[0] * 255; -#else - d[0] = 255 - (unsigned char)fz_mini(s[2] + s[3], 255); - d[1] = 255 - (unsigned char)fz_mini(s[1] + s[3], 255); - d[2] = 255 - (unsigned char)fz_mini(s[0] + s[3], 255); -#endif - d[3] = s[4]; - s += 5; - d += 4; - } -} - -static void fast_rgb_to_bgr(fz_pixmap *dst, fz_pixmap *src) -{ - unsigned char *s = src->samples; - unsigned char *d = dst->samples; - int n = src->w * src->h; - while (n--) - { - d[0] = s[2]; - d[1] = s[1]; - d[2] = s[0]; - d[3] = s[3]; - s += 4; - d += 4; - } -} - -static void -fz_std_conv_pixmap(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src) -{ - float srcv[FZ_MAX_COLORS]; - float dstv[FZ_MAX_COLORS]; - int srcn, dstn; - int k, i; - unsigned int xy; - - fz_colorspace *ss = src->colorspace; - fz_colorspace *ds = dst->colorspace; - - unsigned char *s = src->samples; - unsigned char *d = dst->samples; - - assert(src->w == dst->w && src->h == dst->h); - assert(src->n == ss->n + 1); - assert(dst->n == ds->n + 1); - - srcn = ss->n; - dstn = ds->n; - - xy = (unsigned int)(src->w * src->h); - - /* Special case for Lab colorspace (scaling of components to float) */ - if (!strcmp(ss->name, "Lab") && srcn == 3) - { - fz_color_converter cc; - - fz_lookup_color_converter(&cc, ctx, ds, ss); - for (; xy > 0; xy--) - { - srcv[0] = *s++ / 255.0f * 100; - srcv[1] = *s++ - 128; - srcv[2] = *s++ - 128; - - cc.convert(&cc, dstv, srcv); - - for (k = 0; k < dstn; k++) - *d++ = dstv[k] * 255; - - *d++ = *s++; - } - } - - /* Brute-force for small images */ - else if (xy < 256) - { - fz_color_converter cc; - - fz_lookup_color_converter(&cc, ctx, ds, ss); - for (; xy > 0; xy--) - { - for (k = 0; k < srcn; k++) - srcv[k] = *s++ / 255.0f; - - cc.convert(&cc, dstv, srcv); - - for (k = 0; k < dstn; k++) - *d++ = dstv[k] * 255; - - *d++ = *s++; - } - } - - /* 1-d lookup table for separation and similar colorspaces */ - else if (srcn == 1) - { - unsigned char lookup[FZ_MAX_COLORS * 256]; - fz_color_converter cc; - - fz_lookup_color_converter(&cc, ctx, ds, ss); - for (i = 0; i < 256; i++) - { - srcv[0] = i / 255.0f; - cc.convert(&cc, dstv, srcv); - for (k = 0; k < dstn; k++) - lookup[i * dstn + k] = dstv[k] * 255; - } - - for (; xy > 0; xy--) - { - i = *s++; - for (k = 0; k < dstn; k++) - *d++ = lookup[i * dstn + k]; - *d++ = *s++; - } - } - - /* Memoize colors using a hash table for the general case */ - else - { - fz_hash_table *lookup; - unsigned char *color; - unsigned char dummy = s[0] ^ 255; - unsigned char *sold = &dummy; - fz_color_converter cc; - - fz_lookup_color_converter(&cc, ctx, ds, ss); - lookup = fz_new_hash_table(ctx, 509, srcn, -1); - - for (; xy > 0; xy--) - { - if (*s == *sold && memcmp(sold,s,srcn) == 0) - { - sold = s; - memcpy(d, d-dstn-1, dstn); - d += dstn; - s += srcn; - *d++ = *s++; - } - else - { - sold = s; - color = fz_hash_find(ctx, lookup, s); - if (color) - { - memcpy(d, color, dstn); - s += srcn; - d += dstn; - *d++ = *s++; - } - else - { - for (k = 0; k < srcn; k++) - srcv[k] = *s++ / 255.0f; - cc.convert(&cc, dstv, srcv); - for (k = 0; k < dstn; k++) - *d++ = dstv[k] * 255; - - fz_hash_insert(ctx, lookup, s - srcn, d - dstn); - - *d++ = *s++; - } - } - } - - fz_free_hash(ctx, lookup); - } -} - -void -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); - - dp->interpolate = sp->interpolate; - - if (ss == fz_default_gray) - { - if (ds == fz_default_rgb) fast_gray_to_rgb(dp, sp); - else if (ds == fz_default_bgr) fast_gray_to_rgb(dp, sp); /* bgr == rgb here */ - else if (ds == fz_default_cmyk) fast_gray_to_cmyk(dp, sp); - else fz_std_conv_pixmap(ctx, dp, sp); - } - - else if (ss == fz_default_rgb) - { - if (ds == fz_default_gray) fast_rgb_to_gray(dp, sp); - else if (ds == fz_default_bgr) fast_rgb_to_bgr(dp, sp); - else if (ds == fz_default_cmyk) fast_rgb_to_cmyk(dp, sp); - else fz_std_conv_pixmap(ctx, dp, sp); - } - - else if (ss == fz_default_bgr) - { - if (ds == fz_default_gray) fast_bgr_to_gray(dp, sp); - else if (ds == fz_default_rgb) fast_rgb_to_bgr(dp, sp); /* bgr = rgb here */ - else if (ds == fz_default_cmyk) fast_bgr_to_cmyk(sp, dp); - else fz_std_conv_pixmap(ctx, dp, sp); - } - - else if (ss == fz_default_cmyk) - { - if (ds == fz_default_gray) fast_cmyk_to_gray(dp, sp); - else if (ds == fz_default_bgr) fast_cmyk_to_bgr(ctx, dp, sp); - else if (ds == fz_default_rgb) fast_cmyk_to_rgb(ctx, dp, sp); - else fz_std_conv_pixmap(ctx, dp, sp); - } - - else fz_std_conv_pixmap(ctx, dp, sp); -} - -/* Convert a single color */ - -static void -std_conv_color(fz_color_converter *cc, float *dstv, float *srcv) -{ - float rgb[3]; - int i; - fz_colorspace *srcs = cc->ss; - fz_colorspace *dsts = cc->ds; - fz_context *ctx = cc->ctx; - - if (srcs != dsts) - { - assert(srcs->to_rgb && dsts->from_rgb); - srcs->to_rgb(ctx, srcs, srcv, rgb); - dsts->from_rgb(ctx, dsts, rgb, dstv); - for (i = 0; i < dsts->n; i++) - dstv[i] = fz_clamp(dstv[i], 0, 1); - } - else - { - for (i = 0; i < srcs->n; i++) - dstv[i] = srcv[i]; - } -} - -static void -g2rgb(fz_color_converter *cc, float *dv, float *sv) -{ - dv[0] = sv[0]; - dv[1] = sv[0]; - dv[2] = sv[0]; -} - -static void -g2cmyk(fz_color_converter *cc, float *dv, float *sv) -{ - dv[0] = 0; - dv[1] = 0; - dv[2] = 0; - dv[3] = sv[0]; -} - -static void -rgb2g(fz_color_converter *cc, float *dv, float *sv) -{ - dv[0] = sv[0] * 0.3f + sv[1] * 0.59f + sv[2] * 0.11f; -} - -static void -rgb2bgr(fz_color_converter *cc, float *dv, float *sv) -{ - dv[0] = sv[2]; - dv[1] = sv[1]; - dv[2] = sv[0]; -} - -static void -rgb2cmyk(fz_color_converter *cc, float *dv, float *sv) -{ - float c = 1 - sv[0]; - float m = 1 - sv[1]; - float y = 1 - sv[2]; - float k = fz_min(c, fz_min(m, y)); - dv[0] = c - k; - dv[1] = m - k; - dv[2] = y - k; - dv[3] = k; -} - -static void -bgr2g(fz_color_converter *cc, float *dv, float *sv) -{ - dv[0] = sv[0] * 0.11f + sv[1] * 0.59f + sv[2] * 0.3f; -} - -static void -bgr2cmyk(fz_color_converter *cc, float *dv, float *sv) -{ - float c = 1 - sv[2]; - float m = 1 - sv[1]; - float y = 1 - sv[0]; - float k = fz_min(c, fz_min(m, y)); - dv[0] = c - k; - dv[1] = m - k; - dv[2] = y - k; - dv[3] = k; -} - -static void -cmyk2g(fz_color_converter *cc, float *dv, float *sv) -{ - float c = sv[0] * 0.3f; - float m = sv[1] * 0.59f; - float y = sv[2] * 0.11f; - dv[0] = 1 - fz_min(c + m + y + sv[3], 1); -} - -static void -cmyk2rgb(fz_color_converter *cc, float *dv, float *sv) -{ -#ifdef SLOWCMYK - cmyk_to_rgb(cc->ctx, NULL, sv, dv); -#else - dv[0] = 1 - fz_min(sv[0] + sv[3], 1); - dv[1] = 1 - fz_min(sv[1] + sv[3], 1); - dv[2] = 1 - fz_min(sv[2] + sv[3], 1); -#endif -} - -static void -cmyk2bgr(fz_color_converter *cc, float *dv, float *sv) -{ -#ifdef SLOWCMYK - float rgb[3]; - cmyk_to_rgb(cc->ctx, NULL, sv, rgb); - dv[0] = rgb[2]; - dv[1] = rgb[1]; - dv[2] = rgb[0]; -#else - dv[0] = 1 - fz_min(sv[2] + sv[3], 1); - dv[1] = 1 - fz_min(sv[1] + sv[3], 1); - dv[2] = 1 - fz_min(sv[0] + sv[3], 1); -#endif -} - -void fz_lookup_color_converter(fz_color_converter *cc, fz_context *ctx, fz_colorspace *ds, fz_colorspace *ss) -{ - cc->ctx = ctx; - cc->ds = ds; - cc->ss = ss; - if (ss == fz_default_gray) - { - if ((ds == fz_default_rgb) || (ds == fz_default_bgr)) - cc->convert = g2rgb; - else if (ds == fz_default_cmyk) - cc->convert = g2cmyk; - else - cc->convert = std_conv_color; - } - - else if (ss == fz_default_rgb) - { - if (ds == fz_default_gray) - cc->convert = rgb2g; - else if (ds == fz_default_bgr) - cc->convert = rgb2bgr; - else if (ds == fz_default_cmyk) - cc->convert = rgb2cmyk; - else - cc->convert = std_conv_color; - } - - else if (ss == fz_default_bgr) - { - if (ds == fz_default_gray) - cc->convert = bgr2g; - else if (ds == fz_default_rgb) - cc->convert = rgb2bgr; - else if (ds == fz_default_cmyk) - cc->convert = bgr2cmyk; - else - cc->convert = std_conv_color; - } - - else if (ss == fz_default_cmyk) - { - if (ds == fz_default_gray) - cc->convert = cmyk2g; - else if (ds == fz_default_rgb) - cc->convert = cmyk2rgb; - else if (ds == fz_default_bgr) - cc->convert = cmyk2bgr; - else - cc->convert = std_conv_color; - } - - else - cc->convert = std_conv_color; -} - -void -fz_convert_color(fz_context *ctx, fz_colorspace *ds, float *dv, fz_colorspace *ss, float *sv) -{ - fz_color_converter cc; - - fz_lookup_color_converter(&cc, ctx, ds, ss); - cc.convert(&cc, dv, sv); -} - -/* Indexed */ - -struct indexed -{ - fz_colorspace *base; - int high; - unsigned char *lookup; -}; - -static void -indexed_to_rgb(fz_context *ctx, fz_colorspace *cs, float *color, float *rgb) -{ - struct indexed *idx = cs->data; - float alt[FZ_MAX_COLORS]; - int i, k; - i = color[0] * 255; - i = fz_clampi(i, 0, idx->high); - for (k = 0; k < idx->base->n; k++) - alt[k] = idx->lookup[i * idx->base->n + k] / 255.0f; - idx->base->to_rgb(ctx, idx->base, alt, rgb); -} - -static void -free_indexed(fz_context *ctx, fz_colorspace *cs) -{ - struct indexed *idx = cs->data; - if (idx->base) - fz_drop_colorspace(ctx, idx->base); - fz_free(ctx, idx->lookup); - fz_free(ctx, idx); -} - -fz_colorspace * -fz_new_indexed_colorspace(fz_context *ctx, fz_colorspace *base, int high, unsigned char *lookup) -{ - fz_colorspace *cs; - struct indexed *idx; - - idx = fz_malloc_struct(ctx, struct indexed); - idx->lookup = lookup; - idx->base = base; - idx->high = high; - - fz_try(ctx) - { - cs = fz_new_colorspace(ctx, "Indexed", 1); - cs->to_rgb = indexed_to_rgb; - cs->free_data = free_indexed; - cs->data = idx; - cs->size += sizeof(*idx) + (base->n * (idx->high + 1)) + base->size; - } - fz_catch(ctx) - { - fz_free(ctx, idx); - fz_rethrow_message(ctx, "failed to create indexed colorspace"); - } - return cs; -} - -fz_pixmap * -fz_expand_indexed_pixmap(fz_context *ctx, fz_pixmap *src) -{ - struct indexed *idx; - fz_pixmap *dst; - unsigned char *s, *d; - int y, x, k, n, high; - unsigned char *lookup; - fz_irect bbox; - - assert(src->colorspace->to_rgb == indexed_to_rgb); - assert(src->n == 2); - - idx = src->colorspace->data; - high = idx->high; - lookup = idx->lookup; - n = idx->base->n; - - dst = fz_new_pixmap_with_bbox(ctx, idx->base, fz_pixmap_bbox(ctx, src, &bbox)); - s = src->samples; - d = dst->samples; - - for (y = 0; y < src->h; y++) - { - for (x = 0; x < src->w; x++) - { - int v = *s++; - int a = *s++; - v = fz_mini(v, high); - for (k = 0; k < n; k++) - *d++ = fz_mul255(lookup[v * n + k], a); - *d++ = a; - } - } - - dst->interpolate = src->interpolate; - - return dst; -} diff --git a/fitz/res_font.c b/fitz/res_font.c deleted file mode 100644 index e8613f84..00000000 --- a/fitz/res_font.c +++ /dev/null @@ -1,1094 +0,0 @@ -#include "mupdf/fitz.h" - -#include -#include FT_FREETYPE_H -#include FT_STROKER_H - -#define MAX_BBOX_TABLE_SIZE 4096 - -/* 20 degrees */ -#define SHEAR 0.36397f - -static void fz_drop_freetype(fz_context *ctx); - -static fz_font * -fz_new_font(fz_context *ctx, char *name, int use_glyph_bbox, int glyph_count) -{ - fz_font *font; - int i; - - font = fz_malloc_struct(ctx, fz_font); - font->refs = 1; - - if (name) - fz_strlcpy(font->name, name, sizeof font->name); - else - fz_strlcpy(font->name, "(null)", sizeof font->name); - - font->ft_face = NULL; - font->ft_substitute = 0; - font->ft_bold = 0; - font->ft_italic = 0; - font->ft_hint = 0; - - font->ft_file = NULL; - font->ft_data = NULL; - font->ft_size = 0; - - font->t3matrix = fz_identity; - font->t3resources = NULL; - font->t3procs = NULL; - font->t3lists = NULL; - font->t3widths = NULL; - font->t3flags = NULL; - font->t3doc = NULL; - font->t3run = NULL; - - font->bbox.x0 = 0; - font->bbox.y0 = 0; - font->bbox.x1 = 1; - font->bbox.y1 = 1; - - font->use_glyph_bbox = use_glyph_bbox; - if (use_glyph_bbox && glyph_count <= MAX_BBOX_TABLE_SIZE) - { - font->bbox_count = glyph_count; - font->bbox_table = fz_malloc_array(ctx, glyph_count, sizeof(fz_rect)); - for (i = 0; i < glyph_count; i++) - font->bbox_table[i] = fz_infinite_rect; - } - else - { - if (use_glyph_bbox) - fz_warn(ctx, "not building glyph bbox table for font '%s' with %d glyphs", font->name, glyph_count); - font->bbox_count = 0; - font->bbox_table = NULL; - } - - font->width_count = 0; - font->width_table = NULL; - - return font; -} - -fz_font * -fz_keep_font(fz_context *ctx, fz_font *font) -{ - if (!font) - return NULL; - fz_lock(ctx, FZ_LOCK_ALLOC); - font->refs ++; - fz_unlock(ctx, FZ_LOCK_ALLOC); - return font; -} - -void -fz_drop_font(fz_context *ctx, fz_font *font) -{ - int fterr; - int i, drop; - - fz_lock(ctx, FZ_LOCK_ALLOC); - drop = (font && --font->refs == 0); - fz_unlock(ctx, FZ_LOCK_ALLOC); - if (!drop) - return; - - if (font->t3procs) - { - if (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]); - if (font->t3lists[i]) - fz_drop_display_list(ctx, font->t3lists[i]); - } - fz_free(ctx, font->t3procs); - fz_free(ctx, font->t3lists); - fz_free(ctx, font->t3widths); - fz_free(ctx, font->t3flags); - } - - if (font->ft_face) - { - fz_lock(ctx, FZ_LOCK_FREETYPE); - fterr = FT_Done_Face((FT_Face)font->ft_face); - fz_unlock(ctx, FZ_LOCK_FREETYPE); - if (fterr) - fz_warn(ctx, "freetype finalizing face: %s", ft_error_string(fterr)); - fz_drop_freetype(ctx); - } - - fz_free(ctx, font->ft_file); - fz_free(ctx, font->ft_data); - fz_free(ctx, font->bbox_table); - fz_free(ctx, font->width_table); - fz_free(ctx, font); -} - -void -fz_set_font_bbox(fz_context *ctx, fz_font *font, float xmin, float ymin, float xmax, float ymax) -{ - if (xmin >= xmax || ymin >= ymax) - { - /* Invalid bbox supplied. It would be prohibitively slow to - * measure the true one, so make one up. */ - font->bbox.x0 = -1; - font->bbox.y0 = -1; - font->bbox.x1 = 2; - font->bbox.y1 = 2; - } - else - { - font->bbox.x0 = xmin; - font->bbox.y0 = ymin; - font->bbox.x1 = xmax; - font->bbox.y1 = ymax; - } -} - -/* - * Freetype hooks - */ - -struct fz_font_context_s { - int ctx_refs; - FT_Library ftlib; - int ftlib_refs; -}; - -#undef __FTERRORS_H__ -#define FT_ERRORDEF(e, v, s) { (e), (s) }, -#define FT_ERROR_START_LIST -#define FT_ERROR_END_LIST { 0, NULL } - -struct ft_error -{ - int err; - char *str; -}; - -void fz_new_font_context(fz_context *ctx) -{ - ctx->font = fz_malloc_struct(ctx, fz_font_context); - ctx->font->ctx_refs = 1; - ctx->font->ftlib = NULL; - ctx->font->ftlib_refs = 0; -} - -fz_font_context * -fz_keep_font_context(fz_context *ctx) -{ - if (!ctx || !ctx->font) - return NULL; - fz_lock(ctx, FZ_LOCK_ALLOC); - ctx->font->ctx_refs++; - fz_unlock(ctx, FZ_LOCK_ALLOC); - return ctx->font; -} - -void fz_drop_font_context(fz_context *ctx) -{ - int drop; - if (!ctx || !ctx->font) - return; - fz_lock(ctx, FZ_LOCK_ALLOC); - drop = --ctx->font->ctx_refs; - fz_unlock(ctx, FZ_LOCK_ALLOC); - if (drop == 0) - fz_free(ctx, ctx->font); -} - -static const struct ft_error ft_errors[] = -{ -#include FT_ERRORS_H -}; - -char *ft_error_string(int err) -{ - const struct ft_error *e; - - for (e = ft_errors; e->str; e++) - if (e->err == err) - return e->str; - - return "Unknown error"; -} - -static void -fz_keep_freetype(fz_context *ctx) -{ - int fterr; - int maj, min, pat; - fz_font_context *fct = ctx->font; - - fz_lock(ctx, FZ_LOCK_FREETYPE); - if (fct->ftlib) - { - fct->ftlib_refs++; - fz_unlock(ctx, FZ_LOCK_FREETYPE); - return; - } - - fterr = FT_Init_FreeType(&fct->ftlib); - if (fterr) - { - char *mess = ft_error_string(fterr); - fz_unlock(ctx, FZ_LOCK_FREETYPE); - fz_throw(ctx, FZ_ERROR_GENERIC, "cannot init freetype: %s", mess); - } - - FT_Library_Version(fct->ftlib, &maj, &min, &pat); - if (maj == 2 && min == 1 && pat < 7) - { - fterr = FT_Done_FreeType(fct->ftlib); - if (fterr) - fz_warn(ctx, "freetype finalizing: %s", ft_error_string(fterr)); - fz_unlock(ctx, FZ_LOCK_FREETYPE); - fz_throw(ctx, FZ_ERROR_GENERIC, "freetype version too old: %d.%d.%d", maj, min, pat); - } - - fct->ftlib_refs++; - fz_unlock(ctx, FZ_LOCK_FREETYPE); -} - -static void -fz_drop_freetype(fz_context *ctx) -{ - int fterr; - fz_font_context *fct = ctx->font; - - fz_lock(ctx, FZ_LOCK_FREETYPE); - if (--fct->ftlib_refs == 0) - { - fterr = FT_Done_FreeType(fct->ftlib); - if (fterr) - fz_warn(ctx, "freetype finalizing: %s", ft_error_string(fterr)); - fct->ftlib = NULL; - } - fz_unlock(ctx, FZ_LOCK_FREETYPE); -} - -fz_font * -fz_new_font_from_file(fz_context *ctx, char *name, char *path, int index, int use_glyph_bbox) -{ - FT_Face face; - fz_font *font; - int fterr; - - fz_keep_freetype(ctx); - - fz_lock(ctx, FZ_LOCK_FREETYPE); - fterr = FT_New_Face(ctx->font->ftlib, path, index, &face); - fz_unlock(ctx, FZ_LOCK_FREETYPE); - if (fterr) - { - fz_drop_freetype(ctx); - fz_throw(ctx, FZ_ERROR_GENERIC, "freetype: cannot load font: %s", ft_error_string(fterr)); - } - - if (!name) - name = face->family_name; - - font = fz_new_font(ctx, name, use_glyph_bbox, face->num_glyphs); - font->ft_face = face; - fz_set_font_bbox(ctx, font, - (float) face->bbox.xMin / face->units_per_EM, - (float) face->bbox.yMin / face->units_per_EM, - (float) face->bbox.xMax / face->units_per_EM, - (float) face->bbox.yMax / face->units_per_EM); - - return font; -} - -fz_font * -fz_new_font_from_memory(fz_context *ctx, char *name, unsigned char *data, int len, int index, int use_glyph_bbox) -{ - FT_Face face; - fz_font *font; - int fterr; - - fz_keep_freetype(ctx); - - fz_lock(ctx, FZ_LOCK_FREETYPE); - fterr = FT_New_Memory_Face(ctx->font->ftlib, data, len, index, &face); - fz_unlock(ctx, FZ_LOCK_FREETYPE); - if (fterr) - { - fz_drop_freetype(ctx); - fz_throw(ctx, FZ_ERROR_GENERIC, "freetype: cannot load font: %s", ft_error_string(fterr)); - } - - if (!name) - name = face->family_name; - - font = fz_new_font(ctx, name, use_glyph_bbox, face->num_glyphs); - font->ft_face = face; - fz_set_font_bbox(ctx, font, - (float) face->bbox.xMin / face->units_per_EM, - (float) face->bbox.yMin / face->units_per_EM, - (float) face->bbox.xMax / face->units_per_EM, - (float) face->bbox.yMax / face->units_per_EM); - - return font; -} - -static fz_matrix * -fz_adjust_ft_glyph_width(fz_context *ctx, fz_font *font, int gid, fz_matrix *trm) -{ - /* Fudge the font matrix to stretch the glyph if we've substituted the font. */ - if (font->ft_substitute && font->width_table && gid < font->width_count) - { - FT_Error fterr; - int subw; - int realw; - float scale; - - fz_lock(ctx, FZ_LOCK_FREETYPE); - /* TODO: use FT_Get_Advance */ - fterr = FT_Set_Char_Size(font->ft_face, 1000, 1000, 72, 72); - if (fterr) - fz_warn(ctx, "freetype setting character size: %s", ft_error_string(fterr)); - - fterr = FT_Load_Glyph(font->ft_face, gid, - FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP | FT_LOAD_IGNORE_TRANSFORM); - if (fterr) - fz_warn(ctx, "freetype failed to load glyph: %s", ft_error_string(fterr)); - - realw = ((FT_Face)font->ft_face)->glyph->metrics.horiAdvance; - fz_unlock(ctx, FZ_LOCK_FREETYPE); - subw = font->width_table[gid]; - if (realw) - scale = (float) subw / realw; - else - scale = 1; - - fz_pre_scale(trm, scale, 1); - } - - return trm; -} - -static fz_pixmap * -fz_copy_ft_bitmap(fz_context *ctx, int left, int top, FT_Bitmap *bitmap) -{ - fz_pixmap *pixmap; - int y; - - pixmap = fz_new_pixmap(ctx, NULL, bitmap->width, bitmap->rows); - pixmap->x = left; - pixmap->y = top - bitmap->rows; - - if (bitmap->pixel_mode == FT_PIXEL_MODE_MONO) - { - for (y = 0; y < pixmap->h; y++) - { - unsigned char *out = pixmap->samples + (unsigned int)(y * pixmap->w); - unsigned char *in = bitmap->buffer + (unsigned int)((pixmap->h - y - 1) * bitmap->pitch); - unsigned char bit = 0x80; - int w = pixmap->w; - while (w--) - { - *out++ = (*in & bit) ? 255 : 0; - bit >>= 1; - if (bit == 0) - { - bit = 0x80; - in++; - } - } - } - } - else - { - for (y = 0; y < pixmap->h; y++) - { - memcpy(pixmap->samples + (unsigned int)(y * pixmap->w), - bitmap->buffer + (unsigned int)((pixmap->h - y - 1) * bitmap->pitch), - pixmap->w); - } - } - - return pixmap; -} - -/* 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, const fz_matrix *trm, int aa) -{ - FT_Face face = font->ft_face; - FT_Matrix m; - FT_Vector v; - FT_Error fterr; - fz_pixmap *result; - fz_matrix local_trm = *trm; - - float strength = fz_matrix_expansion(trm) * 0.02f; - - fz_adjust_ft_glyph_width(ctx, font, gid, &local_trm); - - if (font->ft_italic) - fz_pre_shear(&local_trm, SHEAR, 0); - - /* - Freetype mutilates complex glyphs if they are loaded - with FT_Set_Char_Size 1.0. it rounds the coordinates - before applying transformation. to get more precision in - freetype, we shift part of the scale in the matrix - into FT_Set_Char_Size instead - */ - - m.xx = local_trm.a * 64; /* should be 65536 */ - m.yx = local_trm.b * 64; - m.xy = local_trm.c * 64; - m.yy = local_trm.d * 64; - v.x = local_trm.e * 64; - v.y = local_trm.f * 64; - - fz_lock(ctx, FZ_LOCK_FREETYPE); - fterr = FT_Set_Char_Size(face, 65536, 65536, 72, 72); /* should be 64, 64 */ - if (fterr) - fz_warn(ctx, "freetype setting character size: %s", ft_error_string(fterr)); - FT_Set_Transform(face, &m, &v); - - if (aa == 0) - { - /* enable grid fitting for non-antialiased rendering */ - float scale = fz_matrix_expansion(&local_trm); - m.xx = local_trm.a * 65536 / scale; - m.xy = local_trm.b * 65536 / scale; - m.yx = local_trm.c * 65536 / scale; - m.yy = local_trm.d * 65536 / scale; - v.x = 0; - v.y = 0; - - fterr = FT_Set_Char_Size(face, 64 * scale, 64 * scale, 72, 72); - if (fterr) - fz_warn(ctx, "freetype setting character size: %s", ft_error_string(fterr)); - FT_Set_Transform(face, &m, &v); - fterr = FT_Load_Glyph(face, gid, FT_LOAD_NO_BITMAP | FT_LOAD_TARGET_MONO); - if (fterr) { - fz_warn(ctx, "freetype load hinted glyph (gid %d): %s", gid, ft_error_string(fterr)); - goto retry_unhinted; - } - } - else if (font->ft_hint) - { - /* - Enable hinting, but keep the huge char size so that - it is hinted for a character. This will in effect nullify - the effect of grid fitting. This form of hinting should - only be used for DynaLab and similar tricky TrueType fonts, - so that we get the correct outline shape. - */ - fterr = FT_Load_Glyph(face, gid, FT_LOAD_NO_BITMAP); - if (fterr) { - fz_warn(ctx, "freetype load hinted glyph (gid %d): %s", gid, ft_error_string(fterr)); - goto retry_unhinted; - } - } - else - { -retry_unhinted: - fterr = FT_Load_Glyph(face, gid, FT_LOAD_NO_BITMAP | FT_LOAD_NO_HINTING); - if (fterr) - { - fz_warn(ctx, "freetype load glyph (gid %d): %s", gid, ft_error_string(fterr)); - fz_unlock(ctx, FZ_LOCK_FREETYPE); - return NULL; - } - } - - if (font->ft_bold) - { - FT_Outline_Embolden(&face->glyph->outline, strength * 64); - FT_Outline_Translate(&face->glyph->outline, -strength * 32, -strength * 32); - } - - 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_try(ctx) - { - result = fz_copy_ft_bitmap(ctx, face->glyph->bitmap_left, face->glyph->bitmap_top, &face->glyph->bitmap); - } - fz_always(ctx) - { - fz_unlock(ctx, FZ_LOCK_FREETYPE); - } - fz_catch(ctx) - { - fz_rethrow(ctx); - } - - return result; -} - -fz_pixmap * -fz_render_ft_stroked_glyph(fz_context *ctx, fz_font *font, int gid, const fz_matrix *trm, const fz_matrix *ctm, fz_stroke_state *state) -{ - FT_Face face = font->ft_face; - float expansion = fz_matrix_expansion(ctm); - int linewidth = state->linewidth * expansion * 64 / 2; - FT_Matrix m; - FT_Vector v; - FT_Error fterr; - FT_Stroker stroker; - FT_Glyph glyph; - FT_BitmapGlyph bitmap; - fz_pixmap *pixmap; - FT_Stroker_LineJoin line_join; - fz_matrix local_trm = *trm; - - fz_adjust_ft_glyph_width(ctx, font, gid, &local_trm); - - if (font->ft_italic) - fz_pre_shear(&local_trm, SHEAR, 0); - - m.xx = local_trm.a * 64; /* should be 65536 */ - m.yx = local_trm.b * 64; - m.xy = local_trm.c * 64; - m.yy = local_trm.d * 64; - v.x = local_trm.e * 64; - v.y = local_trm.f * 64; - - fz_lock(ctx, FZ_LOCK_FREETYPE); - fterr = FT_Set_Char_Size(face, 65536, 65536, 72, 72); /* should be 64, 64 */ - if (fterr) - { - fz_warn(ctx, "FT_Set_Char_Size: %s", ft_error_string(fterr)); - fz_unlock(ctx, FZ_LOCK_FREETYPE); - return NULL; - } - - FT_Set_Transform(face, &m, &v); - - fterr = FT_Load_Glyph(face, gid, FT_LOAD_NO_BITMAP | FT_LOAD_NO_HINTING); - if (fterr) - { - fz_warn(ctx, "FT_Load_Glyph(gid %d): %s", gid, ft_error_string(fterr)); - fz_unlock(ctx, FZ_LOCK_FREETYPE); - return NULL; - } - - fterr = FT_Stroker_New(ctx->font->ftlib, &stroker); - if (fterr) - { - fz_warn(ctx, "FT_Stroker_New: %s", ft_error_string(fterr)); - fz_unlock(ctx, FZ_LOCK_FREETYPE); - return NULL; - } - -#if FREETYPE_MAJOR * 10000 + FREETYPE_MINOR * 100 + FREETYPE_PATCH > 20405 - /* New freetype */ - line_join = - state->linejoin == FZ_LINEJOIN_MITER ? FT_STROKER_LINEJOIN_MITER_FIXED : - state->linejoin == FZ_LINEJOIN_ROUND ? FT_STROKER_LINEJOIN_ROUND : - state->linejoin == FZ_LINEJOIN_BEVEL ? FT_STROKER_LINEJOIN_BEVEL : - FT_STROKER_LINEJOIN_MITER_VARIABLE; -#else - /* Old freetype */ - line_join = - state->linejoin == FZ_LINEJOIN_MITER ? FT_STROKER_LINEJOIN_MITER : - state->linejoin == FZ_LINEJOIN_ROUND ? FT_STROKER_LINEJOIN_ROUND : - state->linejoin == FZ_LINEJOIN_BEVEL ? FT_STROKER_LINEJOIN_BEVEL : - FT_STROKER_LINEJOIN_MITER; -#endif - FT_Stroker_Set(stroker, linewidth, (FT_Stroker_LineCap)state->start_cap, line_join, state->miterlimit * 65536); - - fterr = FT_Get_Glyph(face->glyph, &glyph); - if (fterr) - { - fz_warn(ctx, "FT_Get_Glyph: %s", ft_error_string(fterr)); - FT_Stroker_Done(stroker); - fz_unlock(ctx, FZ_LOCK_FREETYPE); - return NULL; - } - - fterr = FT_Glyph_Stroke(&glyph, stroker, 1); - if (fterr) - { - fz_warn(ctx, "FT_Glyph_Stroke: %s", ft_error_string(fterr)); - FT_Done_Glyph(glyph); - FT_Stroker_Done(stroker); - fz_unlock(ctx, FZ_LOCK_FREETYPE); - return NULL; - } - - FT_Stroker_Done(stroker); - - 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)); - FT_Done_Glyph(glyph); - fz_unlock(ctx, FZ_LOCK_FREETYPE); - return NULL; - } - - bitmap = (FT_BitmapGlyph)glyph; - fz_try(ctx) - { - pixmap = fz_copy_ft_bitmap(ctx, bitmap->left, bitmap->top, &bitmap->bitmap); - } - fz_always(ctx) - { - FT_Done_Glyph(glyph); - fz_unlock(ctx, FZ_LOCK_FREETYPE); - } - fz_catch(ctx) - { - fz_rethrow(ctx); - } - - return pixmap; -} - -static fz_rect * -fz_bound_ft_glyph(fz_context *ctx, fz_font *font, int gid, const fz_matrix *trm, fz_rect *bounds) -{ - FT_Face face = font->ft_face; - FT_Error fterr; - FT_BBox cbox; - FT_Matrix m; - FT_Vector v; - - // TODO: refactor loading into fz_load_ft_glyph - // TODO: cache results - - float strength = fz_matrix_expansion(trm) * 0.02f; - fz_matrix local_trm = *trm; - - fz_adjust_ft_glyph_width(ctx, font, gid, &local_trm); - - if (font->ft_italic) - fz_pre_shear(&local_trm, SHEAR, 0); - - m.xx = local_trm.a * 64; /* should be 65536 */ - m.yx = local_trm.b * 64; - m.xy = local_trm.c * 64; - m.yy = local_trm.d * 64; - v.x = local_trm.e * 64; - v.y = local_trm.f * 64; - - fz_lock(ctx, FZ_LOCK_FREETYPE); - fterr = FT_Set_Char_Size(face, 65536, 65536, 72, 72); /* should be 64, 64 */ - if (fterr) - fz_warn(ctx, "freetype setting character size: %s", ft_error_string(fterr)); - FT_Set_Transform(face, &m, &v); - - fterr = FT_Load_Glyph(face, gid, FT_LOAD_NO_BITMAP | FT_LOAD_NO_HINTING); - if (fterr) - { - fz_warn(ctx, "freetype load glyph (gid %d): %s", gid, ft_error_string(fterr)); - fz_unlock(ctx, FZ_LOCK_FREETYPE); - bounds->x0 = bounds->x1 = local_trm.e; - bounds->y0 = bounds->y1 = local_trm.f; - return bounds; - } - - if (font->ft_bold) - { - FT_Outline_Embolden(&face->glyph->outline, strength * 64); - FT_Outline_Translate(&face->glyph->outline, -strength * 32, -strength * 32); - } - - FT_Outline_Get_CBox(&face->glyph->outline, &cbox); - fz_unlock(ctx, FZ_LOCK_FREETYPE); - bounds->x0 = cbox.xMin / 64.0f; - bounds->y0 = cbox.yMin / 64.0f; - bounds->x1 = cbox.xMax / 64.0f; - bounds->y1 = cbox.yMax / 64.0f; - - if (fz_is_empty_rect(bounds)) - { - bounds->x0 = bounds->x1 = local_trm.e; - bounds->y0 = bounds->y1 = local_trm.f; - } - - return bounds; -} - -/* Turn FT_Outline into a fz_path */ - -struct closure { - fz_context *ctx; - fz_path *path; - float x, y; -}; - -static int move_to(const FT_Vector *p, void *cc) -{ - fz_context *ctx = ((struct closure *)cc)->ctx; - fz_path *path = ((struct closure *)cc)->path; - float tx = ((struct closure *)cc)->x; - float ty = ((struct closure *)cc)->y; - fz_moveto(ctx, path, tx + p->x / 64.0f, ty + p->y / 64.0f); - return 0; -} - -static int line_to(const FT_Vector *p, void *cc) -{ - fz_context *ctx = ((struct closure *)cc)->ctx; - fz_path *path = ((struct closure *)cc)->path; - float tx = ((struct closure *)cc)->x; - float ty = ((struct closure *)cc)->y; - fz_lineto(ctx, path, tx + p->x / 64.0f, ty + p->y / 64.0f); - return 0; -} - -static int conic_to(const FT_Vector *c, const FT_Vector *p, void *cc) -{ - fz_context *ctx = ((struct closure *)cc)->ctx; - fz_path *path = ((struct closure *)cc)->path; - float tx = ((struct closure *)cc)->x; - float ty = ((struct closure *)cc)->y; - fz_point s, c1, c2; - float cx = tx + c->x / 64.0f, cy = ty + c->y / 64.0f; - float px = tx + p->x / 64.0f, py = ty + p->y / 64.0f; - s = fz_currentpoint(ctx, path); - c1.x = (s.x + cx * 2) / 3; - c1.y = (s.y + cy * 2) / 3; - c2.x = (px + cx * 2) / 3; - c2.y = (py + cy * 2) / 3; - fz_curveto(ctx, path, c1.x, c1.y, c2.x, c2.y, px, py); - return 0; -} - -static int cubic_to(const FT_Vector *c1, const FT_Vector *c2, const FT_Vector *p, void *cc) -{ - fz_context *ctx = ((struct closure *)cc)->ctx; - fz_path *path = ((struct closure *)cc)->path; - float tx = ((struct closure *)cc)->x; - float ty = ((struct closure *)cc)->y; - fz_curveto(ctx, path, - tx + c1->x/64.0f, ty + c1->y/64.0f, - tx + c2->x/64.0f, ty + c2->y/64.0f, - tx + p->x/64.0f, ty + p->y/64.0f); - return 0; -} - -static const FT_Outline_Funcs outline_funcs = { - move_to, line_to, conic_to, cubic_to, 0, 0 -}; - -fz_path * -fz_outline_ft_glyph(fz_context *ctx, fz_font *font, int gid, const fz_matrix *trm) -{ - struct closure cc; - FT_Face face = font->ft_face; - FT_Matrix m; - FT_Vector v; - int fterr; - fz_matrix local_trm = *trm; - - float strength = fz_matrix_expansion(trm) * 0.02f; - - fz_adjust_ft_glyph_width(ctx, font, gid, &local_trm); - - if (font->ft_italic) - fz_pre_shear(&local_trm, SHEAR, 0); - - m.xx = local_trm.a * 64; /* should be 65536 */ - m.yx = local_trm.b * 64; - m.xy = local_trm.c * 64; - m.yy = local_trm.d * 64; - v.x = 0; - v.y = 0; - - fz_lock(ctx, FZ_LOCK_FREETYPE); - - fterr = FT_Set_Char_Size(face, 65536, 65536, 72, 72); /* should be 64, 64 */ - if (fterr) - fz_warn(ctx, "freetype setting character size: %s", ft_error_string(fterr)); - FT_Set_Transform(face, &m, &v); - - fterr = FT_Load_Glyph(face, gid, FT_LOAD_NO_BITMAP | FT_LOAD_NO_HINTING); - if (fterr) - { - fz_warn(ctx, "freetype load glyph (gid %d): %s", gid, ft_error_string(fterr)); - fz_unlock(ctx, FZ_LOCK_FREETYPE); - return NULL; - } - - if (font->ft_bold) - { - FT_Outline_Embolden(&face->glyph->outline, strength * 64); - FT_Outline_Translate(&face->glyph->outline, -strength * 32, -strength * 32); - } - - fz_try(ctx) - { - cc.ctx = ctx; - cc.path = fz_new_path(ctx); - cc.x = local_trm.e; - cc.y = local_trm.f; - fz_moveto(ctx, cc.path, cc.x, cc.y); - FT_Outline_Decompose(&face->glyph->outline, &outline_funcs, &cc); - fz_closepath(ctx, cc.path); - } - fz_always(ctx) - { - fz_unlock(ctx, FZ_LOCK_FREETYPE); - } - fz_catch(ctx) - { - fz_warn(ctx, "freetype cannot decompose outline"); - fz_free(ctx, cc.path); - return NULL; - } - - return cc.path; -} - -/* - * Type 3 fonts... - */ - -fz_font * -fz_new_type3_font(fz_context *ctx, char *name, const fz_matrix *matrix) -{ - fz_font *font; - int i; - - font = fz_new_font(ctx, name, 1, 256); - font->t3procs = fz_malloc_array(ctx, 256, sizeof(fz_buffer*)); - font->t3lists = fz_malloc_array(ctx, 256, sizeof(fz_display_list*)); - font->t3widths = fz_malloc_array(ctx, 256, sizeof(float)); - font->t3flags = fz_malloc_array(ctx, 256, sizeof(char)); - - font->t3matrix = *matrix; - for (i = 0; i < 256; i++) - { - font->t3procs[i] = NULL; - font->t3lists[i] = NULL; - font->t3widths[i] = 0; - font->t3flags[i] = 0; - } - - return font; -} - -void -fz_prepare_t3_glyph(fz_context *ctx, fz_font *font, int gid, int nested_depth) -{ - fz_buffer *contents; - fz_device *dev; - - contents = font->t3procs[gid]; - if (!contents) - return; - - /* We've not already loaded this one! */ - assert(font->t3lists[gid] == NULL); - - font->t3lists[gid] = fz_new_display_list(ctx); - - dev = fz_new_list_device(ctx, font->t3lists[gid]); - dev->flags = FZ_DEVFLAG_FILLCOLOR_UNDEFINED | - FZ_DEVFLAG_STROKECOLOR_UNDEFINED | - FZ_DEVFLAG_STARTCAP_UNDEFINED | - FZ_DEVFLAG_DASHCAP_UNDEFINED | - FZ_DEVFLAG_ENDCAP_UNDEFINED | - FZ_DEVFLAG_LINEJOIN_UNDEFINED | - FZ_DEVFLAG_MITERLIMIT_UNDEFINED | - FZ_DEVFLAG_LINEWIDTH_UNDEFINED; - font->t3run(font->t3doc, font->t3resources, contents, dev, &fz_identity, NULL, 0); - font->t3flags[gid] = dev->flags; - fz_free_device(dev); -} - -static fz_rect * -fz_bound_t3_glyph(fz_context *ctx, fz_font *font, int gid, const fz_matrix *trm, fz_rect *bounds) -{ - fz_display_list *list; - fz_matrix ctm; - fz_device *dev; - - list = font->t3lists[gid]; - if (!list) - { - *bounds = fz_empty_rect; - return fz_transform_rect(bounds, trm); - } - - fz_concat(&ctm, &font->t3matrix, trm); - dev = fz_new_bbox_device(ctx, bounds); - fz_try(ctx) - { - fz_run_display_list(list, dev, &ctm, &fz_infinite_rect, NULL); - } - fz_always(ctx) - { - fz_free_device(dev); - } - fz_catch(ctx) - { - fz_rethrow(ctx); - } - - return bounds; -} - -fz_pixmap * -fz_render_t3_glyph(fz_context *ctx, fz_font *font, int gid, const fz_matrix *trm, fz_colorspace *model, fz_irect scissor) -{ - fz_display_list *list; - fz_matrix ctm; - fz_rect bounds; - fz_irect bbox; - fz_device *dev; - fz_pixmap *glyph; - fz_pixmap *result; - - if (gid < 0 || gid > 255) - return NULL; - - list = font->t3lists[gid]; - if (!list) - return NULL; - - if (font->t3flags[gid] & FZ_DEVFLAG_MASK) - { - if (font->t3flags[gid] & FZ_DEVFLAG_COLOR) - fz_warn(ctx, "type3 glyph claims to be both masked and colored"); - model = NULL; - } - else if (font->t3flags[gid] & FZ_DEVFLAG_COLOR) - { - if (!model) - fz_warn(ctx, "colored type3 glyph wanted in masked context"); - } - else - { - fz_warn(ctx, "type3 glyph doesn't specify masked or colored"); - model = NULL; /* Treat as masked */ - } - - fz_expand_rect(fz_bound_glyph(ctx, font, gid, trm, &bounds), 1); - fz_irect_from_rect(&bbox, &bounds); - fz_intersect_irect(&bbox, &scissor); - - glyph = fz_new_pixmap_with_bbox(ctx, model ? model : fz_device_gray(ctx), &bbox); - fz_clear_pixmap(ctx, glyph); - - fz_concat(&ctm, &font->t3matrix, trm); - dev = fz_new_draw_device_type3(ctx, glyph); - fz_run_display_list(list, dev, &ctm, &fz_infinite_rect, NULL); - fz_free_device(dev); - - if (!model) - { - result = fz_alpha_from_gray(ctx, glyph, 0); - fz_drop_pixmap(ctx, glyph); - } - else - result = glyph; - - return result; -} - -void -fz_render_t3_glyph_direct(fz_context *ctx, fz_device *dev, fz_font *font, int gid, const fz_matrix *trm, void *gstate, int nested_depth) -{ - fz_matrix ctm; - void *contents; - - if (gid < 0 || gid > 255) - return; - - contents = font->t3procs[gid]; - if (!contents) - return; - - if (font->t3flags[gid] & FZ_DEVFLAG_MASK) - { - if (font->t3flags[gid] & FZ_DEVFLAG_COLOR) - fz_warn(ctx, "type3 glyph claims to be both masked and colored"); - } - else if (font->t3flags[gid] & FZ_DEVFLAG_COLOR) - { - } - else - { - fz_warn(ctx, "type3 glyph doesn't specify masked or colored"); - } - - fz_concat(&ctm, &font->t3matrix, trm); - font->t3run(font->t3doc, font->t3resources, contents, dev, &ctm, gstate, nested_depth); -} - -#ifndef NDEBUG -void -fz_print_font(fz_context *ctx, FILE *out, fz_font *font) -{ - fprintf(out, "font '%s' {\n", font->name); - - if (font->ft_face) - { - fprintf(out, "\tfreetype face %p\n", font->ft_face); - if (font->ft_substitute) - fprintf(out, "\tsubstitute font\n"); - } - - if (font->t3procs) - { - fprintf(out, "\ttype3 matrix [%g %g %g %g]\n", - font->t3matrix.a, font->t3matrix.b, - font->t3matrix.c, font->t3matrix.d); - - fprintf(out, "\ttype3 bbox [%g %g %g %g]\n", - font->bbox.x0, font->bbox.y0, - font->bbox.x1, font->bbox.y1); - } - - fprintf(out, "}\n"); -} -#endif - -fz_rect * -fz_bound_glyph(fz_context *ctx, fz_font *font, int gid, const fz_matrix *trm, fz_rect *rect) -{ - if (font->bbox_table && gid < font->bbox_count) - { - if (fz_is_infinite_rect(&font->bbox_table[gid])) - { - if (font->ft_face) - fz_bound_ft_glyph(ctx, font, gid, &fz_identity, &font->bbox_table[gid]); - else if (font->t3lists) - fz_bound_t3_glyph(ctx, font, gid, &fz_identity, &font->bbox_table[gid]); - else - font->bbox_table[gid] = fz_empty_rect; - } - *rect = font->bbox_table[gid]; - } - else - { - /* fall back to font bbox */ - *rect = font->bbox; - } - - return fz_transform_rect(rect, trm); -} - -fz_path * -fz_outline_glyph(fz_context *ctx, fz_font *font, int gid, const fz_matrix *ctm) -{ - if (!font->ft_face) - return NULL; - return fz_outline_ft_glyph(ctx, font, gid, ctm); -} - -int fz_glyph_cacheable(fz_context *ctx, fz_font *font, int gid) -{ - if (!font->t3procs || !font->t3flags || gid < 0 || gid >= font->bbox_count) - return 1; - return (font->t3flags[gid] & FZ_DEVFLAG_UNCACHEABLE) == 0; -} diff --git a/fitz/res_func.c b/fitz/res_func.c deleted file mode 100644 index b5ba4815..00000000 --- a/fitz/res_func.c +++ /dev/null @@ -1,48 +0,0 @@ -#include "mupdf/fitz.h" - -void -fz_eval_function(fz_context *ctx, fz_function *func, float *in_, int inlen, float *out_, int outlen) -{ - float fakein[FZ_FN_MAXM]; - float fakeout[FZ_FN_MAXN]; - float *in = in_; - float *out = out_; - - if (inlen < func->m) - { - in = fakein; - memset(in, 0, sizeof(float) * func->m); - memcpy(in, in_, sizeof(float) * inlen); - } - - if (outlen < func->n) - { - out = fakeout; - memset(out, 0, sizeof(float) * func->n); - } - else - memset(out, 0, sizeof(float) * outlen); - - func->evaluate(ctx, func, in, out); - - if (outlen < func->n) - memcpy(out_, out, sizeof(float) * outlen); -} - -fz_function * -fz_keep_function(fz_context *ctx, fz_function *func) -{ - return (fz_function *)fz_keep_storable(ctx, &func->storable); -} - -void -fz_drop_function(fz_context *ctx, fz_function *func) -{ - fz_drop_storable(ctx, &func->storable); -} - -unsigned int -fz_function_size(fz_function *func) -{ - return (func ? func->size : 0); -} diff --git a/fitz/res_halftone.c b/fitz/res_halftone.c deleted file mode 100644 index 15aebead..00000000 --- a/fitz/res_halftone.c +++ /dev/null @@ -1,202 +0,0 @@ -#include "mupdf/fitz.h" - -fz_halftone * -fz_new_halftone(fz_context *ctx, int comps) -{ - fz_halftone *ht; - int i; - - ht = fz_malloc(ctx, sizeof(fz_halftone) + (comps-1)*sizeof(fz_pixmap *)); - ht->refs = 1; - ht->n = comps; - for (i = 0; i < comps; i++) - ht->comp[i] = NULL; - - return ht; -} - -fz_halftone * -fz_keep_halftone(fz_context *ctx, fz_halftone *ht) -{ - if (ht) - ht->refs++; - return ht; -} - -void -fz_drop_halftone(fz_context *ctx, fz_halftone *ht) -{ - int i; - - if (!ht || --ht->refs != 0) - return; - for (i = 0; i < ht->n; i++) - fz_drop_pixmap(ctx, ht->comp[i]); - fz_free(ctx, ht); -} - -/* Default mono halftone, lifted from Ghostscript. */ -/* The 0x00 entry has been changed to 0x01 to avoid problems with white - * pixels appearing in the output; as we use < 0 should not appear in the - * array. I think that gs scales this slighly and hence never actually uses - * the raw values here. */ -static unsigned char mono_ht[] = -{ - 0x0E, 0x8E, 0x2E, 0xAE, 0x06, 0x86, 0x26, 0xA6, 0x0C, 0x8C, 0x2C, 0xAC, 0x04, 0x84, 0x24, 0xA4, - 0xCE, 0x4E, 0xEE, 0x6E, 0xC6, 0x46, 0xE6, 0x66, 0xCC, 0x4C, 0xEC, 0x6C, 0xC4, 0x44, 0xE4, 0x64, - 0x3E, 0xBE, 0x1E, 0x9E, 0x36, 0xB6, 0x16, 0x96, 0x3C, 0xBC, 0x1C, 0x9C, 0x34, 0xB4, 0x14, 0x94, - 0xFE, 0x7E, 0xDE, 0x5E, 0xF6, 0x76, 0xD6, 0x56, 0xFC, 0x7C, 0xDC, 0x5C, 0xF4, 0x74, 0xD4, 0x54, - 0x01, 0x81, 0x21, 0xA1, 0x09, 0x89, 0x29, 0xA9, 0x03, 0x83, 0x23, 0xA3, 0x0B, 0x8B, 0x2B, 0xAB, - 0xC1, 0x41, 0xE1, 0x61, 0xC9, 0x49, 0xE9, 0x69, 0xC3, 0x43, 0xE3, 0x63, 0xCB, 0x4B, 0xEB, 0x6B, - 0x31, 0xB1, 0x11, 0x91, 0x39, 0xB9, 0x19, 0x99, 0x33, 0xB3, 0x13, 0x93, 0x3B, 0xBB, 0x1B, 0x9B, - 0xF1, 0x71, 0xD1, 0x51, 0xF9, 0x79, 0xD9, 0x59, 0xF3, 0x73, 0xD3, 0x53, 0xFB, 0x7B, 0xDB, 0x5B, - 0x0D, 0x8D, 0x2D, 0xAD, 0x05, 0x85, 0x25, 0xA5, 0x0F, 0x8F, 0x2F, 0xAF, 0x07, 0x87, 0x27, 0xA7, - 0xCD, 0x4D, 0xED, 0x6D, 0xC5, 0x45, 0xE5, 0x65, 0xCF, 0x4F, 0xEF, 0x6F, 0xC7, 0x47, 0xE7, 0x67, - 0x3D, 0xBD, 0x1D, 0x9D, 0x35, 0xB5, 0x15, 0x95, 0x3F, 0xBF, 0x1F, 0x9F, 0x37, 0xB7, 0x17, 0x97, - 0xFD, 0x7D, 0xDD, 0x5D, 0xF5, 0x75, 0xD5, 0x55, 0xFF, 0x7F, 0xDF, 0x5F, 0xF7, 0x77, 0xD7, 0x57, - 0x02, 0x82, 0x22, 0xA2, 0x0A, 0x8A, 0x2A, 0xAA, 0x01 /*0x00*/, 0x80, 0x20, 0xA0, 0x08, 0x88, 0x28, 0xA8, - 0xC2, 0x42, 0xE2, 0x62, 0xCA, 0x4A, 0xEA, 0x6A, 0xC0, 0x40, 0xE0, 0x60, 0xC8, 0x48, 0xE8, 0x68, - 0x32, 0xB2, 0x12, 0x92, 0x3A, 0xBA, 0x1A, 0x9A, 0x30, 0xB0, 0x10, 0x90, 0x38, 0xB8, 0x18, 0x98, - 0xF2, 0x72, 0xD2, 0x52, 0xFA, 0x7A, 0xDA, 0x5A, 0xF0, 0x70, 0xD0, 0x50, 0xF8, 0x78, 0xD8, 0x58 -}; - -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 */ - ht->comp[0] = fz_new_pixmap_with_data(ctx, NULL, 16, 16, mono_ht); - return ht; -} - -/* Finally, code to actually perform halftoning. */ -static void make_ht_line(unsigned char *buf, fz_halftone *ht, int x, int y, int w) -{ - /* FIXME: There is a potential optimisation here; in the case where - * the LCM of the halftone tile widths is smaller than w, we could - * form just one 'LCM' run, then copy it repeatedly. - */ - int k, n; - n = ht->n; - for (k = 0; k < n; k++) - { - fz_pixmap *tile = ht->comp[k]; - unsigned char *b = buf++; - unsigned char *t; - unsigned char *tbase; - int px = x + tile->x; - int py = y + tile->y; - int tw = tile->w; - int th = tile->h; - int w2 = w; - int len; - px = px % tw; - if (px < 0) - px += tw; - py = py % th; - if (py < 0) - py += th; - - assert(tile->n == 1); - - /* Left hand section; from x to tile width */ - tbase = tile->samples + (unsigned int)(py * tw); - t = tbase + px; - len = tw - px; - if (len > w2) - len = w2; - w2 -= len; - while (len--) - { - *b = *t++; - b += n; - } - - /* Centre section - complete copies */ - w2 -= tw; - while (w2 >= 0) - { - len = tw; - t = tbase; - while (len--) - { - *b = *t++; - b += n; - } - w2 -= tw; - } - w2 += tw; - - /* Right hand section - stragglers */ - t = tbase; - while (w2--) - { - *b = *t++; - b += n; - } - } -} - -/* Inner mono thresholding code */ -static void do_threshold_1(unsigned char *ht_line, unsigned char *pixmap, unsigned char *out, int w) -{ - int bit = 0x80; - int h = 0; - - do - { - if (*pixmap < *ht_line++) - h |= bit; - pixmap += 2; /* Skip the alpha */ - bit >>= 1; - if (bit == 0) - { - *out++ = h; - h = 0; - bit = 0x80; - } - - } - while (--w); - if (bit != 0x80) - *out++ = h; -} - -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) - 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, pix->xres, pix->yres); - o = out->samples; - p = pix->samples; - - h = pix->h; - x = pix->x; - y = pix->y; - w = pix->w; - ostride = out->stride; - pstride = pix->w * pix->n; - while (h--) - { - make_ht_line(ht_line, ht, x, y++, w); - do_threshold_1(ht_line, p, o, w); - o += ostride; - p += pstride; - } - if (!ht_orig) - fz_drop_halftone(ctx, ht); - return out; -} diff --git a/fitz/res_image.c b/fitz/res_image.c deleted file mode 100644 index 73b4bc28..00000000 --- a/fitz/res_image.c +++ /dev/null @@ -1,493 +0,0 @@ -#include "mupdf/fitz.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); -} - -typedef struct fz_image_key_s fz_image_key; - -struct fz_image_key_s { - int refs; - fz_image *image; - int l2factor; -}; - -static int -fz_make_hash_image_key(fz_store_hash *hash, void *key_) -{ - fz_image_key *key = (fz_image_key *)key_; - - hash->u.pi.ptr = key->image; - hash->u.pi.i = key->l2factor; - return 1; -} - -static void * -fz_keep_image_key(fz_context *ctx, void *key_) -{ - fz_image_key *key = (fz_image_key *)key_; - - fz_lock(ctx, FZ_LOCK_ALLOC); - key->refs++; - fz_unlock(ctx, FZ_LOCK_ALLOC); - - return (void *)key; -} - -static void -fz_drop_image_key(fz_context *ctx, void *key_) -{ - fz_image_key *key = (fz_image_key *)key_; - int drop; - - if (key == NULL) - return; - fz_lock(ctx, FZ_LOCK_ALLOC); - drop = --key->refs; - fz_unlock(ctx, FZ_LOCK_ALLOC); - if (drop == 0) - { - fz_drop_image(ctx, key->image); - fz_free(ctx, key); - } -} - -static int -fz_cmp_image_key(void *k0_, void *k1_) -{ - fz_image_key *k0 = (fz_image_key *)k0_; - fz_image_key *k1 = (fz_image_key *)k1_; - - return k0->image == k1->image && k0->l2factor == k1->l2factor; -} - -#ifndef NDEBUG -static void -fz_debug_image(FILE *out, void *key_) -{ - fz_image_key *key = (fz_image_key *)key_; - - fprintf(out, "(image %d x %d sf=%d) ", key->image->w, key->image->h, key->l2factor); -} -#endif - -static fz_store_type fz_image_store_type = -{ - fz_make_hash_image_key, - fz_keep_image_key, - fz_drop_image_key, - fz_cmp_image_key, -#ifndef NDEBUG - fz_debug_image -#endif -}; - -static void -fz_mask_color_key(fz_pixmap *pix, int n, int *colorkey) -{ - unsigned char *p = pix->samples; - int len = pix->w * pix->h; - int k, t; - while (len--) - { - t = 1; - for (k = 0; k < n; k++) - if (p[k] < colorkey[k * 2] || p[k] > colorkey[k * 2 + 1]) - t = 0; - if (t) - for (k = 0; k < pix->n; k++) - p[k] = 0; - p += pix->n; - } -} - -fz_pixmap * -fz_decomp_image_from_stream(fz_context *ctx, fz_stream *stm, fz_image *image, int in_line, int indexed, int l2factor, int native_l2factor) -{ - fz_pixmap *tile = NULL; - int stride, len, i; - unsigned char *samples = NULL; - int f = 1<w + f-1) >> native_l2factor; - int h = (image->h + f-1) >> native_l2factor; - - fz_var(tile); - fz_var(samples); - - fz_try(ctx) - { - tile = fz_new_pixmap(ctx, image->colorspace, w, h); - tile->interpolate = image->interpolate; - - stride = (w * image->n * image->bpc + 7) / 8; - - samples = fz_malloc_array(ctx, h, stride); - - len = fz_read(stm, samples, h * stride); - if (len < 0) - { - fz_throw(ctx, FZ_ERROR_GENERIC, "cannot read image data"); - } - - /* Make sure we read the EOF marker (for inline images only) */ - if (in_line) - { - unsigned char tbuf[512]; - fz_try(ctx) - { - int tlen = fz_read(stm, tbuf, sizeof tbuf); - if (tlen > 0) - fz_warn(ctx, "ignoring garbage at end of image"); - } - fz_catch(ctx) - { - /* FIXME: TryLater? */ - fz_warn(ctx, "ignoring error at end of image"); - } - } - - /* Pad truncated images */ - if (len < stride * h) - { - fz_warn(ctx, "padding truncated image"); - memset(samples + len, 0, stride * h - len); - } - - /* Invert 1-bit image masks */ - if (image->imagemask) - { - /* 0=opaque and 1=transparent so we need to invert */ - unsigned char *p = samples; - len = h * stride; - for (i = 0; i < len; i++) - p[i] = ~p[i]; - } - - fz_unpack_tile(tile, samples, image->n, image->bpc, stride, indexed); - - fz_free(ctx, samples); - samples = NULL; - - if (image->usecolorkey) - fz_mask_color_key(tile, image->n, image->colorkey); - - if (indexed) - { - fz_pixmap *conv; - fz_decode_indexed_tile(tile, image->decode, (1 << image->bpc) - 1); - conv = fz_expand_indexed_pixmap(ctx, tile); - fz_drop_pixmap(ctx, tile); - tile = conv; - } - else - { - fz_decode_tile(tile, image->decode); - } - } - fz_always(ctx) - { - fz_close(stm); - } - fz_catch(ctx) - { - if (tile) - fz_drop_pixmap(ctx, tile); - fz_free(ctx, samples); - - fz_rethrow(ctx); - } - - /* Now apply any extra subsampling required */ - if (l2factor - native_l2factor > 0) - { - if (l2factor - native_l2factor > 8) - l2factor = native_l2factor + 8; - fz_subsample_pixmap(ctx, tile, l2factor - native_l2factor); - } - - return tile; -} - -void -fz_free_image(fz_context *ctx, fz_storable *image_) -{ - fz_image *image = (fz_image *)image_; - - if (image == NULL) - return; - fz_drop_pixmap(ctx, image->tile); - fz_free_compressed_buffer(ctx, image->buffer); - fz_drop_colorspace(ctx, image->colorspace); - fz_drop_image(ctx, image->mask); - fz_free(ctx, image); -} - -fz_pixmap * -fz_image_get_pixmap(fz_context *ctx, fz_image *image, int w, int h) -{ - fz_pixmap *tile; - fz_stream *stm; - int l2factor; - fz_image_key key; - int native_l2factor; - int indexed; - fz_image_key *keyp; - - /* Check for 'simple' images which are just pixmaps */ - if (image->buffer == NULL) - { - tile = image->tile; - if (!tile) - return NULL; - return fz_keep_pixmap(ctx, tile); /* That's all we can give you! */ - } - - /* Ensure our expectations for tile size are reasonable */ - if (w > image->w) - w = image->w; - if (h > image->h) - h = image->h; - - /* What is our ideal factor? */ - if (w == 0 || h == 0) - l2factor = 0; - else - for (l2factor=0; image->w>>(l2factor+1) >= w && image->h>>(l2factor+1) >= h && l2factor < 8; l2factor++); - - /* Can we find any suitable tiles in the cache? */ - key.refs = 1; - key.image = image; - key.l2factor = l2factor; - do - { - tile = fz_find_item(ctx, fz_free_pixmap_imp, &key, &fz_image_store_type); - if (tile) - return tile; - key.l2factor--; - } - while (key.l2factor >= 0); - - /* We need to make a new one. */ - /* First check for ones that we can't decode using streams */ - switch (image->buffer->params.type) - { - case FZ_IMAGE_PNG: - tile = fz_load_png(ctx, image->buffer->buffer->data, image->buffer->buffer->len); - break; - case FZ_IMAGE_TIFF: - tile = fz_load_tiff(ctx, image->buffer->buffer->data, image->buffer->buffer->len); - break; - default: - native_l2factor = l2factor; - stm = fz_open_image_decomp_stream(ctx, image->buffer, &native_l2factor); - - indexed = fz_colorspace_is_indexed(image->colorspace); - tile = fz_decomp_image_from_stream(ctx, stm, image, 0, indexed, l2factor, native_l2factor); - break; - } - - /* Now we try to cache the pixmap. Any failure here will just result - * in us not caching. */ - fz_var(keyp); - fz_try(ctx) - { - fz_pixmap *existing_tile; - - keyp = fz_malloc_struct(ctx, fz_image_key); - keyp->refs = 1; - keyp->image = fz_keep_image(ctx, image); - keyp->l2factor = l2factor; - existing_tile = fz_store_item(ctx, keyp, tile, fz_pixmap_size(ctx, tile), &fz_image_store_type); - if (existing_tile) - { - /* We already have a tile. This must have been produced by a - * racing thread. We'll throw away ours and use that one. */ - fz_drop_pixmap(ctx, tile); - tile = existing_tile; - } - } - fz_always(ctx) - { - fz_drop_image_key(ctx, keyp); - } - fz_catch(ctx) - { - /* Do nothing */ - } - - return tile; -} - -fz_image * -fz_new_image_from_pixmap(fz_context *ctx, fz_pixmap *pixmap, fz_image *mask) -{ - fz_image *image; - - assert(mask == NULL || mask->mask == NULL); - - fz_try(ctx) - { - image = fz_malloc_struct(ctx, fz_image); - FZ_INIT_STORABLE(image, 1, fz_free_image); - image->w = pixmap->w; - image->h = pixmap->h; - image->n = pixmap->n; - image->colorspace = pixmap->colorspace; - image->bpc = 8; - image->buffer = NULL; - image->get_pixmap = fz_image_get_pixmap; - image->xres = pixmap->xres; - image->yres = pixmap->yres; - image->tile = pixmap; - image->mask = mask; - } - fz_catch(ctx) - { - fz_drop_image(ctx, mask); - fz_rethrow(ctx); - } - return image; -} - -fz_image * -fz_new_image(fz_context *ctx, int w, int h, int bpc, fz_colorspace *colorspace, - int xres, int yres, int interpolate, int imagemask, float *decode, - int *colorkey, fz_compressed_buffer *buffer, fz_image *mask) -{ - fz_image *image; - - assert(mask == NULL || mask->mask == NULL); - - fz_try(ctx) - { - image = fz_malloc_struct(ctx, fz_image); - FZ_INIT_STORABLE(image, 1, fz_free_image); - image->get_pixmap = fz_image_get_pixmap; - image->w = w; - image->h = h; - image->xres = xres; - image->yres = yres; - image->bpc = bpc; - image->n = (colorspace ? colorspace->n : 1); - image->colorspace = colorspace; - image->interpolate = interpolate; - image->imagemask = imagemask; - image->usecolorkey = (colorkey != NULL); - if (colorkey) - memcpy(image->colorkey, colorkey, sizeof(int)*image->n*2); - if (decode) - memcpy(image->decode, decode, sizeof(float)*image->n*2); - else - { - float maxval = fz_colorspace_is_indexed(colorspace) ? (1 << bpc) - 1 : 1; - int i; - for (i = 0; i < image->n; i++) - { - image->decode[2*i] = 0; - image->decode[2*i+1] = maxval; - } - } - image->mask = mask; - image->buffer = buffer; - } - fz_catch(ctx) - { - fz_free_compressed_buffer(ctx, buffer); - fz_rethrow(ctx); - } - - return image; -} - -fz_image * -fz_new_image_from_data(fz_context *ctx, unsigned char *data, int len) -{ - fz_buffer *buffer = NULL; - fz_image *image; - - fz_var(buffer); - fz_var(data); - - fz_try(ctx) - { - buffer = fz_new_buffer_from_data(ctx, data, len); - data = NULL; - image = fz_new_image_from_buffer(ctx, buffer); - } - fz_always(ctx) - { - fz_drop_buffer(ctx, buffer); - } - fz_catch(ctx) - { - fz_free(ctx, data); - fz_rethrow(ctx); - } - - return image; -} - -fz_image * -fz_new_image_from_buffer(fz_context *ctx, fz_buffer *buffer) -{ - fz_compressed_buffer *bc = NULL; - int w, h, xres, yres; - fz_colorspace *cspace; - int len = buffer->len; - unsigned char *buf = buffer->data; - - fz_var(bc); - - fz_try(ctx) - { - if (len < 8) - fz_throw(ctx, FZ_ERROR_GENERIC, "unknown image file format"); - - bc = fz_malloc_struct(ctx, fz_compressed_buffer); - bc->buffer = fz_keep_buffer(ctx, buffer); - - if (buf[0] == 0xff && buf[1] == 0xd8) - { - bc->params.type = FZ_IMAGE_JPEG; - bc->params.u.jpeg.color_transform = -1; - fz_load_jpeg_info(ctx, buf, len, &w, &h, &xres, &yres, &cspace); - } - else if (memcmp(buf, "\211PNG\r\n\032\n", 8) == 0) - { - bc->params.type = FZ_IMAGE_PNG; - fz_load_png_info(ctx, buf, len, &w, &h, &xres, &yres, &cspace); - } - else if (memcmp(buf, "II", 2) == 0 && buf[2] == 0xBC) - fz_throw(ctx, FZ_ERROR_GENERIC, "JPEG-XR codec is not available"); - else if (memcmp(buf, "MM", 2) == 0 || memcmp(buf, "II", 2) == 0) - { - bc->params.type = FZ_IMAGE_TIFF; - fz_load_tiff_info(ctx, buf, len, &w, &h, &xres, &yres, &cspace); - } - else - fz_throw(ctx, FZ_ERROR_GENERIC, "unknown image file format"); - } - fz_catch(ctx) - { - fz_free_compressed_buffer(ctx, bc); - fz_rethrow(ctx); - } - - return fz_new_image(ctx, w, h, 8, cspace, xres, yres, 0, 0, NULL, NULL, bc, NULL); -} diff --git a/fitz/res_path.c b/fitz/res_path.c deleted file mode 100644 index cbdfc7bc..00000000 --- a/fitz/res_path.c +++ /dev/null @@ -1,507 +0,0 @@ -#include -#include "mupdf/fitz.h" - -fz_path * -fz_new_path(fz_context *ctx) -{ - fz_path *path; - - path = fz_malloc_struct(ctx, fz_path); - path->len = 0; - path->cap = 0; - path->items = NULL; - path->last = -1; - - return path; -} - -fz_path * -fz_clone_path(fz_context *ctx, fz_path *old) -{ - fz_path *path; - - assert(old); - path = fz_malloc_struct(ctx, fz_path); - fz_try(ctx) - { - path->len = old->len; - path->cap = old->len; - path->items = fz_malloc_array(ctx, path->cap, sizeof(fz_path_item)); - memcpy(path->items, old->items, sizeof(fz_path_item) * path->len); - } - fz_catch(ctx) - { - fz_free(ctx, path); - fz_rethrow(ctx); - } - - return path; -} - -void -fz_free_path(fz_context *ctx, fz_path *path) -{ - if (path == NULL) - return; - fz_free(ctx, path->items); - fz_free(ctx, path); -} - -static void -grow_path(fz_context *ctx, fz_path *path, int n) -{ - int newcap = path->cap; - if (path->len + n <= path->cap) - { - path->last = path->len; - return; - } - while (path->len + n > newcap) - newcap = newcap + 36; - path->items = fz_resize_array(ctx, path->items, newcap, sizeof(fz_path_item)); - path->cap = newcap; - path->last = path->len; -} - -fz_point -fz_currentpoint(fz_context *ctx, fz_path *path) -{ - fz_point c, m; - int i; - - c.x = c.y = m.x = m.y = 0; - i = 0; - - while (i < path->len) - { - switch (path->items[i++].k) - { - case FZ_MOVETO: - m.x = c.x = path->items[i++].v; - m.y = c.y = path->items[i++].v; - break; - case FZ_LINETO: - c.x = path->items[i++].v; - c.y = path->items[i++].v; - break; - case FZ_CURVETO: - i += 4; - c.x = path->items[i++].v; - c.y = path->items[i++].v; - break; - case FZ_CLOSE_PATH: - c = m; - } - } - - return c; -} - -void -fz_moveto(fz_context *ctx, fz_path *path, float x, float y) -{ - if (path->last >= 0 && path->items[path->last].k == FZ_MOVETO) - { - /* No point in having MOVETO then MOVETO */ - path->len = path->last; - } - grow_path(ctx, path, 3); - path->items[path->len++].k = FZ_MOVETO; - path->items[path->len++].v = x; - path->items[path->len++].v = y; -} - -void -fz_lineto(fz_context *ctx, fz_path *path, float x, float y) -{ - float x0, y0; - - if (path->last < 0) - { - fz_warn(ctx, "lineto with no current point"); - return; - } - if (path->items[path->last].k == FZ_CLOSE_PATH) - { - x0 = path->items[path->last-2].v; - y0 = path->items[path->last-1].v; - } - else - { - x0 = path->items[path->len-2].v; - y0 = path->items[path->len-1].v; - } - /* Anything other than MoveTo followed by LineTo the same place is a nop */ - if (path->items[path->last].k != FZ_MOVETO && x0 == x && y0 == y) - return; - grow_path(ctx, path, 3); - path->items[path->len++].k = FZ_LINETO; - path->items[path->len++].v = x; - path->items[path->len++].v = y; -} - -void -fz_curveto(fz_context *ctx, fz_path *path, - float x1, float y1, - float x2, float y2, - float x3, float y3) -{ - float x0, y0; - - if (path->last < 0) - { - fz_warn(ctx, "curveto with no current point"); - return; - } - if (path->items[path->last].k == FZ_CLOSE_PATH) - { - x0 = path->items[path->last-2].v; - y0 = path->items[path->last-1].v; - } - else - { - x0 = path->items[path->len-2].v; - y0 = path->items[path->len-1].v; - } - - /* Check for degenerate cases: */ - if (x0 == x1 && y0 == y1) - { - if (x2 == x3 && y2 == y3) - { - /* If (x1,y1)==(x2,y2) and prev wasn't a moveto, then skip */ - if (x1 == x2 && y1 == y2 && path->items[path->last].k != FZ_MOVETO) - return; - /* Otherwise a line will suffice */ - fz_lineto(ctx, path, x3, y3); - return; - } - if (x1 == x2 && y1 == y2) - { - /* A line will suffice */ - fz_lineto(ctx, path, x3, y3); - return; - } - } - else if (x1 == x2 && y1 == y2 && x2 == x3 && y2 == y3) - { - /* A line will suffice */ - fz_lineto(ctx, path, x3, y3); - return; - } - - grow_path(ctx, path, 7); - path->items[path->len++].k = FZ_CURVETO; - path->items[path->len++].v = x1; - path->items[path->len++].v = y1; - path->items[path->len++].v = x2; - path->items[path->len++].v = y2; - path->items[path->len++].v = x3; - path->items[path->len++].v = y3; -} - -void -fz_curvetov(fz_context *ctx, fz_path *path, float x2, float y2, float x3, float y3) -{ - float x1, y1; - if (path->last < 0) - { - fz_warn(ctx, "curvetov with no current point"); - return; - } - if (path->items[path->last].k == FZ_CLOSE_PATH) - { - x1 = path->items[path->last-2].v; - y1 = path->items[path->last-1].v; - } - else - { - x1 = path->items[path->len-2].v; - y1 = path->items[path->len-1].v; - } - fz_curveto(ctx, path, x1, y1, x2, y2, x3, y3); -} - -void -fz_curvetoy(fz_context *ctx, fz_path *path, float x1, float y1, float x3, float y3) -{ - fz_curveto(ctx, path, x1, y1, x3, y3, x3, y3); -} - -void -fz_closepath(fz_context *ctx, fz_path *path) -{ - if (path->last < 0) - { - fz_warn(ctx, "closepath with no current point"); - return; - } - /* CLOSE following a CLOSE is a NOP */ - if (path->items[path->last].k == FZ_CLOSE_PATH) - return; - grow_path(ctx, path, 1); - path->items[path->len++].k = FZ_CLOSE_PATH; -} - -static inline fz_rect *bound_expand(fz_rect *r, const fz_point *p) -{ - if (p->x < r->x0) r->x0 = p->x; - if (p->y < r->y0) r->y0 = p->y; - if (p->x > r->x1) r->x1 = p->x; - if (p->y > r->y1) r->y1 = p->y; - return r; -} - -fz_rect * -fz_bound_path(fz_context *ctx, fz_path *path, const fz_stroke_state *stroke, const fz_matrix *ctm, fz_rect *r) -{ - fz_point p; - int i = 0; - - /* If the path is empty, return the empty rectangle here - don't wait - * for it to be expanded in the stroked case below. */ - if (path->len == 0) - { - *r = fz_empty_rect; - return r; - } - /* A path must start with a moveto - and if that's all there is - * then the path is empty. */ - if (path->len == 3) - { - *r = fz_empty_rect; - return r; - } - - p.x = path->items[1].v; - p.y = path->items[2].v; - fz_transform_point(&p, ctm); - r->x0 = r->x1 = p.x; - r->y0 = r->y1 = p.y; - - while (i < path->len) - { - switch (path->items[i++].k) - { - case FZ_CURVETO: - p.x = path->items[i++].v; - p.y = path->items[i++].v; - bound_expand(r, fz_transform_point(&p, ctm)); - p.x = path->items[i++].v; - p.y = path->items[i++].v; - bound_expand(r, fz_transform_point(&p, ctm)); - p.x = path->items[i++].v; - p.y = path->items[i++].v; - bound_expand(r, fz_transform_point(&p, ctm)); - break; - case FZ_MOVETO: - if (i + 2 == path->len) - { - /* Trailing Moveto - cannot affect bbox */ - i += 2; - break; - } - /* fallthrough */ - case FZ_LINETO: - p.x = path->items[i++].v; - p.y = path->items[i++].v; - bound_expand(r, fz_transform_point(&p, ctm)); - break; - case FZ_CLOSE_PATH: - break; - } - } - - if (stroke) - { - fz_adjust_rect_for_stroke(r, stroke, ctm); - } - - return r; -} - -fz_rect * -fz_adjust_rect_for_stroke(fz_rect *r, const fz_stroke_state *stroke, const fz_matrix *ctm) -{ - float expand; - - if (!stroke) - return r; - - expand = stroke->linewidth; - if (expand == 0) - expand = 1.0f; - expand *= fz_matrix_max_expansion(ctm); - if ((stroke->linejoin == FZ_LINEJOIN_MITER || stroke->linejoin == FZ_LINEJOIN_MITER_XPS) && stroke->miterlimit > 1) - expand *= stroke->miterlimit; - - r->x0 -= expand; - r->y0 -= expand; - r->x1 += expand; - r->y1 += expand; - return r; -} - -void -fz_transform_path(fz_context *ctx, fz_path *path, const fz_matrix *ctm) -{ - int k, i = 0; - - while (i < path->len) - { - switch (path->items[i++].k) - { - case FZ_CURVETO: - for (k = 0; k < 3; k++) - { - fz_transform_point((fz_point *)(void *)&path->items[i].v, ctm); - i += 2; - } - break; - case FZ_MOVETO: - case FZ_LINETO: - fz_transform_point((fz_point *)(void *)&path->items[i].v, ctm); - i += 2; - break; - case FZ_CLOSE_PATH: - break; - } - } -} - -#ifndef NDEBUG -void -fz_print_path(fz_context *ctx, FILE *out, fz_path *path, int indent) -{ - float x, y; - int i = 0; - int n; - while (i < path->len) - { - for (n = 0; n < indent; n++) - fputc(' ', out); - switch (path->items[i++].k) - { - case FZ_MOVETO: - x = path->items[i++].v; - y = path->items[i++].v; - fprintf(out, "%g %g m\n", x, y); - break; - case FZ_LINETO: - x = path->items[i++].v; - y = path->items[i++].v; - fprintf(out, "%g %g l\n", x, y); - break; - case FZ_CURVETO: - x = path->items[i++].v; - y = path->items[i++].v; - fprintf(out, "%g %g ", x, y); - x = path->items[i++].v; - y = path->items[i++].v; - fprintf(out, "%g %g ", x, y); - x = path->items[i++].v; - y = path->items[i++].v; - fprintf(out, "%g %g c\n", x, y); - break; - case FZ_CLOSE_PATH: - fprintf(out, "h\n"); - break; - } - } -} -#endif - -fz_stroke_state * -fz_keep_stroke_state(fz_context *ctx, fz_stroke_state *stroke) -{ - if (!stroke) - return NULL; - - fz_lock(ctx, FZ_LOCK_ALLOC); - if (stroke->refs > 0) - stroke->refs++; - fz_unlock(ctx, FZ_LOCK_ALLOC); - return stroke; -} - -void -fz_drop_stroke_state(fz_context *ctx, fz_stroke_state *stroke) -{ - int drop; - - if (!stroke) - return; - - fz_lock(ctx, FZ_LOCK_ALLOC); - drop = (stroke->refs > 0 ? --stroke->refs == 0 : 0); - fz_unlock(ctx, FZ_LOCK_ALLOC); - if (drop) - fz_free(ctx, stroke); -} - -fz_stroke_state * -fz_new_stroke_state_with_len(fz_context *ctx, int len) -{ - fz_stroke_state *state; - - len -= nelem(state->dash_list); - if (len < 0) - len = 0; - - state = Memento_label(fz_malloc(ctx, sizeof(*state) + sizeof(state->dash_list[0]) * len), "fz_stroke_state"); - state->refs = 1; - state->start_cap = FZ_LINECAP_BUTT; - state->dash_cap = FZ_LINECAP_BUTT; - state->end_cap = FZ_LINECAP_BUTT; - state->linejoin = FZ_LINEJOIN_MITER; - state->linewidth = 1; - state->miterlimit = 10; - state->dash_phase = 0; - state->dash_len = 0; - memset(state->dash_list, 0, sizeof(state->dash_list[0]) * (len + nelem(state->dash_list))); - - return state; -} - -fz_stroke_state * -fz_new_stroke_state(fz_context *ctx) -{ - return fz_new_stroke_state_with_len(ctx, 0); -} - -fz_stroke_state * -fz_unshare_stroke_state_with_len(fz_context *ctx, fz_stroke_state *shared, int len) -{ - int single, unsize, shsize, shlen, drop; - fz_stroke_state *unshared; - - fz_lock(ctx, FZ_LOCK_ALLOC); - single = (shared->refs == 1); - fz_unlock(ctx, FZ_LOCK_ALLOC); - - shlen = shared->dash_len - nelem(shared->dash_list); - if (shlen < 0) - shlen = 0; - shsize = sizeof(*shared) + sizeof(shared->dash_list[0]) * shlen; - len -= nelem(shared->dash_list); - if (len < 0) - len = 0; - if (single && shlen >= len) - return shared; - unsize = sizeof(*unshared) + sizeof(unshared->dash_list[0]) * len; - unshared = Memento_label(fz_malloc(ctx, unsize), "fz_stroke_state"); - memcpy(unshared, shared, (shsize > unsize ? unsize : shsize)); - unshared->refs = 1; - fz_lock(ctx, FZ_LOCK_ALLOC); - drop = (shared->refs > 0 ? --shared->refs == 0 : 0); - fz_unlock(ctx, FZ_LOCK_ALLOC); - if (drop) - fz_free(ctx, shared); - return unshared; -} - -fz_stroke_state * -fz_unshare_stroke_state(fz_context *ctx, fz_stroke_state *shared) -{ - return fz_unshare_stroke_state_with_len(ctx, shared, shared->dash_len); -} diff --git a/fitz/res_pcl.c b/fitz/res_pcl.c deleted file mode 100644 index eae5dad2..00000000 --- a/fitz/res_pcl.c +++ /dev/null @@ -1,856 +0,0 @@ -#include "mupdf/fitz.h" - -/* Lifted from ghostscript gdevjlm.h */ -/* - * The notion that there is such a thing as a "PCL printer" is a fiction: no - * two "PCL" printers, even at the same PCL level, have identical command - * sets. (The H-P documentation isn't fully accurate either; for example, - * it doesn't reveal that the DeskJet printers implement anything beyond PCL - * 3.) - * - * This file contains feature definitions for a generic monochrome PCL - * driver (gdevdljm.c), and the specific feature values for all such - * printers that Ghostscript currently supports. - */ - -/* Printer spacing capabilities. Include at most one of these. */ -#define PCL_NO_SPACING 0 /* no vertical spacing capability, must be 0 */ -#define PCL3_SPACING 1 /* *p+Y (PCL 3) */ -#define PCL4_SPACING 2 /* *bY (PCL 4) */ -#define PCL5_SPACING 4 /* *bY and clear seed row (PCL 5) */ -/* The following is only used internally. */ -#define PCL_ANY_SPACING \ - (PCL3_SPACING | PCL4_SPACING | PCL5_SPACING) - -/* Individual printer properties. Any subset of these may be included. */ -#define PCL_MODE_2_COMPRESSION 8 /* compression mode 2 supported */ - /* (PCL 4) */ -#define PCL_MODE_3_COMPRESSION 16 /* compression modes 2 & 3 supported */ - /* (PCL 5) */ -#define PCL_END_GRAPHICS_DOES_RESET 32 /* *rB resets all parameters */ -#define PCL_HAS_DUPLEX 64 /* &lS supported */ -#define PCL_CAN_SET_PAPER_SIZE 128 /* &lA supported */ -#define PCL_CAN_PRINT_COPIES 256 /* &lX supported */ -#define HACK__IS_A_LJET4PJL 512 -#define HACK__IS_A_OCE9050 1024 - -/* Shorthands for the most common spacing/compression combinations. */ -#define PCL_MODE0 PCL3_SPACING -#define PCL_MODE0NS PCL_NO_SPACING -#define PCL_MODE2 (PCL4_SPACING | PCL_MODE_2_COMPRESSION) -#define PCL_MODE2P (PCL_NO_SPACING | PCL_MODE_2_COMPRESSION) -#define PCL_MODE3 (PCL5_SPACING | PCL_MODE_3_COMPRESSION) -#define PCL_MODE3NS (PCL_NO_SPACING | PCL_MODE_3_COMPRESSION) - -#define MIN_SKIP_LINES 7 -static const char *const from2to3 = "\033*b3M"; -static const char *const from3to2 = "\033*b2M"; -static const int penalty_from2to3 = 5; /* strlen(from2to3); */ -static const int penalty_from3to2 = 5; /* strlen(from3to2); */ - -/* H-P DeskJet */ -static const fz_pcl_options fz_pcl_options_ljet4 = -{ - (PCL_MODE2 | PCL_END_GRAPHICS_DOES_RESET | PCL_CAN_SET_PAPER_SIZE), - "\033&k1W\033*b2M", - "\033&k1W\033*b2M" -}; - -/* H-P DeskJet 500 */ -static const fz_pcl_options fz_pcl_options_dj500 = -{ - (PCL_MODE3 | PCL_END_GRAPHICS_DOES_RESET | PCL_CAN_SET_PAPER_SIZE), - "\033&k1W", - "\033&k1W" -}; - -/* Kyocera FS-600 */ -static const fz_pcl_options fz_pcl_options_fs600 = -{ - (PCL_MODE3 | PCL_CAN_SET_PAPER_SIZE | PCL_CAN_PRINT_COPIES), - "\033*r0F\033&u%dD", - "\033*r0F\033&u%dD" -}; - -/* H-P original LaserJet */ -/* H-P LaserJet Plus */ -static const fz_pcl_options fz_pcl_options_lj = -{ - (PCL_MODE0), - "\033*b0M", - "\033*b0M" -}; - -/* H-P LaserJet IIp, IId */ -static const fz_pcl_options fz_pcl_options_lj2 = -{ - (PCL_MODE2P | PCL_CAN_SET_PAPER_SIZE), - "\033*r0F\033*b2M", - "\033*r0F\033*b2M" -}; - -/* H-P LaserJet III* */ -static const fz_pcl_options fz_pcl_options_lj3 = -{ - (PCL_MODE3 | PCL_CAN_SET_PAPER_SIZE | PCL_CAN_PRINT_COPIES), - "\033&l-180u36Z\033*r0F", - "\033&l-180u36Z\033*r0F" -}; - -/* H-P LaserJet IIId */ -static const fz_pcl_options fz_pcl_options_lj3d = -{ - (PCL_MODE3 | PCL_HAS_DUPLEX | PCL_CAN_SET_PAPER_SIZE | PCL_CAN_PRINT_COPIES), - "\033&l-180u36Z\033*r0F", - "\033&l180u36Z\033*r0F" -}; - -/* H-P LaserJet 4 */ -static const fz_pcl_options fz_pcl_options_lj4 = -{ - (PCL_MODE3 | PCL_CAN_SET_PAPER_SIZE | PCL_CAN_PRINT_COPIES), - "\033&l-180u36Z\033*r0F\033&u%dD", - "\033&l-180u36Z\033*r0F\033&u%dD" -}; - -/* H-P LaserJet 4 PL */ -static const fz_pcl_options fz_pcl_options_lj4pl = -{ - (PCL_MODE3 | PCL_CAN_SET_PAPER_SIZE | PCL_CAN_PRINT_COPIES | HACK__IS_A_LJET4PJL), - "\033&l-180u36Z\033*r0F\033&u%dD", - "\033&l-180u36Z\033*r0F\033&u%dD" -}; - -/* H-P LaserJet 4d */ -static const fz_pcl_options fz_pcl_options_lj4d = -{ - (PCL_MODE3 | PCL_HAS_DUPLEX | PCL_CAN_SET_PAPER_SIZE | PCL_CAN_PRINT_COPIES), - "\033&l-180u36Z\033*r0F\033&u%dD", - "\033&l180u36Z\033*r0F\033&u%dD" -}; - -/* H-P 2563B line printer */ -static const fz_pcl_options fz_pcl_options_lp2563b = -{ - (PCL_MODE0NS | PCL_CAN_SET_PAPER_SIZE), - "\033*b0M", - "\033*b0M" -}; - -/* OCE 9050 line printer */ -static const fz_pcl_options fz_pcl_options_oce9050 = -{ - (PCL_MODE3NS | PCL_CAN_SET_PAPER_SIZE | HACK__IS_A_OCE9050), - "\033*b0M", - "\033*b0M" -}; - -static void copy_opts(fz_pcl_options *dst, const fz_pcl_options *src) -{ - if (dst) - *dst = *src; -} - -void fz_pcl_preset(fz_context *ctx, fz_pcl_options *opts, const char *preset) -{ - if (preset == NULL || *preset == 0 || !strcmp(preset, "ljet4")) - copy_opts(opts, &fz_pcl_options_ljet4); - else if (!strcmp(preset, "dj500")) - copy_opts(opts, &fz_pcl_options_dj500); - else if (!strcmp(preset, "fs600")) - copy_opts(opts, &fz_pcl_options_fs600); - else if (!strcmp(preset, "lj")) - copy_opts(opts, &fz_pcl_options_lj); - else if (!strcmp(preset, "lj2")) - copy_opts(opts, &fz_pcl_options_lj2); - else if (!strcmp(preset, "lj3")) - copy_opts(opts, &fz_pcl_options_lj3); - else if (!strcmp(preset, "lj3d")) - copy_opts(opts, &fz_pcl_options_lj3d); - else if (!strcmp(preset, "lj4")) - copy_opts(opts, &fz_pcl_options_lj4); - else if (!strcmp(preset, "lj4pl")) - copy_opts(opts, &fz_pcl_options_lj4pl); - else if (!strcmp(preset, "lj4d")) - copy_opts(opts, &fz_pcl_options_lj4d); - else if (!strcmp(preset, "lp2563b")) - copy_opts(opts, &fz_pcl_options_lp2563b); - else if (!strcmp(preset, "oce9050")) - copy_opts(opts, &fz_pcl_options_oce9050); - else - fz_throw(ctx, FZ_ERROR_GENERIC, "Unknown preset '%s'", preset); -} - -void fz_pcl_option(fz_context *ctx, fz_pcl_options *opts, const char *option, int val) -{ - if (opts == NULL) - return; - - if (!strcmp(option, "spacing")) - { - switch (val) - { - case 0: - opts->features &= ~PCL_ANY_SPACING; - break; - case 1: - opts->features = (opts->features & ~PCL_ANY_SPACING) | PCL3_SPACING; - break; - case 2: - opts->features = (opts->features & ~PCL_ANY_SPACING) | PCL4_SPACING; - break; - case 3: - opts->features = (opts->features & ~PCL_ANY_SPACING) | PCL5_SPACING; - break; - default: - fz_throw(ctx, FZ_ERROR_GENERIC, "Unsupported PCL spacing %d (0-3 only)", val); - } - } - else if (!strcmp(option, "mode2")) - { - if (val == 0) - opts->features &= ~PCL_MODE_2_COMPRESSION; - else if (val == 1) - opts->features |= PCL_MODE_2_COMPRESSION; - else - fz_throw(ctx, FZ_ERROR_GENERIC, "Expected 0 or 1 for mode2 value"); - } - else if (!strcmp(option, "mode3")) - { - if (val == 0) - opts->features &= ~PCL_MODE_3_COMPRESSION; - else if (val == 1) - opts->features |= PCL_MODE_3_COMPRESSION; - else - fz_throw(ctx, FZ_ERROR_GENERIC, "Expected 0 or 1 for mode3 value"); - } - else if (!strcmp(option, "eog_reset")) - { - if (val == 0) - opts->features &= ~PCL_END_GRAPHICS_DOES_RESET; - else if (val == 1) - opts->features |= PCL_END_GRAPHICS_DOES_RESET; - else - fz_throw(ctx, FZ_ERROR_GENERIC, "Expected 0 or 1 for eog_reset value"); - } - else if (!strcmp(option, "has_duplex")) - { - if (val == 0) - opts->features &= ~PCL_HAS_DUPLEX; - else if (val == 1) - opts->features |= PCL_HAS_DUPLEX; - else - fz_throw(ctx, FZ_ERROR_GENERIC, "Expected 0 or 1 for has_duplex value"); - } - else if (!strcmp(option, "has_papersize")) - { - if (val == 0) - opts->features &= ~PCL_CAN_SET_PAPER_SIZE; - else if (val == 1) - opts->features |= PCL_CAN_SET_PAPER_SIZE; - else - fz_throw(ctx, FZ_ERROR_GENERIC, "Expected 0 or 1 for has_papersize value"); - } - else if (!strcmp(option, "has_copies")) - { - if (val == 0) - opts->features &= ~PCL_CAN_PRINT_COPIES; - else if (val == 1) - opts->features |= PCL_CAN_PRINT_COPIES; - else - fz_throw(ctx, FZ_ERROR_GENERIC, "Expected 0 or 1 for has_papersize value"); - } - else if (!strcmp(option, "is_ljet4pjl")) - { - if (val == 0) - opts->features &= ~HACK__IS_A_LJET4PJL; - else if (val == 1) - opts->features |= HACK__IS_A_LJET4PJL; - else - fz_throw(ctx, FZ_ERROR_GENERIC, "Expected 0 or 1 for is_ljet4pjl value"); - } - else if (!strcmp(option, "is_oce9050")) - { - if (val == 0) - opts->features &= ~HACK__IS_A_OCE9050; - else if (val == 1) - opts->features |= HACK__IS_A_OCE9050; - else - fz_throw(ctx, FZ_ERROR_GENERIC, "Expected 0 or 1 for is_oce9050 value"); - } - else - fz_throw(ctx, FZ_ERROR_GENERIC, "Unknown pcl option '%s'", option); -} - -static void -make_init(fz_pcl_options *pcl, char *buf, unsigned long len, const char *str, int res) -{ - int paper_source = -1; - - snprintf(buf, len, str, res); - - if (pcl->manual_feed_set && pcl->manual_feed) - paper_source = 2; - else if (pcl->media_position_set && pcl->media_position >= 0) - paper_source = pcl->media_position; - if (paper_source >= 0) - { - char buf2[40]; - snprintf(buf2, sizeof(buf2), "\033&l%dH", paper_source); - strncat(buf, buf2, len); - } -} - -static void -pcl_header(fz_output *out, fz_pcl_options *pcl, int num_copies, int xres) -{ - char odd_page_init[80]; - char even_page_init[80]; - - make_init(pcl, odd_page_init, sizeof(odd_page_init), pcl->odd_page_init, xres); - make_init(pcl, even_page_init, sizeof(even_page_init), pcl->even_page_init, xres); - - if (pcl->page_count == 0) - { - if (pcl->features & HACK__IS_A_LJET4PJL) - fz_puts(out, "\033%-12345X@PJL\r\n@PJL ENTER LANGUAGE = PCL\r\n"); - fz_puts(out, "\033E"); /* reset printer */ - /* If the printer supports it, set the paper size */ - /* based on the actual requested size. */ - if (pcl->features & PCL_CAN_SET_PAPER_SIZE) - fz_printf(out, "\033&l%dA", pcl->paper_size); - /* If printer can duplex, set duplex mode appropriately. */ - if (pcl->features & PCL_HAS_DUPLEX) - { - if (pcl->duplex_set) - { - if (pcl->duplex) - { - if (!pcl->tumble) - fz_puts(out, "\033&l1S"); - else - fz_puts(out, "\033&l2S"); - } - else - fz_puts(out, "\033&l0S"); - } - else - { - /* default to duplex for this printer */ - fz_puts(out, "\033&l1S"); - } - } - } - - /* Put out per-page initialization. */ - /* in duplex mode the sheet is already in process, so there are some - * commands which must not be sent to the printer for the 2nd page, - * as this commands will cause the printer to eject the sheet with - * only the 1st page printed. This commands are: - * \033&l%dA (setting paper size) - * \033&l%dH (setting paper tray) - * in simplex mode we set this parameters for each page, - * in duplex mode we set this parameters for each odd page - */ - - if ((pcl->features & PCL_HAS_DUPLEX) && pcl->duplex_set && pcl->duplex) - { - /* We are printing duplex, so change margins as needed */ - if (((pcl->page_count/num_copies)%2) == 0) - { - if (pcl->page_count != 0 && (pcl->features & PCL_CAN_SET_PAPER_SIZE)) - { - fz_printf(out, "\033&l%dA", pcl->paper_size); - } - fz_puts(out, "\033&l0o0l0E"); - fz_puts(out, pcl->odd_page_init); - } - else - fz_puts(out, pcl->even_page_init); - } - else - { - if (pcl->features & PCL_CAN_SET_PAPER_SIZE) - { - fz_printf(out, "\033&l%dA", pcl->paper_size); - } - fz_puts(out, "\033&l0o0l0E"); - fz_puts(out, pcl->odd_page_init); - } - - fz_printf(out, "\033&l%dX", num_copies); /* # of copies */ - - /* End raster graphics, position cursor at top. */ - fz_puts(out, "\033*rB\033*p0x0Y"); - - /* The DeskJet and DeskJet Plus reset everything upon */ - /* receiving \033*rB, so we must reinitialize graphics mode. */ - if (pcl->features & PCL_END_GRAPHICS_DOES_RESET) - { - fz_puts(out, pcl->odd_page_init); /* Assume this does the right thing */ - fz_printf(out, "\033&l%dX", num_copies); /* # of copies */ - } - - /* Set resolution. */ - fz_printf(out, "\033*t%dR", xres); - pcl->page_count++; -} - -void -fz_output_pcl(fz_output *out, const fz_pixmap *pixmap, fz_pcl_options *pcl) -{ - //unsigned char *sp; - //int y, x, sn, dn, ss; - fz_context *ctx; - - if (!out || !pixmap) - return; - - ctx = out->ctx; - - if (pixmap->n != 1 && pixmap->n != 2 && pixmap->n != 4) - fz_throw(ctx, FZ_ERROR_GENERIC, "pixmap must be grayscale or rgb to write as pcl"); - - pcl_header(out, pcl, 1, pixmap->xres); - -#if 0 - sn = pixmap->n; - dn = pixmap->n; - if (dn == 2 || dn == 4) - dn--; - - /* Now output the actual bitmap, using a packbits like compression */ - sp = pixmap->samples; - ss = pixmap->w * sn; - y = 0; - while (y < pixmap->h) - { - int yrep; - - assert(sp == pixmap->samples + y * ss); - - /* Count the number of times this line is repeated */ - for (yrep = 1; yrep < 256 && y+yrep < pixmap->h; yrep++) - { - if (memcmp(sp, sp + yrep * ss, ss) != 0) - break; - } - fz_write_byte(out, yrep-1); - - /* Encode the line */ - x = 0; - while (x < pixmap->w) - { - int d; - - assert(sp == pixmap->samples + y * ss + x * sn); - - /* How far do we have to look to find a repeated value? */ - for (d = 1; d < 128 && x+d < pixmap->w; d++) - { - if (memcmp(sp + (d-1)*sn, sp + d*sn, sn) == 0) - break; - } - if (d == 1) - { - int xrep; - - /* We immediately have a repeat (or we've hit - * the end of the line). Count the number of - * times this value is repeated. */ - for (xrep = 1; xrep < 128 && x+xrep < pixmap->w; xrep++) - { - if (memcmp(sp, sp + xrep*sn, sn) != 0) - break; - } - fz_write_byte(out, xrep-1); - fz_write(out, sp, dn); - sp += sn*xrep; - x += xrep; - } - else - { - fz_write_byte(out, 257-d); - x += d; - while (d > 0) - { - fz_write(out, sp, dn); - sp += sn; - d--; - } - } - } - - /* Move to the next line */ - sp += ss*(yrep-1); - y += yrep; - } -#endif -} - -/* - * Mode 2 Row compression routine for the HP DeskJet & LaserJet IIp. - * Compresses data from row up to end_row, storing the result - * starting at compressed. Returns the number of bytes stored. - * Runs of K<=127 literal bytes are encoded as K-1 followed by - * the bytes; runs of 2<=K<=127 identical bytes are encoded as - * 257-K followed by the byte. - * In the worst case, the result is N+(N/127)+1 bytes long, - * where N is the original byte count (end_row - row). - */ -int -mode2compress(unsigned char *out, unsigned char *in, int in_len) -{ - int x; - int out_len = 0; - int run; - - for (x = 0; x < in_len; x += run) - { - /* How far do we have to look to find a value that isn't repeated? */ - for (run = 1; run < 127 && x+run < in_len; run++) - if (in[0] != in[run]) - break; - if (run > 1) - { - /* We have a run of matching bytes */ - out[out_len++] = 257-run; - out[out_len++] = in[0]; - } - else - { - int i; - - /* How many literals do we need to copy? */ - for (run = 1; run < 127 && x+run < in_len; run++) - if (in[run] == in[run+1]) - break; - out[out_len++] = run-1; - for (i = 0; i < run; i++) - out[out_len++] = in[i]; - } - in += run; - } - return out_len; -} - -/* - * Mode 3 compression routine for the HP LaserJet III family. - * Compresses bytecount bytes starting at current, storing the result - * in compressed, comparing against and updating previous. - * Returns the number of bytes stored. In the worst case, - * the number of bytes is bytecount+(bytecount/8)+1. - */ -int -mode3compress(unsigned char *out, const unsigned char *in, unsigned char *prev, int in_len) -{ - unsigned char *compressed = out; - const unsigned char *cur = in; - const unsigned char *end = in + in_len; - - while (cur < end) { /* Detect a maximum run of unchanged bytes. */ - const unsigned char *run = cur; - const unsigned char *diff; - const unsigned char *stop; - int offset, cbyte; - - while (cur < end && *cur == *prev) { - cur++, prev++; - } - if (cur == end) - break; /* rest of row is unchanged */ - /* Detect a run of up to 8 changed bytes. */ - /* We know that *cur != *prev. */ - diff = cur; - stop = (end - cur > 8 ? cur + 8 : end); - do - { - *prev++ = *cur++; - } - while (cur < stop && *cur != *prev); - /* Now [run..diff) are unchanged, and */ - /* [diff..cur) are changed. */ - /* Generate the command byte(s). */ - offset = diff - run; - cbyte = (cur - diff - 1) << 5; - if (offset < 31) - *out++ = cbyte + offset; - else { - *out++ = cbyte + 31; - offset -= 31; - while (offset >= 255) - *out++ = 255, offset -= 255; - *out++ = offset; - } - /* Copy the changed data. */ - while (diff < cur) - *out++ = *diff++; - } - return out - compressed; -} - -void wind(void) -{} - -void -fz_output_pcl_bitmap(fz_output *out, const fz_bitmap *bitmap, fz_pcl_options *pcl) -{ - unsigned char *data, *out_data; - int y, ss, rmask, line_size; - fz_context *ctx; - int num_blank_lines; - int compression = -1; - unsigned char *prev_row = NULL; - unsigned char *out_row_mode_2 = NULL; - unsigned char *out_row_mode_3 = NULL; - int out_count; - int max_mode_2_size; - int max_mode_3_size; - - if (!out || !bitmap) - return; - - ctx = out->ctx; - - if (pcl->features & HACK__IS_A_OCE9050) - { - /* Enter HPGL/2 mode, begin plot, Initialise (start plot), Enter PCL mode */ - fz_puts(out, "\033%1BBPIN;\033%1A"); - } - - pcl_header(out, pcl, 1, bitmap->xres); - - fz_var(prev_row); - fz_var(out_row_mode_2); - fz_var(out_row_mode_3); - - fz_try(ctx) - { - num_blank_lines = 0; - rmask = ~0 << (-bitmap->w & 7); - line_size = (bitmap->w + 7)/8; - max_mode_2_size = line_size + (line_size/127) + 1; - max_mode_3_size = line_size + (line_size/8) + 1; - prev_row = fz_calloc(ctx, line_size, sizeof(unsigned char)); - out_row_mode_2 = fz_calloc(ctx, max_mode_2_size, sizeof(unsigned char)); - out_row_mode_3 = fz_calloc(ctx, max_mode_3_size, sizeof(unsigned char)); - - /* Transfer raster graphics. */ - data = bitmap->samples; - ss = bitmap->stride; - for (y = 0; y < bitmap->h; y++, data += ss) - { - unsigned char *end_data = data + line_size; - - if ((end_data[-1] & rmask) == 0) - { - end_data--; - while (end_data > data && end_data[-1] == 0) - end_data--; - } - if (end_data == data) - { - /* Blank line */ - num_blank_lines++; - continue; - } - wind(); - - /* We've reached a non-blank line. */ - /* Put out a spacing command if necessary. */ - if (num_blank_lines == y) { - /* We're at the top of a page. */ - if (pcl->features & PCL_ANY_SPACING) - { - if (num_blank_lines > 0) - fz_printf(out, "\033*p+%dY", num_blank_lines * bitmap->yres); - /* Start raster graphics. */ - fz_puts(out, "\033*r1A"); - } - else if (pcl->features & PCL_MODE_3_COMPRESSION) - { - /* Start raster graphics. */ - fz_puts(out, "\033*r1A"); - for (; num_blank_lines; num_blank_lines--) - fz_puts(out, "\033*b0W"); - } - else - { - /* Start raster graphics. */ - fz_puts(out, "\033*r1A"); - for (; num_blank_lines; num_blank_lines--) - fz_puts(out, "\033*bW"); - } - } - - /* Skip blank lines if any */ - else if (num_blank_lines != 0) - { - /* Moving down from current position causes head - * motion on the DeskJet, so if the number of lines - * is small, we're better off printing blanks. - * - * For Canon LBP4i and some others, *bY - * doesn't properly clear the seed row if we are in - * compression mode 3. - */ - if ((num_blank_lines < MIN_SKIP_LINES && compression != 3) || - !(pcl->features & PCL_ANY_SPACING)) - { - int mode_3ns = ((pcl->features & PCL_MODE_3_COMPRESSION) && !(pcl->features & PCL_ANY_SPACING)); - if (mode_3ns && compression != 2) - { - /* Switch to mode 2 */ - fz_puts(out, from3to2); - compression = 2; - } - if (pcl->features & PCL_MODE_3_COMPRESSION) - { - /* Must clear the seed row. */ - fz_puts(out, "\033*b1Y"); - num_blank_lines--; - } - if (mode_3ns) - { - for (; num_blank_lines; num_blank_lines--) - fz_puts(out, "\033*b0W"); - } - else - { - for (; num_blank_lines; num_blank_lines--) - fz_puts(out, "\033*bW"); - } - } - else if (pcl->features & PCL3_SPACING) - fz_printf(out, "\033*p+%dY", num_blank_lines * bitmap->yres); - else - fz_printf(out, "\033*b%dY", num_blank_lines); - /* Clear the seed row (only matters for mode 3 compression). */ - memset(prev_row, 0, line_size); - } - num_blank_lines = 0; - - /* Choose the best compression mode for this particular line. */ - if (pcl->features & PCL_MODE_3_COMPRESSION) - { - /* Compression modes 2 and 3 are both available. Try - * both and see which produces the least output data. - */ - int count3 = mode3compress(out_row_mode_3, data, prev_row, line_size); - int count2 = mode2compress(out_row_mode_2, data, line_size); - int penalty3 = (compression == 3 ? 0 : penalty_from2to3); - int penalty2 = (compression == 2 ? 0 : penalty_from3to2); - - if (count3 + penalty3 < count2 + penalty2) - { - if (compression != 3) - fz_puts(out, from2to3); - compression = 3; - out_data = (unsigned char *)out_row_mode_3; - out_count = count3; - } - else - { - if (compression != 2) - fz_puts(out, from3to2); - compression = 2; - out_data = (unsigned char *)out_row_mode_2; - out_count = count2; - } - } - else if (pcl->features & PCL_MODE_2_COMPRESSION) - { - out_data = out_row_mode_2; - out_count = mode2compress(out_row_mode_2, data, line_size); - } - else - { - out_data = data; - out_count = line_size; - } - - /* Transfer the data */ - fz_printf(out, "\033*b%dW", out_count); - fz_write(out, out_data, out_count); - } - - /* end raster graphics and eject page */ - fz_puts(out, "\033*rB\f"); - - if (pcl->features & HACK__IS_A_OCE9050) - { - /* Pen up, pen select, advance full page, reset */ - fz_puts(out, "\033%1BPUSP0PG;\033E"); - } - } - fz_always(ctx) - { - fz_free(ctx, prev_row); - fz_free(ctx, out_row_mode_2); - fz_free(ctx, out_row_mode_3); - } - fz_catch(ctx) - { - fz_rethrow(ctx); - } -} - -void -fz_write_pcl(fz_context *ctx, fz_pixmap *pixmap, char *filename, int append, fz_pcl_options *pcl) -{ - FILE *fp; - fz_output *out = NULL; - - fp = fopen(filename, append ? "ab" : "wb"); - if (!fp) - { - fz_throw(ctx, FZ_ERROR_GENERIC, "cannot open file '%s': %s", filename, strerror(errno)); - } - - fz_var(out); - - fz_try(ctx) - { - out = fz_new_output_with_file(ctx, fp); - fz_output_pcl(out, pixmap, pcl); - } - fz_always(ctx) - { - fz_close_output(out); - fclose(fp); - } - fz_catch(ctx) - { - fz_rethrow(ctx); - } -} - -void -fz_write_pcl_bitmap(fz_context *ctx, fz_bitmap *bitmap, char *filename, int append, fz_pcl_options *pcl) -{ - FILE *fp; - fz_output *out = NULL; - - fp = fopen(filename, append ? "ab" : "wb"); - if (!fp) - { - fz_throw(ctx, FZ_ERROR_GENERIC, "cannot open file '%s': %s", filename, strerror(errno)); - } - - fz_var(out); - - fz_try(ctx) - { - out = fz_new_output_with_file(ctx, fp); - fz_output_pcl_bitmap(out, bitmap, pcl); - } - fz_always(ctx) - { - fz_close_output(out); - fclose(fp); - } - fz_catch(ctx) - { - fz_rethrow(ctx); - } -} diff --git a/fitz/res_pixmap.c b/fitz/res_pixmap.c deleted file mode 100644 index 7391c17e..00000000 --- a/fitz/res_pixmap.c +++ /dev/null @@ -1,1062 +0,0 @@ -#include "mupdf/fitz.h" - -fz_pixmap * -fz_keep_pixmap(fz_context *ctx, fz_pixmap *pix) -{ - return (fz_pixmap *)fz_keep_storable(ctx, &pix->storable); -} - -void -fz_drop_pixmap(fz_context *ctx, fz_pixmap *pix) -{ - fz_drop_storable(ctx, &pix->storable); -} - -void -fz_free_pixmap_imp(fz_context *ctx, fz_storable *pix_) -{ - fz_pixmap *pix = (fz_pixmap *)pix_; - - if (pix->colorspace) - fz_drop_colorspace(ctx, pix->colorspace); - if (pix->free_samples) - fz_free(ctx, pix->samples); - fz_free(ctx, pix); -} - -fz_pixmap * -fz_new_pixmap_with_data(fz_context *ctx, fz_colorspace *colorspace, int w, int h, unsigned char *samples) -{ - fz_pixmap *pix; - - if (w < 0 || h < 0) - fz_throw(ctx, FZ_ERROR_GENERIC, "Illegal dimensions for pixmap %d %d", w, h); - - pix = fz_malloc_struct(ctx, fz_pixmap); - FZ_INIT_STORABLE(pix, 1, fz_free_pixmap_imp); - pix->x = 0; - pix->y = 0; - pix->w = w; - pix->h = h; - pix->interpolate = 1; - pix->xres = 96; - pix->yres = 96; - pix->colorspace = NULL; - pix->n = 1; - - if (colorspace) - { - pix->colorspace = fz_keep_colorspace(ctx, colorspace); - pix->n = 1 + colorspace->n; - } - - pix->samples = samples; - if (samples) - { - pix->free_samples = 0; - } - else - { - fz_try(ctx) - { - if (pix->w + pix->n - 1 > INT_MAX / pix->n) - fz_throw(ctx, FZ_ERROR_GENERIC, "overly wide image"); - pix->samples = fz_malloc_array(ctx, pix->h, pix->w * pix->n); - } - fz_catch(ctx) - { - if (colorspace) - fz_drop_colorspace(ctx, colorspace); - fz_free(ctx, pix); - fz_rethrow(ctx); - } - pix->free_samples = 1; - } - - return pix; -} - -fz_pixmap * -fz_new_pixmap(fz_context *ctx, fz_colorspace *colorspace, int w, int h) -{ - return fz_new_pixmap_with_data(ctx, colorspace, w, h, NULL); -} - -fz_pixmap * -fz_new_pixmap_with_bbox(fz_context *ctx, fz_colorspace *colorspace, const fz_irect *r) -{ - fz_pixmap *pixmap; - pixmap = fz_new_pixmap(ctx, colorspace, r->x1 - r->x0, r->y1 - r->y0); - pixmap->x = r->x0; - pixmap->y = r->y0; - return pixmap; -} - -fz_pixmap * -fz_new_pixmap_with_bbox_and_data(fz_context *ctx, fz_colorspace *colorspace, const fz_irect *r, unsigned char *samples) -{ - fz_pixmap *pixmap = fz_new_pixmap_with_data(ctx, colorspace, r->x1 - r->x0, r->y1 - r->y0, samples); - pixmap->x = r->x0; - pixmap->y = r->y0; - return pixmap; -} - -fz_irect * -fz_pixmap_bbox(fz_context *ctx, fz_pixmap *pix, fz_irect *bbox) -{ - bbox->x0 = pix->x; - bbox->y0 = pix->y; - bbox->x1 = pix->x + pix->w; - bbox->y1 = pix->y + pix->h; - return bbox; -} - -fz_irect * -fz_pixmap_bbox_no_ctx(fz_pixmap *pix, fz_irect *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) -{ - memset(pix->samples, 0, (unsigned int)(pix->w * pix->h * pix->n)); -} - -void -fz_clear_pixmap_with_value(fz_context *ctx, fz_pixmap *pix, int value) -{ - if (value == 255) - { - memset(pix->samples, 255, (unsigned int)(pix->w * pix->h * pix->n)); - } - else - { - int k, x, y; - unsigned char *s = pix->samples; - for (y = 0; y < pix->h; y++) - { - for (x = 0; x < pix->w; x++) - { - for (k = 0; k < pix->n - 1; k++) - *s++ = value; - *s++ = 255; - } - } - } -} - -void -fz_copy_pixmap_rect(fz_context *ctx, fz_pixmap *dest, fz_pixmap *src, const fz_irect *b) -{ - const unsigned char *srcp; - unsigned char *destp; - int x, y, w, destspan, srcspan; - fz_irect local_b, bb; - - local_b = *b; - fz_intersect_irect(&local_b, fz_pixmap_bbox(ctx, dest, &bb)); - fz_intersect_irect(&local_b, fz_pixmap_bbox(ctx, src, &bb)); - w = local_b.x1 - local_b.x0; - y = local_b.y1 - local_b.y0; - if (w <= 0 || y <= 0) - return; - - srcspan = src->w * src->n; - srcp = src->samples + (unsigned int)(srcspan * (local_b.y0 - src->y) + src->n * (local_b.x0 - src->x)); - destspan = dest->w * dest->n; - destp = dest->samples + (unsigned int)(destspan * (local_b.y0 - dest->y) + dest->n * (local_b.x0 - dest->x)); - - if (src->n == dest->n) - { - w *= src->n; - do - { - memcpy(destp, srcp, w); - srcp += srcspan; - destp += destspan; - } - while (--y); - } - else if (src->n == 2 && dest->n == 4) - { - /* Copy, and convert from grey+alpha to rgb+alpha */ - srcspan -= w*2; - destspan -= w*4; - do - { - for (x = w; x > 0; x--) - { - unsigned char v = *srcp++; - unsigned char a = *srcp++; - *destp++ = v; - *destp++ = v; - *destp++ = v; - *destp++ = a; - } - srcp += srcspan; - destp += destspan; - } - while (--y); - } - else if (src->n == 4 && dest->n == 2) - { - /* Copy, and convert from rgb+alpha to grey+alpha */ - srcspan -= w*4; - destspan -= w*2; - do - { - for (x = w; x > 0; x--) - { - int v; - v = *srcp++; - v += *srcp++; - v += *srcp++; - *destp++ = (unsigned char)((v+1)/3); - *destp++ = *srcp++; - } - srcp += srcspan; - destp += destspan; - } - while (--y); - } - else - { - /* FIXME: Crap conversion */ - int z; - int sn = src->n-1; - int dn = dest->n-1; - - srcspan -= w*src->n; - destspan -= w*dest->n; - do - { - for (x = w; x > 0; x--) - { - int v = 0; - for (z = sn; z > 0; z--) - v += *srcp++; - v = (v * dn + (sn>>1)) / sn; - for (z = dn; z > 0; z--) - *destp++ = (unsigned char)v; - *destp++ = *srcp++; - } - srcp += srcspan; - destp += destspan; - } - while (--y); - } -} - -void -fz_clear_pixmap_rect_with_value(fz_context *ctx, fz_pixmap *dest, int value, const fz_irect *b) -{ - unsigned char *destp; - int x, y, w, k, destspan; - fz_irect bb; - fz_irect local_b = *b; - - fz_intersect_irect(&local_b, fz_pixmap_bbox(ctx, dest, &bb)); - w = local_b.x1 - local_b.x0; - y = local_b.y1 - local_b.y0; - if (w <= 0 || y <= 0) - return; - - destspan = dest->w * dest->n; - destp = dest->samples + (unsigned int)(destspan * (local_b.y0 - dest->y) + dest->n * (local_b.x0 - dest->x)); - if (value == 255) - do - { - memset(destp, 255, (unsigned int)(w * dest->n)); - destp += destspan; - } - while (--y); - else - do - { - unsigned char *s = destp; - for (x = 0; x < w; x++) - { - for (k = 0; k < dest->n - 1; k++) - *s++ = value; - *s++ = 255; - } - destp += destspan; - } - while (--y); -} - -void -fz_premultiply_pixmap(fz_context *ctx, fz_pixmap *pix) -{ - unsigned char *s = pix->samples; - unsigned char a; - int k, x, y; - - for (y = 0; y < pix->h; y++) - { - for (x = 0; x < pix->w; x++) - { - a = s[pix->n - 1]; - for (k = 0; k < pix->n - 1; k++) - s[k] = fz_mul255(s[k], a); - s += pix->n; - } - } -} - -void -fz_unmultiply_pixmap(fz_context *ctx, fz_pixmap *pix) -{ - unsigned char *s = pix->samples; - int a, inva; - int k, x, y; - - for (y = 0; y < pix->h; y++) - { - for (x = 0; x < pix->w; x++) - { - a = s[pix->n - 1]; - inva = a ? 255 * 256 / a : 0; - for (k = 0; k < pix->n - 1; k++) - s[k] = (s[k] * inva) >> 8; - s += pix->n; - } - } -} - -fz_pixmap * -fz_alpha_from_gray(fz_context *ctx, fz_pixmap *gray, int luminosity) -{ - fz_pixmap *alpha; - unsigned char *sp, *dp; - int len; - fz_irect bbox; - - assert(gray->n == 2); - - alpha = fz_new_pixmap_with_bbox(ctx, NULL, fz_pixmap_bbox(ctx, gray, &bbox)); - dp = alpha->samples; - sp = gray->samples; - if (!luminosity) - sp ++; - - len = gray->w * gray->h; - while (len--) - { - *dp++ = sp[0]; - sp += 2; - } - - return alpha; -} - -void -fz_invert_pixmap(fz_context *ctx, fz_pixmap *pix) -{ - unsigned char *s = pix->samples; - int k, x, y; - - for (y = 0; y < pix->h; y++) - { - for (x = 0; x < pix->w; x++) - { - for (k = 0; k < pix->n - 1; k++) - s[k] = 255 - s[k]; - s += pix->n; - } - } -} - -void fz_invert_pixmap_rect(fz_pixmap *image, const fz_irect *rect) -{ - unsigned char *p; - int x, y, n; - - int x0 = fz_clampi(rect->x0 - image->x, 0, image->w - 1); - int x1 = fz_clampi(rect->x1 - image->x, 0, image->w - 1); - int y0 = fz_clampi(rect->y0 - image->y, 0, image->h - 1); - int y1 = fz_clampi(rect->y1 - image->y, 0, image->h - 1); - - for (y = y0; y < y1; y++) - { - p = image->samples + (unsigned int)((y * image->w + x0) * image->n); - for (x = x0; x < x1; x++) - { - for (n = image->n; n > 1; n--, p++) - *p = 255 - *p; - p++; - } - } -} - -void -fz_gamma_pixmap(fz_context *ctx, fz_pixmap *pix, float gamma) -{ - unsigned char gamma_map[256]; - unsigned char *s = pix->samples; - int k, x, y; - - for (k = 0; k < 256; k++) - gamma_map[k] = pow(k / 255.0f, gamma) * 255; - - for (y = 0; y < pix->h; y++) - { - for (x = 0; x < pix->w; x++) - { - for (k = 0; k < pix->n - 1; k++) - s[k] = gamma_map[s[k]]; - s += pix->n; - } - } -} - -/* - * Write pixmap to PNM file (without alpha channel) - */ - -void -fz_write_pnm(fz_context *ctx, fz_pixmap *pixmap, char *filename) -{ - FILE *fp; - unsigned char *p; - int len; - - if (pixmap->n != 1 && pixmap->n != 2 && pixmap->n != 4) - fz_throw(ctx, FZ_ERROR_GENERIC, "pixmap must be grayscale or rgb to write as pnm"); - - fp = fopen(filename, "wb"); - if (!fp) - fz_throw(ctx, FZ_ERROR_GENERIC, "cannot open file '%s': %s", filename, strerror(errno)); - - if (pixmap->n == 1 || pixmap->n == 2) - fprintf(fp, "P5\n"); - if (pixmap->n == 4) - fprintf(fp, "P6\n"); - fprintf(fp, "%d %d\n", pixmap->w, pixmap->h); - fprintf(fp, "255\n"); - - len = pixmap->w * pixmap->h; - p = pixmap->samples; - - switch (pixmap->n) - { - case 1: - fwrite(p, 1, len, fp); - break; - case 2: - while (len--) - { - putc(p[0], fp); - p += 2; - } - break; - case 4: - while (len--) - { - putc(p[0], fp); - putc(p[1], fp); - putc(p[2], fp); - p += 4; - } - } - - fclose(fp); -} - -/* - * Write pixmap to PAM file (with or without alpha channel) - */ - -void -fz_write_pam(fz_context *ctx, fz_pixmap *pixmap, char *filename, int savealpha) -{ - unsigned char *sp; - int y, w, k; - FILE *fp; - - int sn = pixmap->n; - int dn = pixmap->n; - if (!savealpha && dn > 1) - dn--; - - fp = fopen(filename, "wb"); - if (!fp) - fz_throw(ctx, FZ_ERROR_GENERIC, "cannot open file '%s': %s", filename, strerror(errno)); - - fprintf(fp, "P7\n"); - fprintf(fp, "WIDTH %d\n", pixmap->w); - fprintf(fp, "HEIGHT %d\n", pixmap->h); - fprintf(fp, "DEPTH %d\n", dn); - fprintf(fp, "MAXVAL 255\n"); - if (pixmap->colorspace) - fprintf(fp, "# COLORSPACE %s\n", pixmap->colorspace->name); - switch (dn) - { - case 1: fprintf(fp, "TUPLTYPE GRAYSCALE\n"); break; - case 2: if (sn == 2) fprintf(fp, "TUPLTYPE GRAYSCALE_ALPHA\n"); break; - case 3: if (sn == 4) fprintf(fp, "TUPLTYPE RGB\n"); break; - case 4: if (sn == 4) fprintf(fp, "TUPLTYPE RGB_ALPHA\n"); break; - } - fprintf(fp, "ENDHDR\n"); - - sp = pixmap->samples; - for (y = 0; y < pixmap->h; y++) - { - w = pixmap->w; - while (w--) - { - for (k = 0; k < dn; k++) - putc(sp[k], fp); - sp += sn; - } - } - - fclose(fp); -} - -/* - * Write pixmap to PNG file (with or without alpha channel) - */ - -#include - -static inline void big32(unsigned char *buf, unsigned int v) -{ - buf[0] = (v >> 24) & 0xff; - buf[1] = (v >> 16) & 0xff; - buf[2] = (v >> 8) & 0xff; - buf[3] = (v) & 0xff; -} - -static void putchunk(char *tag, unsigned char *data, int size, fz_output *out) -{ - unsigned int sum; - fz_write_int32be(out, size); - fz_write(out, tag, 4); - fz_write(out, data, size); - sum = crc32(0, NULL, 0); - sum = crc32(sum, (unsigned char*)tag, 4); - sum = crc32(sum, data, size); - fz_write_int32be(out, sum); -} - -void -fz_write_png(fz_context *ctx, fz_pixmap *pixmap, char *filename, int savealpha) -{ - FILE *fp = fopen(filename, "wb"); - fz_output *out = NULL; - - if (!fp) - { - fz_throw(ctx, FZ_ERROR_GENERIC, "cannot open file '%s': %s", filename, strerror(errno)); - } - - fz_var(out); - - fz_try(ctx) - { - out = fz_new_output_with_file(ctx, fp); - fz_output_png(out, pixmap, savealpha); - } - fz_always(ctx) - { - fz_close_output(out); - fclose(fp); - } - fz_catch(ctx) - { - fz_rethrow(ctx); - } -} - -void -fz_output_png(fz_output *out, const fz_pixmap *pixmap, int savealpha) -{ - static const unsigned char pngsig[8] = { 137, 80, 78, 71, 13, 10, 26, 10 }; - unsigned char head[13]; - unsigned char *udata = NULL; - unsigned char *cdata = NULL; - unsigned char *sp, *dp; - uLong usize, csize; - int y, x, k, sn, dn; - int color; - int err; - fz_context *ctx; - - if (!out || !pixmap) - return; - - ctx = out->ctx; - - fz_var(udata); - fz_var(cdata); - - if (pixmap->n != 1 && pixmap->n != 2 && pixmap->n != 4) - fz_throw(ctx, FZ_ERROR_GENERIC, "pixmap must be grayscale or rgb to write as png"); - - sn = pixmap->n; - dn = pixmap->n; - if (!savealpha && dn > 1) - dn--; - - switch (dn) - { - default: - case 1: color = 0; break; - case 2: color = 4; break; - case 3: color = 2; break; - case 4: color = 6; break; - } - - usize = (pixmap->w * dn + 1) * pixmap->h; - csize = compressBound(usize); - fz_try(ctx) - { - udata = fz_malloc(ctx, usize); - cdata = fz_malloc(ctx, csize); - } - fz_catch(ctx) - { - fz_free(ctx, udata); - fz_rethrow(ctx); - } - - sp = pixmap->samples; - dp = udata; - for (y = 0; y < pixmap->h; y++) - { - *dp++ = 1; /* sub prediction filter */ - for (x = 0; x < pixmap->w; x++) - { - for (k = 0; k < dn; k++) - { - if (x == 0) - dp[k] = sp[k]; - else - dp[k] = sp[k] - sp[k-sn]; - } - sp += sn; - dp += dn; - } - } - - err = compress(cdata, &csize, udata, usize); - if (err != Z_OK) - { - fz_free(ctx, udata); - fz_free(ctx, cdata); - fz_throw(ctx, FZ_ERROR_GENERIC, "cannot compress image data"); - } - - big32(head+0, pixmap->w); - big32(head+4, pixmap->h); - head[8] = 8; /* depth */ - head[9] = color; - head[10] = 0; /* compression */ - head[11] = 0; /* filter */ - head[12] = 0; /* interlace */ - - fz_write(out, pngsig, 8); - putchunk("IHDR", head, 13, out); - putchunk("IDAT", cdata, csize, out); - putchunk("IEND", head, 0, out); - - fz_free(ctx, udata); - fz_free(ctx, cdata); -} - -fz_buffer * -fz_image_as_png(fz_context *ctx, fz_image *image, int w, int h) -{ - fz_pixmap *pix = fz_image_get_pixmap(ctx, image, image->w, image->h); - fz_buffer *buf = NULL; - fz_output *out; - - fz_var(buf); - fz_var(out); - - fz_try(ctx) - { - if (pix->colorspace != fz_device_gray(ctx) || pix->colorspace != fz_device_rgb(ctx)) - { - fz_pixmap *pix2 = fz_new_pixmap(ctx, fz_device_rgb(ctx), pix->w, pix->h); - fz_convert_pixmap(ctx, pix2, pix); - fz_drop_pixmap(ctx, pix); - pix = pix2; - } - buf = fz_new_buffer(ctx, 1024); - out = fz_new_output_with_buffer(ctx, buf); - fz_output_png(out, pix, 0); - } - fz_always(ctx) - { - fz_close_output(out); - fz_drop_pixmap(ctx, pix); - } - fz_catch(ctx) - { - fz_drop_buffer(ctx, buf); - fz_rethrow(ctx); - } - return buf; -} - -unsigned int -fz_pixmap_size(fz_context *ctx, fz_pixmap * pix) -{ - if (pix == NULL) - return 0; - return sizeof(*pix) + pix->n * pix->w * pix->h; -} - -#ifdef ARCH_ARM -static void -fz_subsample_pixmap_ARM(unsigned char *ptr, int w, int h, int f, int factor, - int n, int fwd, int back, int back2, int fwd2, - int divX, int back4, int fwd4, int fwd3, - int divY, int back5, int divXY) -__attribute__((naked)); - -static void -fz_subsample_pixmap_ARM(unsigned char *ptr, int w, int h, int f, int factor, - int n, int fwd, int back, int back2, int fwd2, - int divX, int back4, int fwd4, int fwd3, - int divY, int back5, int divXY) -{ - asm volatile( - ENTER_ARM - "stmfd r13!,{r1,r4-r11,r14} \n" - "@STACK:r1,<9>,factor,n,fwd,back,back2,fwd2,divX,back4,fwd4,fwd3,divY,back5,divXY\n" - "@ r0 = src = ptr \n" - "@ r1 = w \n" - "@ r2 = h \n" - "@ r3 = f \n" - "mov r9, r0 @ r9 = dst = ptr \n" - "ldr r6, [r13,#4*12] @ r6 = fwd \n" - "ldr r7, [r13,#4*13] @ r7 = back \n" - "subs r2, r2, r3 @ r2 = h -= f \n" - "blt 11f @ Skip if less than a full row \n" - "1: @ for (y = h; y > 0; y--) { \n" - "ldr r1, [r13] @ r1 = w \n" - "subs r1, r1, r3 @ r1 = w -= f \n" - "blt 6f @ Skip if less than a full col \n" - "ldr r4, [r13,#4*10] @ r4 = factor \n" - "ldr r8, [r13,#4*14] @ r8 = back2 \n" - "ldr r12,[r13,#4*15] @ r12= fwd2 \n" - "2: @ for (x = w; x > 0; x--) { \n" - "ldr r5, [r13,#4*11] @ for (nn = n; nn > 0; n--) { \n" - "3: @ \n" - "mov r14,#0 @ r14= v = 0 \n" - "sub r5, r5, r3, LSL #8 @ for (xx = f; xx > 0; x--) { \n" - "4: @ \n" - "add r5, r5, r3, LSL #16 @ for (yy = f; yy > 0; y--) { \n" - "5: @ \n" - "ldrb r11,[r0], r6 @ r11= *src src += fwd \n" - "subs r5, r5, #1<<16 @ xx-- \n" - "add r14,r14,r11 @ v += r11 \n" - "bgt 5b @ } \n" - "sub r0, r0, r7 @ src -= back \n" - "adds r5, r5, #1<<8 @ yy-- \n" - "blt 4b @ } \n" - "mov r14,r14,LSR r4 @ r14 = v >>= factor \n" - "strb r14,[r9], #1 @ *d++ = r14 \n" - "sub r0, r0, r8 @ s -= back2 \n" - "subs r5, r5, #1 @ n-- \n" - "bgt 3b @ } \n" - "add r0, r0, r12 @ s += fwd2 \n" - "subs r1, r1, r3 @ x -= f \n" - "bge 2b @ } \n" - "6: @ Less than a full column left \n" - "adds r1, r1, r3 @ x += f \n" - "beq 11f @ if (x == 0) next row \n" - "@ r0 = src \n" - "@ r1 = x \n" - "@ r2 = y \n" - "@ r3 = f \n" - "@ r4 = factor \n" - "@ r6 = fwd \n" - "@ r7 = back \n" - "@STACK:r1,<9>,factor,n,fwd,back,back2,fwd2,divX,back4,fwd4,fwd3,divY,back5,divXY\n" - "ldr r5, [r13,#4*11] @ for (nn = n; nn > 0; n--) { \n" - "ldr r4, [r13,#4*16] @ r4 = divX \n" - "ldr r8, [r13,#4*17] @ r8 = back4 \n" - "ldr r12,[r13,#4*18] @ r12= fwd4 \n" - "8: @ \n" - "mov r14,#0 @ r14= v = 0 \n" - "sub r5, r5, r1, LSL #8 @ for (xx = x; xx > 0; x--) { \n" - "9: @ \n" - "add r5, r5, r3, LSL #16 @ for (yy = f; yy > 0; y--) { \n" - "10: @ \n" - "ldrb r11,[r0], r6 @ r11= *src src += fwd \n" - "subs r5, r5, #1<<16 @ xx-- \n" - "add r14,r14,r11 @ v += r11 \n" - "bgt 10b @ } \n" - "sub r0, r0, r7 @ src -= back \n" - "adds r5, r5, #1<<8 @ yy-- \n" - "blt 9b @ } \n" - "mul r14,r4, r14 @ r14= v *= divX \n" - "mov r14,r14,LSR #16 @ r14= v >>= 16 \n" - "strb r14,[r9], #1 @ *d++ = r14 \n" - "sub r0, r0, r8 @ s -= back4 \n" - "subs r5, r5, #1 @ n-- \n" - "bgt 8b @ } \n" - "add r0, r0, r12 @ s += fwd4 \n" - "11: @ \n" - "ldr r14,[r13,#4*19] @ r14 = fwd3 \n" - "subs r2, r2, r3 @ h -= f \n" - "add r0, r0, r14 @ s += fwd3 \n" - "bge 1b @ } \n" - "adds r2, r2, r3 @ h += f \n" - "beq 21f @ if no stray row, end \n" - "@ So doing one last (partial) row \n" - "@STACK:r1,<9>,factor,n,fwd,back,back2,fwd2,divX,back4,fwd4,fwd3,divY,back5,divXY\n" - "@ r0 = src = ptr \n" - "@ r1 = w \n" - "@ r2 = h \n" - "@ r3 = f \n" - "@ r4 = factor \n" - "@ r5 = n \n" - "@ r6 = fwd \n" - "12: @ for (y = h; y > 0; y--) { \n" - "ldr r1, [r13] @ r1 = w \n" - "ldr r7, [r13,#4*21] @ r7 = back5 \n" - "ldr r8, [r13,#4*14] @ r8 = back2 \n" - "subs r1, r1, r3 @ r1 = w -= f \n" - "blt 17f @ Skip if less than a full col \n" - "ldr r4, [r13,#4*20] @ r4 = divY \n" - "ldr r12,[r13,#4*15] @ r12= fwd2 \n" - "13: @ for (x = w; x > 0; x--) { \n" - "ldr r5, [r13,#4*11] @ for (nn = n; nn > 0; n--) { \n" - "14: @ \n" - "mov r14,#0 @ r14= v = 0 \n" - "sub r5, r5, r3, LSL #8 @ for (xx = f; xx > 0; x--) { \n" - "15: @ \n" - "add r5, r5, r2, LSL #16 @ for (yy = y; yy > 0; y--) { \n" - "16: @ \n" - "ldrb r11,[r0], r6 @ r11= *src src += fwd \n" - "subs r5, r5, #1<<16 @ xx-- \n" - "add r14,r14,r11 @ v += r11 \n" - "bgt 16b @ } \n" - "sub r0, r0, r7 @ src -= back5 \n" - "adds r5, r5, #1<<8 @ yy-- \n" - "blt 15b @ } \n" - "mul r14,r4, r14 @ r14 = x *= divY \n" - "mov r14,r14,LSR #16 @ r14 = v >>= 16 \n" - "strb r14,[r9], #1 @ *d++ = r14 \n" - "sub r0, r0, r8 @ s -= back2 \n" - "subs r5, r5, #1 @ n-- \n" - "bgt 14b @ } \n" - "add r0, r0, r12 @ s += fwd2 \n" - "subs r1, r1, r3 @ x -= f \n" - "bge 13b @ } \n" - "17: @ Less than a full column left \n" - "adds r1, r1, r3 @ x += f \n" - "beq 21f @ if (x == 0) end \n" - "@ r0 = src \n" - "@ r1 = x \n" - "@ r2 = y \n" - "@ r3 = f \n" - "@ r4 = factor \n" - "@ r6 = fwd \n" - "@ r7 = back5 \n" - "@ r8 = back2 \n" - "@STACK:r1,<9>,factor,n,fwd,back,back2,fwd2,divX,back4,fwd4,fwd3,divY,back5,divXY\n" - "ldr r4, [r13,#4*22] @ r4 = divXY \n" - "ldr r5, [r13,#4*11] @ for (nn = n; nn > 0; n--) { \n" - "18: @ \n" - "mov r14,#0 @ r14= v = 0 \n" - "sub r5, r5, r1, LSL #8 @ for (xx = x; xx > 0; x--) { \n" - "19: @ \n" - "add r5, r5, r2, LSL #16 @ for (yy = y; yy > 0; y--) { \n" - "20: @ \n" - "ldrb r11,[r0],r6 @ r11= *src src += fwd \n" - "subs r5, r5, #1<<16 @ xx-- \n" - "add r14,r14,r11 @ v += r11 \n" - "bgt 20b @ } \n" - "sub r0, r0, r7 @ src -= back5 \n" - "adds r5, r5, #1<<8 @ yy-- \n" - "blt 19b @ } \n" - "mul r14,r4, r14 @ r14= v *= divX \n" - "mov r14,r14,LSR #16 @ r14= v >>= 16 \n" - "strb r14,[r9], #1 @ *d++ = r14 \n" - "sub r0, r0, r8 @ s -= back2 \n" - "subs r5, r5, #1 @ n-- \n" - "bgt 18b @ } \n" - "21: @ \n" - "ldmfd r13!,{r1,r4-r11,PC} @ pop, return to thumb \n" - ENTER_THUMB - ); -} - -#endif - -void -fz_subsample_pixmap(fz_context *ctx, fz_pixmap *tile, int factor) -{ - int dst_w, dst_h, w, h, fwd, fwd2, fwd3, back, back2, x, y, n, xx, yy, nn, f; - unsigned char *s, *d; - - if (!tile) - return; - s = d = tile->samples; - f = 1<w; - h = tile->h; - n = tile->n; - dst_w = (w + f-1)>>factor; - dst_h = (h + f-1)>>factor; - fwd = w*n; - back = f*fwd-n; - back2 = f*n-1; - fwd2 = (f-1)*n; - fwd3 = (f-1)*fwd; - factor *= 2; -#ifdef ARCH_ARM - { - int strayX = w%f; - int divX = (strayX ? 65536/(strayX*f) : 0); - int fwd4 = (strayX-1) * n; - int back4 = strayX*n-1; - int strayY = h%f; - int divY = (strayY ? 65536/(strayY*f) : 0); - int back5 = fwd * strayY - n; - int divXY = (strayY*strayX ? 65536/(strayX*strayY) : 0); - fz_subsample_pixmap_ARM(s, w, h, f, factor, n, fwd, back, - back2, fwd2, divX, back4, fwd4, fwd3, - divY, back5, divXY); - } -#else - for (y = h - f; y >= 0; y -= f) - { - for (x = w - f; x >= 0; x -= f) - { - for (nn = n; nn > 0; nn--) - { - int v = 0; - for (xx = f; xx > 0; xx--) - { - for (yy = f; yy > 0; yy--) - { - v += *s; - s += fwd; - } - s -= back; - } - *d++ = v >> factor; - s -= back2; - } - s += fwd2; - } - /* Do any strays */ - x += f; - if (x > 0) - { - int div = x * f; - int fwd4 = (x-1) * n; - int back4 = x*n-1; - for (nn = n; nn > 0; nn--) - { - int v = 0; - for (xx = x; xx > 0; xx--) - { - for (yy = f; yy > 0; yy--) - { - v += *s; - s += fwd; - } - s -= back; - } - *d++ = v / div; - s -= back4; - } - s += fwd4; - } - s += fwd3; - } - /* Do any stray line */ - y += f; - if (y > 0) - { - int div = y * f; - int back5 = fwd * y - n; - for (x = w - f; x >= 0; x -= f) - { - for (nn = n; nn > 0; nn--) - { - int v = 0; - for (xx = f; xx > 0; xx--) - { - for (yy = y; yy > 0; yy--) - { - v += *s; - s += fwd; - } - s -= back5; - } - *d++ = v / div; - s -= back2; - } - s += fwd2; - } - /* Do any stray at the end of the stray line */ - x += f; - if (x > 0) - { - div = x * y; - for (nn = n; nn > 0; nn--) - { - int v = 0; - for (xx = x; xx > 0; xx--) - { - for (yy = y; yy > 0; yy--) - { - v += *s; - s += fwd; - } - s -= back5; - } - *d++ = v / div; - s -= back2; - } - } - } -#endif - tile->w = dst_w; - tile->h = dst_h; - tile->samples = fz_resize_array(ctx, tile->samples, dst_w * n, dst_h); -} - -void -fz_pixmap_set_resolution(fz_pixmap *pix, int res) -{ - pix->xres = res; - pix->yres = res; -} - -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/res_pwg.c b/fitz/res_pwg.c deleted file mode 100644 index fe1fcd2e..00000000 --- a/fitz/res_pwg.c +++ /dev/null @@ -1,318 +0,0 @@ -#include "mupdf/fitz.h" - -void -fz_output_pwg_file_header(fz_output *out) -{ - static const unsigned char pwgsig[4] = { 'R', 'a', 'S', '2' }; - - /* Sync word */ - fz_write(out, pwgsig, 4); -} - -static void -output_header(fz_output *out, const fz_pwg_options *pwg, int xres, int yres, int w, int h, int bpp) -{ - static const char zero[64] = { 0 }; - int i; - - /* Page Header: */ - fz_write(out, pwg ? pwg->media_class : zero, 64); - fz_write(out, pwg ? pwg->media_color : zero, 64); - fz_write(out, pwg ? pwg->media_type : zero, 64); - fz_write(out, pwg ? pwg->output_type : zero, 64); - fz_write_int32be(out, pwg ? pwg->advance_distance : 0); - fz_write_int32be(out, pwg ? pwg->advance_media : 0); - fz_write_int32be(out, pwg ? pwg->collate : 0); - fz_write_int32be(out, pwg ? pwg->cut_media : 0); - fz_write_int32be(out, pwg ? pwg->duplex : 0); - fz_write_int32be(out, xres); - fz_write_int32be(out, yres); - /* CUPS format says that 284->300 are supposed to be the bbox of the - * page in points. PWG says 'Reserved'. */ - for (i=284; i < 300; i += 4) - fz_write(out, zero, 4); - fz_write_int32be(out, pwg ? pwg->insert_sheet : 0); - fz_write_int32be(out, pwg ? pwg->jog : 0); - fz_write_int32be(out, pwg ? pwg->leading_edge : 0); - /* CUPS format says that 312->320 are supposed to be the margins of - * the lower left hand edge of page in points. PWG says 'Reserved'. */ - for (i=312; i < 320; i += 4) - fz_write(out, zero, 4); - fz_write_int32be(out, pwg ? pwg->manual_feed : 0); - fz_write_int32be(out, pwg ? pwg->media_position : 0); - fz_write_int32be(out, pwg ? pwg->media_weight : 0); - fz_write_int32be(out, pwg ? pwg->mirror_print : 0); - fz_write_int32be(out, pwg ? pwg->negative_print : 0); - fz_write_int32be(out, pwg ? pwg->num_copies : 0); - fz_write_int32be(out, pwg ? pwg->orientation : 0); - fz_write_int32be(out, pwg ? pwg->output_face_up : 0); - fz_write_int32be(out, w * 72/ xres); /* Page size in points */ - fz_write_int32be(out, h * 72/ yres); - fz_write_int32be(out, pwg ? pwg->separations : 0); - fz_write_int32be(out, pwg ? pwg->tray_switch : 0); - fz_write_int32be(out, pwg ? pwg->tumble : 0); - fz_write_int32be(out, w); /* Page image in pixels */ - fz_write_int32be(out, h); - fz_write_int32be(out, pwg ? pwg->media_type_num : 0); - fz_write_int32be(out, bpp < 8 ? 1 : 8); /* Bits per color */ - fz_write_int32be(out, bpp); /* Bits per pixel */ - fz_write_int32be(out, (w * bpp + 7)/8); /* Bytes per line */ - fz_write_int32be(out, 0); /* Chunky pixels */ - fz_write_int32be(out, bpp == 1 ? 3 /* Black */ : (bpp == 8 ? 18 /* Sgray */ : 19 /* Srgb */)); /* Colorspace */ - fz_write_int32be(out, pwg ? pwg->compression : 0); - fz_write_int32be(out, pwg ? pwg->row_count : 0); - fz_write_int32be(out, pwg ? pwg->row_feed : 0); - fz_write_int32be(out, pwg ? pwg->row_step : 0); - fz_write_int32be(out, bpp <= 8 ? 1 : 3); /* Num Colors */ - for (i=424; i < 452; i += 4) - fz_write(out, zero, 4); - fz_write_int32be(out, 1); /* TotalPageCount */ - fz_write_int32be(out, 1); /* CrossFeedTransform */ - fz_write_int32be(out, 1); /* FeedTransform */ - fz_write_int32be(out, 0); /* ImageBoxLeft */ - fz_write_int32be(out, 0); /* ImageBoxTop */ - fz_write_int32be(out, w); /* ImageBoxRight */ - fz_write_int32be(out, h); /* ImageBoxBottom */ - for (i=480; i < 1668; i += 4) - fz_write(out, zero, 4); - fz_write(out, pwg ? pwg->rendering_intent : zero, 64); - fz_write(out, pwg ? pwg->page_size_name : zero, 64); -} - -void -fz_output_pwg_page(fz_output *out, const fz_pixmap *pixmap, const fz_pwg_options *pwg) -{ - unsigned char *sp; - int y, x, sn, dn, ss; - fz_context *ctx; - - if (!out || !pixmap) - return; - - ctx = out->ctx; - - if (pixmap->n != 1 && pixmap->n != 2 && pixmap->n != 4) - fz_throw(ctx, FZ_ERROR_GENERIC, "pixmap must be grayscale or rgb to write as pwg"); - - sn = pixmap->n; - dn = pixmap->n; - if (dn == 2 || dn == 4) - dn--; - - output_header(out, pwg, pixmap->xres, pixmap->yres, pixmap->w, pixmap->h, dn*8); - - /* Now output the actual bitmap, using a packbits like compression */ - sp = pixmap->samples; - ss = pixmap->w * sn; - y = 0; - while (y < pixmap->h) - { - int yrep; - - assert(sp == pixmap->samples + y * ss); - - /* Count the number of times this line is repeated */ - for (yrep = 1; yrep < 256 && y+yrep < pixmap->h; yrep++) - { - if (memcmp(sp, sp + yrep * ss, ss) != 0) - break; - } - fz_write_byte(out, yrep-1); - - /* Encode the line */ - x = 0; - while (x < pixmap->w) - { - int d; - - assert(sp == pixmap->samples + y * ss + x * sn); - - /* How far do we have to look to find a repeated value? */ - for (d = 1; d < 128 && x+d < pixmap->w; d++) - { - if (memcmp(sp + (d-1)*sn, sp + d*sn, sn) == 0) - break; - } - if (d == 1) - { - int xrep; - - /* We immediately have a repeat (or we've hit - * the end of the line). Count the number of - * times this value is repeated. */ - for (xrep = 1; xrep < 128 && x+xrep < pixmap->w; xrep++) - { - if (memcmp(sp, sp + xrep*sn, sn) != 0) - break; - } - fz_write_byte(out, xrep-1); - fz_write(out, sp, dn); - sp += sn*xrep; - x += xrep; - } - else - { - fz_write_byte(out, 257-d); - x += d; - while (d > 0) - { - fz_write(out, sp, dn); - sp += sn; - d--; - } - } - } - - /* Move to the next line */ - sp += ss*(yrep-1); - y += yrep; - } -} - -void -fz_output_pwg_bitmap_page(fz_output *out, const fz_bitmap *bitmap, const fz_pwg_options *pwg) -{ - unsigned char *sp; - int y, x, ss; - int byte_width; - - if (!out || !bitmap) - return; - - output_header(out, pwg, bitmap->xres, bitmap->yres, bitmap->w, bitmap->h, 1); - - /* Now output the actual bitmap, using a packbits like compression */ - sp = bitmap->samples; - ss = bitmap->stride; - byte_width = (bitmap->w+7)/8; - y = 0; - while (y < bitmap->h) - { - int yrep; - - assert(sp == bitmap->samples + y * ss); - - /* Count the number of times this line is repeated */ - for (yrep = 1; yrep < 256 && y+yrep < bitmap->h; yrep++) - { - if (memcmp(sp, sp + yrep * ss, byte_width) != 0) - break; - } - fz_write_byte(out, yrep-1); - - /* Encode the line */ - x = 0; - while (x < byte_width) - { - int d; - - assert(sp == bitmap->samples + y * ss + x); - - /* How far do we have to look to find a repeated value? */ - for (d = 1; d < 128 && x+d < byte_width; d++) - { - if (sp[d-1] == sp[d]) - break; - } - if (d == 1) - { - int xrep; - - /* We immediately have a repeat (or we've hit - * the end of the line). Count the number of - * times this value is repeated. */ - for (xrep = 1; xrep < 128 && x+xrep < byte_width; xrep++) - { - if (sp[0] != sp[xrep]) - break; - } - fz_write_byte(out, xrep-1); - fz_write(out, sp, 1); - sp += xrep; - x += xrep; - } - else - { - fz_write_byte(out, 257-d); - fz_write(out, sp, d); - sp += d; - x += d; - } - } - - /* Move to the next line */ - sp += ss*yrep - byte_width; - y += yrep; - } -} - -void -fz_output_pwg(fz_output *out, const fz_pixmap *pixmap, const fz_pwg_options *pwg) -{ - fz_output_pwg_file_header(out); - fz_output_pwg_page(out, pixmap, pwg); -} - -void -fz_write_pwg(fz_context *ctx, fz_pixmap *pixmap, char *filename, int append, const fz_pwg_options *pwg) -{ - FILE *fp; - fz_output *out = NULL; - - fp = fopen(filename, append ? "ab" : "wb"); - if (!fp) - { - fz_throw(ctx, FZ_ERROR_GENERIC, "cannot open file '%s': %s", filename, strerror(errno)); - } - - fz_var(out); - - fz_try(ctx) - { - out = fz_new_output_with_file(ctx, fp); - if (!append) - fz_output_pwg_file_header(out); - fz_output_pwg_page(out, pixmap, pwg); - } - fz_always(ctx) - { - fz_close_output(out); - fclose(fp); - } - fz_catch(ctx) - { - fz_rethrow(ctx); - } -} - -void -fz_write_pwg_bitmap(fz_context *ctx, fz_bitmap *bitmap, char *filename, int append, const fz_pwg_options *pwg) -{ - FILE *fp; - fz_output *out = NULL; - - fp = fopen(filename, append ? "ab" : "wb"); - if (!fp) - { - fz_throw(ctx, FZ_ERROR_GENERIC, "cannot open file '%s': %s", filename, strerror(errno)); - } - - fz_var(out); - - fz_try(ctx) - { - out = fz_new_output_with_file(ctx, fp); - if (!append) - fz_output_pwg_file_header(out); - fz_output_pwg_bitmap_page(out, bitmap, pwg); - } - fz_always(ctx) - { - fz_close_output(out); - fclose(fp); - } - fz_catch(ctx) - { - fz_rethrow(ctx); - } -} diff --git a/fitz/res_shade.c b/fitz/res_shade.c deleted file mode 100644 index b13dc215..00000000 --- a/fitz/res_shade.c +++ /dev/null @@ -1,1096 +0,0 @@ -#include "mupdf/fitz.h" - -#define SWAP(a,b) {fz_vertex *t = (a); (a) = (b); (b) = t;} - -static void -paint_tri(fz_mesh_processor *painter, fz_vertex *v0, fz_vertex *v1, fz_vertex *v2) -{ - painter->process(painter->process_arg, v0, v1, v2); -} - -static void -paint_quad(fz_mesh_processor *painter, fz_vertex *v0, fz_vertex *v1, fz_vertex *v2, fz_vertex *v3) -{ - /* For a quad with corners (in clockwise or anticlockwise order) are - * v0, v1, v2, v3. We can choose to split in in various different ways. - * Arbitrarily we can pick v0, v1, v3 for the first triangle. We then - * have to choose between v1, v2, v3 or v3, v2, v1 (or their equivalent - * rotations) for the second triangle. - * - * v1, v2, v3 has the property that both triangles share the same - * winding (useful if we were ever doing simple back face culling). - * - * v3, v2, v1 has the property that all the 'shared' edges (both - * within this quad, and with adjacent quads) are walked in the same - * direction every time. This can be useful in that depending on the - * implementation/rounding etc walking from A -> B can hit different - * pixels than walking from B->A. - * - * In the event neither of these things matter at the moment, as all - * the process functions where it matters order the edges from top to - * bottom before walking them. - */ - painter->process(painter->process_arg, v0, v1, v3); - painter->process(painter->process_arg, v3, v2, v1); -} - -static void -fz_process_mesh_type1(fz_context *ctx, fz_shade *shade, const fz_matrix *ctm, fz_mesh_processor *painter) -{ - float *p = shade->u.f.fn_vals; - int xdivs = shade->u.f.xdivs; - int ydivs = shade->u.f.ydivs; - float x0 = shade->u.f.domain[0][0]; - float y0 = shade->u.f.domain[0][1]; - float x1 = shade->u.f.domain[1][0]; - float y1 = shade->u.f.domain[1][1]; - int xx, yy; - float y, yn, x; - fz_vertex vs[2][2]; - fz_vertex *v = vs[0]; - fz_vertex *vn = vs[1]; - int n = shade->colorspace->n; - fz_matrix local_ctm; - - fz_concat(&local_ctm, &shade->u.f.matrix, ctm); - - y = y0; - for (yy = 0; yy < ydivs; yy++) - { - yn = y0 + (y1 - y0) * (yy + 1) / ydivs; - - x = x0; - v[0].p.x = x; v[0].p.y = y; - fz_transform_point(&v[0].p, &local_ctm); - memcpy(v[0].c, p, n*sizeof(float)); - p += n; - v[1].p.x = x; v[1].p.y = yn; - fz_transform_point(&v[1].p, &local_ctm); - memcpy(v[1].c, p + xdivs*n, n*sizeof(float)); - for (xx = 0; xx < xdivs; xx++) - { - x = x0 + (x1 - x0) * (xx + 1) / xdivs; - - vn[0].p.x = x; vn[0].p.y = y; - fz_transform_point(&vn[0].p, &local_ctm); - memcpy(vn[0].c, p, n*sizeof(float)); - p += n; - vn[1].p.x = x; vn[1].p.y = yn; - fz_transform_point(&vn[1].p, &local_ctm); - memcpy(vn[1].c, p + xdivs*n, n*sizeof(float)); - - paint_quad(painter, &v[0], &vn[0], &vn[1], &v[1]); - SWAP(v,vn); - } - y = yn; - } -} - -/* FIXME: Nasty */ -#define HUGENUM 32000 /* how far to extend linear/radial shadings */ - -static fz_point -fz_point_on_circle(fz_point p, float r, float theta) -{ - p.x = p.x + cosf(theta) * r; - p.y = p.y + sinf(theta) * r; - - return p; -} - -static void -fz_process_mesh_type2(fz_context *ctx, fz_shade *shade, const fz_matrix *ctm, fz_mesh_processor *painter) -{ - fz_point p0, p1, dir; - fz_vertex v0, v1, v2, v3; - fz_vertex e0, e1; - float theta; - - p0.x = shade->u.l_or_r.coords[0][0]; - p0.y = shade->u.l_or_r.coords[0][1]; - p1.x = shade->u.l_or_r.coords[1][0]; - p1.y = shade->u.l_or_r.coords[1][1]; - dir.x = p0.y - p1.y; - dir.y = p1.x - p0.x; - fz_transform_point(&p0, ctm); - fz_transform_point(&p1, ctm); - fz_transform_vector(&dir, ctm); - theta = atan2f(dir.y, dir.x); - - v0.p = fz_point_on_circle(p0, HUGENUM, theta); - v1.p = fz_point_on_circle(p1, HUGENUM, theta); - v2.p = fz_point_on_circle(p0, -HUGENUM, theta); - v3.p = fz_point_on_circle(p1, -HUGENUM, theta); - - v0.c[0] = 0; - v1.c[0] = 1; - v2.c[0] = 0; - v3.c[0] = 1; - - paint_quad(painter, &v0, &v2, &v3, &v1); - - if (shade->u.l_or_r.extend[0]) - { - e0.p.x = v0.p.x - (p1.x - p0.x) * HUGENUM; - e0.p.y = v0.p.y - (p1.y - p0.y) * HUGENUM; - - e1.p.x = v2.p.x - (p1.x - p0.x) * HUGENUM; - e1.p.y = v2.p.y - (p1.y - p0.y) * HUGENUM; - - e0.c[0] = 0; - e1.c[0] = 0; - v0.c[0] = 0; - v2.c[0] = 0; - - paint_quad(painter, &e0, &v0, &v2, &e1); - } - - if (shade->u.l_or_r.extend[1]) - { - e0.p.x = v1.p.x + (p1.x - p0.x) * HUGENUM; - e0.p.y = v1.p.y + (p1.y - p0.y) * HUGENUM; - - e1.p.x = v3.p.x + (p1.x - p0.x) * HUGENUM; - e1.p.y = v3.p.y + (p1.y - p0.y) * HUGENUM; - - e0.c[0] = 1; - e1.c[0] = 1; - v1.c[0] = 1; - v3.c[0] = 1; - - paint_quad(painter, &e0, &v1, &v3, &e1); - } -} - -/* FIXME: Nasty */ -#define RADSEGS 32 /* how many segments to generate for radial meshes */ - -static void -fz_paint_annulus(const fz_matrix *ctm, - fz_point p0, float r0, float c0, - fz_point p1, float r1, float c1, - fz_mesh_processor *painter) -{ - fz_vertex t0, t1, t2, t3, b0, b1, b2, b3; - float theta, step; - int i; - - theta = atan2f(p1.y - p0.y, p1.x - p0.x); - step = (float)M_PI * 2 / RADSEGS; - - for (i = 0; i < RADSEGS / 2; i++) - { - t0.p = fz_point_on_circle(p0, r0, theta + i * step); - t1.p = fz_point_on_circle(p0, r0, theta + i * step + step); - t2.p = fz_point_on_circle(p1, r1, theta + i * step); - t3.p = fz_point_on_circle(p1, r1, theta + i * step + step); - b0.p = fz_point_on_circle(p0, r0, theta - i * step); - b1.p = fz_point_on_circle(p0, r0, theta - i * step - step); - b2.p = fz_point_on_circle(p1, r1, theta - i * step); - b3.p = fz_point_on_circle(p1, r1, theta - i * step - step); - - fz_transform_point(&t0.p, ctm); - fz_transform_point(&t1.p, ctm); - fz_transform_point(&t2.p, ctm); - fz_transform_point(&t3.p, ctm); - fz_transform_point(&b0.p, ctm); - fz_transform_point(&b1.p, ctm); - fz_transform_point(&b2.p, ctm); - fz_transform_point(&b3.p, ctm); - - t0.c[0] = c0; - t1.c[0] = c0; - t2.c[0] = c1; - t3.c[0] = c1; - b0.c[0] = c0; - b1.c[0] = c0; - b2.c[0] = c1; - b3.c[0] = c1; - - paint_quad(painter, &t0, &t2, &t3, &t1); - paint_quad(painter, &b0, &b2, &b3, &b1); - } -} - -static void -fz_process_mesh_type3(fz_context *ctx, fz_shade *shade, const fz_matrix *ctm, fz_mesh_processor *painter) -{ - fz_point p0, p1; - float r0, r1; - fz_point e; - float er, rs; - - p0.x = shade->u.l_or_r.coords[0][0]; - p0.y = shade->u.l_or_r.coords[0][1]; - r0 = shade->u.l_or_r.coords[0][2]; - - p1.x = shade->u.l_or_r.coords[1][0]; - p1.y = shade->u.l_or_r.coords[1][1]; - r1 = shade->u.l_or_r.coords[1][2]; - - if (shade->u.l_or_r.extend[0]) - { - if (r0 < r1) - rs = r0 / (r0 - r1); - else - rs = -HUGENUM; - - e.x = p0.x + (p1.x - p0.x) * rs; - e.y = p0.y + (p1.y - p0.y) * rs; - er = r0 + (r1 - r0) * rs; - - fz_paint_annulus(ctm, e, er, 0, p0, r0, 0, painter); - } - - fz_paint_annulus(ctm, p0, r0, 0, p1, r1, 1, painter); - - if (shade->u.l_or_r.extend[1]) - { - if (r0 > r1) - rs = r1 / (r1 - r0); - else - rs = -HUGENUM; - - e.x = p1.x + (p0.x - p1.x) * rs; - e.y = p1.y + (p0.y - p1.y) * rs; - er = r1 + (r0 - r1) * rs; - - fz_paint_annulus(ctm, p1, r1, 1, e, er, 1, painter); - } -} - -static inline float read_sample(fz_stream *stream, int bits, float min, float max) -{ - /* we use pow(2,x) because (1<buffer); - fz_vertex v[4]; - fz_vertex *va = &v[0]; - fz_vertex *vb = &v[1]; - fz_vertex *vc = &v[2]; - fz_vertex *vd = &v[3]; - int flag, i, ncomp = painter->ncomp; - int bpflag = shade->u.m.bpflag; - int bpcoord = shade->u.m.bpcoord; - int bpcomp = shade->u.m.bpcomp; - float x0 = shade->u.m.x0; - float x1 = shade->u.m.x1; - float y0 = shade->u.m.y0; - float y1 = shade->u.m.y1; - float *c0 = shade->u.m.c0; - float *c1 = shade->u.m.c1; - - fz_try(ctx) - { - while (!fz_is_eof_bits(stream)) - { - flag = fz_read_bits(stream, bpflag); - vd->p.x = read_sample(stream, bpcoord, x0, x1); - vd->p.y = read_sample(stream, bpcoord, y0, y1); - fz_transform_point(&vd->p, ctm); - for (i = 0; i < ncomp; i++) - vd->c[i] = read_sample(stream, bpcomp, c0[i], c1[i]); - - switch (flag) - { - case 0: /* start new triangle */ - SWAP(va, vd); - - fz_read_bits(stream, bpflag); - vb->p.x = read_sample(stream, bpcoord, x0, x1); - vb->p.y = read_sample(stream, bpcoord, y0, y1); - fz_transform_point(&vb->p, ctm); - for (i = 0; i < ncomp; i++) - vb->c[i] = read_sample(stream, bpcomp, c0[i], c1[i]); - - fz_read_bits(stream, bpflag); - vc->p.x = read_sample(stream, bpcoord, x0, x1); - vc->p.y = read_sample(stream, bpcoord, y0, y1); - fz_transform_point(&vc->p, ctm); - for (i = 0; i < ncomp; i++) - vc->c[i] = read_sample(stream, bpcomp, c0[i], c1[i]); - - paint_tri(painter, va, vb, vc); - break; - - case 1: /* Vb, Vc, Vd */ - SWAP(va, vb); - SWAP(vb, vc); - SWAP(vc, vd); - paint_tri(painter, va, vb, vc); - break; - - case 2: /* Va, Vc, Vd */ - SWAP(vb, vc); - SWAP(vc, vd); - paint_tri(painter, va, vb, vc); - break; - } - } - } - fz_always(ctx) - { - fz_close(stream); - } - fz_catch(ctx) - { - fz_rethrow(ctx); - } -} - -static void -fz_process_mesh_type5(fz_context *ctx, fz_shade *shade, const fz_matrix *ctm, fz_mesh_processor *painter) -{ - fz_stream *stream = fz_open_compressed_buffer(ctx, shade->buffer); - fz_vertex *buf = NULL; - fz_vertex *ref = NULL; - int first; - int ncomp = painter->ncomp; - int i, k; - int vprow = shade->u.m.vprow; - int bpcoord = shade->u.m.bpcoord; - int bpcomp = shade->u.m.bpcomp; - float x0 = shade->u.m.x0; - float x1 = shade->u.m.x1; - float y0 = shade->u.m.y0; - float y1 = shade->u.m.y1; - float *c0 = shade->u.m.c0; - float *c1 = shade->u.m.c1; - - fz_var(buf); - fz_var(ref); - - fz_try(ctx) - { - ref = fz_malloc_array(ctx, vprow, sizeof(fz_vertex)); - buf = fz_malloc_array(ctx, vprow, sizeof(fz_vertex)); - first = 1; - - while (!fz_is_eof_bits(stream)) - { - for (i = 0; i < vprow; i++) - { - buf[i].p.x = read_sample(stream, bpcoord, x0, x1); - buf[i].p.y = read_sample(stream, bpcoord, y0, y1); - fz_transform_point(&buf[i].p, ctm); - for (k = 0; k < ncomp; k++) - buf[i].c[k] = read_sample(stream, bpcomp, c0[k], c1[k]); - } - - if (!first) - for (i = 0; i < vprow - 1; i++) - paint_quad(painter, &ref[i], &ref[i+1], &buf[i+1], &buf[i]); - - SWAP(ref,buf); - first = 0; - } - } - fz_always(ctx) - { - fz_free(ctx, ref); - fz_free(ctx, buf); - fz_close(stream); - } - fz_catch(ctx) - { - fz_rethrow(ctx); - } -} - -/* Subdivide and tessellate tensor-patches */ - -typedef struct tensor_patch_s tensor_patch; - -struct tensor_patch_s -{ - fz_point pole[4][4]; - float color[4][FZ_MAX_COLORS]; -}; - -static void -triangulate_patch(fz_mesh_processor *painter, tensor_patch p) -{ - fz_vertex v0, v1, v2, v3; - int col_len = painter->ncomp * sizeof(v0.c[0]); - - v0.p = p.pole[0][0]; - memcpy(v0.c, p.color[0], col_len); - - v1.p = p.pole[0][3]; - memcpy(v1.c, p.color[1], col_len); - - v2.p = p.pole[3][3]; - memcpy(v2.c, p.color[2], col_len); - - v3.p = p.pole[3][0]; - memcpy(v3.c, p.color[3], col_len); - - paint_quad(painter, &v0, &v1, &v2, &v3); -} - -static inline void midcolor(float *c, float *c1, float *c2, int n) -{ - int i; - for (i = 0; i < n; i++) - c[i] = (c1[i] + c2[i]) * 0.5f; -} - -static void -split_curve(fz_point *pole, fz_point *q0, fz_point *q1, int polestep) -{ - /* - split bezier curve given by control points pole[0]..pole[3] - using de casteljau algo at midpoint and build two new - bezier curves q0[0]..q0[3] and q1[0]..q1[3]. all indices - should be multiplies by polestep == 1 for vertical bezier - curves in patch and == 4 for horizontal bezier curves due - to C's multi-dimensional matrix memory layout. - */ - - float x12 = (pole[1 * polestep].x + pole[2 * polestep].x) * 0.5f; - float y12 = (pole[1 * polestep].y + pole[2 * polestep].y) * 0.5f; - - q0[1 * polestep].x = (pole[0 * polestep].x + pole[1 * polestep].x) * 0.5f; - q0[1 * polestep].y = (pole[0 * polestep].y + pole[1 * polestep].y) * 0.5f; - q1[2 * polestep].x = (pole[2 * polestep].x + pole[3 * polestep].x) * 0.5f; - q1[2 * polestep].y = (pole[2 * polestep].y + pole[3 * polestep].y) * 0.5f; - - q0[2 * polestep].x = (q0[1 * polestep].x + x12) * 0.5f; - q0[2 * polestep].y = (q0[1 * polestep].y + y12) * 0.5f; - q1[1 * polestep].x = (x12 + q1[2 * polestep].x) * 0.5f; - q1[1 * polestep].y = (y12 + q1[2 * polestep].y) * 0.5f; - - q0[3 * polestep].x = (q0[2 * polestep].x + q1[1 * polestep].x) * 0.5f; - q0[3 * polestep].y = (q0[2 * polestep].y + q1[1 * polestep].y) * 0.5f; - q1[0 * polestep].x = (q0[2 * polestep].x + q1[1 * polestep].x) * 0.5f; - q1[0 * polestep].y = (q0[2 * polestep].y + q1[1 * polestep].y) * 0.5f; - - q0[0 * polestep].x = pole[0 * polestep].x; - q0[0 * polestep].y = pole[0 * polestep].y; - q1[3 * polestep].x = pole[3 * polestep].x; - q1[3 * polestep].y = pole[3 * polestep].y; -} - -static void -split_stripe(tensor_patch *p, tensor_patch *s0, tensor_patch *s1, int n) -{ - /* - split all horizontal bezier curves in patch, - creating two new patches with half the width. - */ - split_curve(&p->pole[0][0], &s0->pole[0][0], &s1->pole[0][0], 4); - split_curve(&p->pole[0][1], &s0->pole[0][1], &s1->pole[0][1], 4); - split_curve(&p->pole[0][2], &s0->pole[0][2], &s1->pole[0][2], 4); - split_curve(&p->pole[0][3], &s0->pole[0][3], &s1->pole[0][3], 4); - - /* interpolate the colors for the two new patches. */ - memcpy(s0->color[0], p->color[0], n * sizeof(s0->color[0][0])); - memcpy(s0->color[1], p->color[1], n * sizeof(s0->color[1][0])); - midcolor(s0->color[2], p->color[1], p->color[2], n); - midcolor(s0->color[3], p->color[0], p->color[3], n); - - memcpy(s1->color[0], s0->color[3], n * sizeof(s1->color[0][0])); - memcpy(s1->color[1], s0->color[2], n * sizeof(s1->color[1][0])); - memcpy(s1->color[2], p->color[2], n * sizeof(s1->color[2][0])); - memcpy(s1->color[3], p->color[3], n * sizeof(s1->color[3][0])); -} - -static void -draw_stripe(fz_mesh_processor *painter, tensor_patch *p, int depth) -{ - tensor_patch s0, s1; - - /* split patch into two half-height patches */ - split_stripe(p, &s0, &s1, painter->ncomp); - - depth--; - if (depth == 0) - { - /* if no more subdividing, draw two new patches... */ - triangulate_patch(painter, s1); - triangulate_patch(painter, s0); - } - else - { - /* ...otherwise, continue subdividing. */ - draw_stripe(painter, &s1, depth); - draw_stripe(painter, &s0, depth); - } -} - -static void -split_patch(tensor_patch *p, tensor_patch *s0, tensor_patch *s1, int n) -{ - /* - split all vertical bezier curves in patch, - creating two new patches with half the height. - */ - split_curve(p->pole[0], s0->pole[0], s1->pole[0], 1); - split_curve(p->pole[1], s0->pole[1], s1->pole[1], 1); - split_curve(p->pole[2], s0->pole[2], s1->pole[2], 1); - split_curve(p->pole[3], s0->pole[3], s1->pole[3], 1); - - /* interpolate the colors for the two new patches. */ - memcpy(s0->color[0], p->color[0], n * sizeof(s0->color[0][0])); - midcolor(s0->color[1], p->color[0], p->color[1], n); - midcolor(s0->color[2], p->color[2], p->color[3], n); - memcpy(s0->color[3], p->color[3], n * sizeof(s0->color[3][0])); - - memcpy(s1->color[0], s0->color[1], n * sizeof(s1->color[0][0])); - memcpy(s1->color[1], p->color[1], n * sizeof(s1->color[1][0])); - memcpy(s1->color[2], p->color[2], n * sizeof(s1->color[2][0])); - memcpy(s1->color[3], s0->color[2], n * sizeof(s1->color[3][0])); -} - -static void -draw_patch(fz_mesh_processor *painter, tensor_patch *p, int depth, int origdepth) -{ - tensor_patch s0, s1; - - /* split patch into two half-width patches */ - split_patch(p, &s0, &s1, painter->ncomp); - - depth--; - if (depth == 0) - { - /* if no more subdividing, draw two new patches... */ - draw_stripe(painter, &s0, origdepth); - draw_stripe(painter, &s1, origdepth); - } - else - { - /* ...otherwise, continue subdividing. */ - draw_patch(painter, &s0, depth, origdepth); - draw_patch(painter, &s1, depth, origdepth); - } -} - -static fz_point -compute_tensor_interior( - fz_point a, fz_point b, fz_point c, fz_point d, - fz_point e, fz_point f, fz_point g, fz_point h) -{ - fz_point pt; - - /* see equations at page 330 in pdf 1.7 */ - - pt.x = -4 * a.x; - pt.x += 6 * (b.x + c.x); - pt.x += -2 * (d.x + e.x); - pt.x += 3 * (f.x + g.x); - pt.x += -1 * h.x; - pt.x /= 9; - - pt.y = -4 * a.y; - pt.y += 6 * (b.y + c.y); - pt.y += -2 * (d.y + e.y); - pt.y += 3 * (f.y + g.y); - pt.y += -1 * h.y; - pt.y /= 9; - - return pt; -} - -static void -make_tensor_patch(tensor_patch *p, int type, fz_point *pt) -{ - if (type == 6) - { - /* see control point stream order at page 325 in pdf 1.7 */ - - p->pole[0][0] = pt[0]; - p->pole[0][1] = pt[1]; - p->pole[0][2] = pt[2]; - p->pole[0][3] = pt[3]; - p->pole[1][3] = pt[4]; - p->pole[2][3] = pt[5]; - p->pole[3][3] = pt[6]; - p->pole[3][2] = pt[7]; - p->pole[3][1] = pt[8]; - p->pole[3][0] = pt[9]; - p->pole[2][0] = pt[10]; - p->pole[1][0] = pt[11]; - - /* see equations at page 330 in pdf 1.7 */ - - p->pole[1][1] = compute_tensor_interior( - p->pole[0][0], p->pole[0][1], p->pole[1][0], p->pole[0][3], - p->pole[3][0], p->pole[3][1], p->pole[1][3], p->pole[3][3]); - - p->pole[1][2] = compute_tensor_interior( - p->pole[0][3], p->pole[0][2], p->pole[1][3], p->pole[0][0], - p->pole[3][3], p->pole[3][2], p->pole[1][0], p->pole[3][0]); - - p->pole[2][1] = compute_tensor_interior( - p->pole[3][0], p->pole[3][1], p->pole[2][0], p->pole[3][3], - p->pole[0][0], p->pole[0][1], p->pole[2][3], p->pole[0][3]); - - p->pole[2][2] = compute_tensor_interior( - p->pole[3][3], p->pole[3][2], p->pole[2][3], p->pole[3][0], - p->pole[0][3], p->pole[0][2], p->pole[2][0], p->pole[0][0]); - } - else if (type == 7) - { - /* see control point stream order at page 330 in pdf 1.7 */ - - p->pole[0][0] = pt[0]; - p->pole[0][1] = pt[1]; - p->pole[0][2] = pt[2]; - p->pole[0][3] = pt[3]; - p->pole[1][3] = pt[4]; - p->pole[2][3] = pt[5]; - p->pole[3][3] = pt[6]; - p->pole[3][2] = pt[7]; - p->pole[3][1] = pt[8]; - p->pole[3][0] = pt[9]; - p->pole[2][0] = pt[10]; - p->pole[1][0] = pt[11]; - p->pole[1][1] = pt[12]; - p->pole[1][2] = pt[13]; - p->pole[2][2] = pt[14]; - p->pole[2][1] = pt[15]; - } -} - -/* FIXME: Nasty */ -#define SUBDIV 3 /* how many levels to subdivide patches */ - -static void -fz_process_mesh_type6(fz_context *ctx, fz_shade *shade, const fz_matrix *ctm, fz_mesh_processor *painter) -{ - fz_stream *stream = fz_open_compressed_buffer(ctx, shade->buffer); - float color_storage[2][4][FZ_MAX_COLORS]; - fz_point point_storage[2][12]; - int store = 0; - int ncomp = painter->ncomp; - int i, k; - int bpflag = shade->u.m.bpflag; - int bpcoord = shade->u.m.bpcoord; - int bpcomp = shade->u.m.bpcomp; - float x0 = shade->u.m.x0; - float x1 = shade->u.m.x1; - float y0 = shade->u.m.y0; - float y1 = shade->u.m.y1; - float *c0 = shade->u.m.c0; - float *c1 = shade->u.m.c1; - - fz_try(ctx) - { - float (*prevc)[FZ_MAX_COLORS] = NULL; - fz_point *prevp = NULL; - while (!fz_is_eof_bits(stream)) - { - float (*c)[FZ_MAX_COLORS] = color_storage[store]; - fz_point *v = point_storage[store]; - int startcolor; - int startpt; - int flag; - tensor_patch patch; - - flag = fz_read_bits(stream, bpflag); - - if (flag == 0) - { - startpt = 0; - startcolor = 0; - } - else - { - startpt = 4; - startcolor = 2; - } - - for (i = startpt; i < 12; i++) - { - v[i].x = read_sample(stream, bpcoord, x0, x1); - v[i].y = read_sample(stream, bpcoord, y0, y1); - fz_transform_point(&v[i], ctm); - } - - for (i = startcolor; i < 4; i++) - { - for (k = 0; k < ncomp; k++) - c[i][k] = read_sample(stream, bpcomp, c0[k], c1[k]); - } - - if (flag == 0) - { - } - else if (flag == 1 && prevc) - { - v[0] = prevp[3]; - v[1] = prevp[4]; - v[2] = prevp[5]; - v[3] = prevp[6]; - memcpy(c[0], prevc[1], ncomp * sizeof(float)); - memcpy(c[1], prevc[2], ncomp * sizeof(float)); - } - else if (flag == 2 && prevc) - { - v[0] = prevp[6]; - v[1] = prevp[7]; - v[2] = prevp[8]; - v[3] = prevp[9]; - memcpy(c[0], prevc[2], ncomp * sizeof(float)); - memcpy(c[1], prevc[3], ncomp * sizeof(float)); - } - else if (flag == 3 && prevc) - { - v[0] = prevp[ 9]; - v[1] = prevp[10]; - v[2] = prevp[11]; - v[3] = prevp[ 0]; - memcpy(c[0], prevc[3], ncomp * sizeof(float)); - memcpy(c[1], prevc[0], ncomp * sizeof(float)); - } - else - continue; - - make_tensor_patch(&patch, 6, v); - - for (i = 0; i < 4; i++) - memcpy(patch.color[i], c[i], ncomp * sizeof(float)); - - draw_patch(painter, &patch, SUBDIV, SUBDIV); - - prevp = v; - prevc = c; - store ^= 1; - } - } - fz_always(ctx) - { - fz_close(stream); - } - fz_catch(ctx) - { - fz_rethrow(ctx); - } -} - -static void -fz_process_mesh_type7(fz_context *ctx, fz_shade *shade, const fz_matrix *ctm, fz_mesh_processor *painter) -{ - fz_stream *stream = fz_open_compressed_buffer(ctx, shade->buffer); - int bpflag = shade->u.m.bpflag; - int bpcoord = shade->u.m.bpcoord; - int bpcomp = shade->u.m.bpcomp; - float x0 = shade->u.m.x0; - float x1 = shade->u.m.x1; - float y0 = shade->u.m.y0; - float y1 = shade->u.m.y1; - float *c0 = shade->u.m.c0; - float *c1 = shade->u.m.c1; - float color_storage[2][4][FZ_MAX_COLORS]; - fz_point point_storage[2][16]; - int store = 0; - int ncomp = painter->ncomp; - int i, k; - float (*prevc)[FZ_MAX_COLORS] = NULL; - fz_point (*prevp) = NULL; - - fz_try(ctx) - { - while (!fz_is_eof_bits(stream)) - { - float (*c)[FZ_MAX_COLORS] = color_storage[store]; - fz_point *v = point_storage[store]; - int startcolor; - int startpt; - int flag; - tensor_patch patch; - - flag = fz_read_bits(stream, bpflag); - - if (flag == 0) - { - startpt = 0; - startcolor = 0; - } - else - { - startpt = 4; - startcolor = 2; - } - - for (i = startpt; i < 16; i++) - { - v[i].x = read_sample(stream, bpcoord, x0, x1); - v[i].y = read_sample(stream, bpcoord, y0, y1); - fz_transform_point(&v[i], ctm); - } - - for (i = startcolor; i < 4; i++) - { - for (k = 0; k < ncomp; k++) - c[i][k] = read_sample(stream, bpcomp, c0[k], c1[k]); - } - - if (flag == 0) - { - } - else if (flag == 1 && prevc) - { - v[0] = prevp[3]; - v[1] = prevp[4]; - v[2] = prevp[5]; - v[3] = prevp[6]; - memcpy(c[0], prevc[1], ncomp * sizeof(float)); - memcpy(c[1], prevc[2], ncomp * sizeof(float)); - } - else if (flag == 2 && prevc) - { - v[0] = prevp[6]; - v[1] = prevp[7]; - v[2] = prevp[8]; - v[3] = prevp[9]; - memcpy(c[0], prevc[2], ncomp * sizeof(float)); - memcpy(c[1], prevc[3], ncomp * sizeof(float)); - } - else if (flag == 3 && prevc) - { - v[0] = prevp[ 9]; - v[1] = prevp[10]; - v[2] = prevp[11]; - v[3] = prevp[ 0]; - memcpy(c[0], prevc[3], ncomp * sizeof(float)); - memcpy(c[1], prevc[0], ncomp * sizeof(float)); - } - else - continue; /* We have no patch! */ - - make_tensor_patch(&patch, 7, v); - - for (i = 0; i < 4; i++) - memcpy(patch.color[i], c[i], ncomp * sizeof(float)); - - draw_patch(painter, &patch, SUBDIV, SUBDIV); - - prevp = v; - prevc = c; - store ^= 1; - } - } - fz_always(ctx) - { - fz_close(stream); - } - fz_catch(ctx) - { - fz_rethrow(ctx); - } -} - -void -fz_process_mesh(fz_context *ctx, fz_shade *shade, const fz_matrix *ctm, - fz_mesh_process_fn *process, void *process_arg) -{ - fz_mesh_processor painter; - - painter.ctx = ctx; - painter.shade = shade; - painter.process = process; - painter.process_arg = process_arg; - painter.ncomp = (shade->use_function > 0 ? 1 : shade->colorspace->n); - - if (shade->type == FZ_FUNCTION_BASED) - fz_process_mesh_type1(ctx, shade, ctm, &painter); - else if (shade->type == FZ_LINEAR) - fz_process_mesh_type2(ctx, shade, ctm, &painter); - else if (shade->type == FZ_RADIAL) - fz_process_mesh_type3(ctx, shade, ctm, &painter); - else if (shade->type == FZ_MESH_TYPE4) - fz_process_mesh_type4(ctx, shade, ctm, &painter); - else if (shade->type == FZ_MESH_TYPE5) - fz_process_mesh_type5(ctx, shade, ctm, &painter); - else if (shade->type == FZ_MESH_TYPE6) - fz_process_mesh_type6(ctx, shade, ctm, &painter); - else if (shade->type == FZ_MESH_TYPE7) - fz_process_mesh_type7(ctx, shade, ctm, &painter); - else - fz_throw(ctx, FZ_ERROR_GENERIC, "Unexpected mesh type %d\n", shade->type); -} - -static fz_rect * -fz_bound_mesh_type1(fz_context *ctx, fz_shade *shade, fz_rect *bbox) -{ - bbox->x0 = shade->u.f.domain[0][0]; - bbox->y0 = shade->u.f.domain[0][1]; - bbox->x1 = shade->u.f.domain[1][0]; - bbox->y1 = shade->u.f.domain[1][1]; - return fz_transform_rect(bbox, &shade->u.f.matrix); -} - -static fz_rect * -fz_bound_mesh_type2(fz_context *ctx, fz_shade *shade, fz_rect *bbox) -{ - /* FIXME: If axis aligned and not extended, the bbox may only be - * infinite in one direction */ - *bbox = fz_infinite_rect; - return bbox; -} - -static fz_rect * -fz_bound_mesh_type3(fz_context *ctx, fz_shade *shade, fz_rect *bbox) -{ - fz_point p0, p1; - float r0, r1; - - r0 = shade->u.l_or_r.coords[0][2]; - r1 = shade->u.l_or_r.coords[1][2]; - - if (shade->u.l_or_r.extend[0]) - { - if (r0 >= r1) - { - *bbox = fz_infinite_rect; - return bbox; - } - } - - if (shade->u.l_or_r.extend[1]) - { - if (r0 <= r1) - { - *bbox = fz_infinite_rect; - return bbox; - } - } - - p0.x = shade->u.l_or_r.coords[0][0]; - p0.y = shade->u.l_or_r.coords[0][1]; - p1.x = shade->u.l_or_r.coords[1][0]; - p1.y = shade->u.l_or_r.coords[1][1]; - - bbox->x0 = p0.x - r0; bbox->y0 = p0.y - r0; - bbox->x1 = p0.x + r0; bbox->y1 = p0.x + r0; - if (bbox->x0 > p1.x - r1) - bbox->x0 = p1.x - r1; - if (bbox->x1 < p1.x + r1) - bbox->x1 = p1.x + r1; - if (bbox->y0 > p1.y - r1) - bbox->y0 = p1.y - r1; - if (bbox->y1 < p1.y + r1) - bbox->y1 = p1.y + r1; - return bbox; -} - -static fz_rect * -fz_bound_mesh_type4567(fz_context *ctx, fz_shade *shade, fz_rect *bbox) -{ - bbox->x0 = shade->u.m.x0; - bbox->y0 = shade->u.m.y0; - bbox->x1 = shade->u.m.x1; - bbox->y1 = shade->u.m.y1; - return bbox; -} - -static fz_rect * -fz_bound_mesh(fz_context *ctx, fz_shade *shade, fz_rect *bbox) -{ - if (shade->type == FZ_FUNCTION_BASED) - fz_bound_mesh_type1(ctx, shade, bbox); - else if (shade->type == FZ_LINEAR) - fz_bound_mesh_type2(ctx, shade, bbox); - else if (shade->type == FZ_RADIAL) - fz_bound_mesh_type3(ctx, shade, bbox); - else if (shade->type == FZ_MESH_TYPE4 || - shade->type == FZ_MESH_TYPE5 || - shade->type == FZ_MESH_TYPE6 || - shade->type == FZ_MESH_TYPE7) - fz_bound_mesh_type4567(ctx, shade, bbox); - else - fz_throw(ctx, FZ_ERROR_GENERIC, "Unexpected mesh type %d\n", shade->type); - - return bbox; -} - -fz_shade * -fz_keep_shade(fz_context *ctx, fz_shade *shade) -{ - return (fz_shade *)fz_keep_storable(ctx, &shade->storable); -} - -void -fz_free_shade_imp(fz_context *ctx, fz_storable *shade_) -{ - fz_shade *shade = (fz_shade *)shade_; - - if (shade->colorspace) - fz_drop_colorspace(ctx, shade->colorspace); - if (shade->type == FZ_FUNCTION_BASED) - fz_free(ctx, shade->u.f.fn_vals); - fz_free_compressed_buffer(ctx, shade->buffer); - fz_free(ctx, shade); -} - -void -fz_drop_shade(fz_context *ctx, fz_shade *shade) -{ - fz_drop_storable(ctx, &shade->storable); -} - -fz_rect * -fz_bound_shade(fz_context *ctx, fz_shade *shade, const fz_matrix *ctm, fz_rect *s) -{ - fz_matrix local_ctm; - fz_rect rect; - - fz_concat(&local_ctm, &shade->matrix, ctm); - *s = shade->bbox; - if (shade->type != FZ_LINEAR && shade->type != FZ_RADIAL) - { - fz_bound_mesh(ctx, shade, &rect); - fz_intersect_rect(s, &rect); - } - return fz_transform_rect(s, &local_ctm); -} - -#ifndef NDEBUG -void -fz_print_shade(fz_context *ctx, FILE *out, fz_shade *shade) -{ - int i; - - fprintf(out, "shading {\n"); - - switch (shade->type) - { - case FZ_FUNCTION_BASED: fprintf(out, "\ttype function_based\n"); break; - case FZ_LINEAR: fprintf(out, "\ttype linear\n"); break; - case FZ_RADIAL: fprintf(out, "\ttype radial\n"); break; - default: /* MESH */ fprintf(out, "\ttype mesh\n"); break; - } - - fprintf(out, "\tbbox [%g %g %g %g]\n", - shade->bbox.x0, shade->bbox.y0, - shade->bbox.x1, shade->bbox.y1); - - fprintf(out, "\tcolorspace %s\n", shade->colorspace->name); - - 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) - { - fprintf(out, "\tbackground ["); - for (i = 0; i < shade->colorspace->n; i++) - fprintf(out, "%s%g", i == 0 ? "" : " ", shade->background[i]); - fprintf(out, "]\n"); - } - - if (shade->use_function) - { - fprintf(out, "\tfunction\n"); - } - - fprintf(out, "}\n"); -} -#endif diff --git a/fitz/res_store.c b/fitz/res_store.c deleted file mode 100644 index 609f10dc..00000000 --- a/fitz/res_store.c +++ /dev/null @@ -1,638 +0,0 @@ -#include "mupdf/fitz.h" - -typedef struct fz_item_s fz_item; - -struct fz_item_s -{ - void *key; - fz_storable *val; - unsigned int size; - fz_item *next; - fz_item *prev; - fz_store *store; - fz_store_type *type; -}; - -struct fz_store_s -{ - int refs; - - /* Every item in the store is kept in a doubly linked list, ordered - * by usage (so LRU entries are at the end). */ - fz_item *head; - fz_item *tail; - - /* We have a hash table that allows to quickly find a subset of the - * entries (those whose keys are indirect objects). */ - fz_hash_table *hash; - - /* We keep track of the size of the store, and keep it below max. */ - unsigned int max; - unsigned int size; -}; - -void -fz_new_store_context(fz_context *ctx, unsigned int max) -{ - fz_store *store; - store = fz_malloc_struct(ctx, fz_store); - fz_try(ctx) - { - store->hash = fz_new_hash_table(ctx, 4096, sizeof(fz_store_hash), FZ_LOCK_ALLOC); - } - fz_catch(ctx) - { - fz_free(ctx, store); - fz_rethrow(ctx); - } - store->refs = 1; - store->head = NULL; - store->tail = NULL; - store->size = 0; - store->max = max; - ctx->store = store; -} - -void * -fz_keep_storable(fz_context *ctx, fz_storable *s) -{ - if (s == NULL) - return NULL; - fz_lock(ctx, FZ_LOCK_ALLOC); - if (s->refs > 0) - s->refs++; - fz_unlock(ctx, FZ_LOCK_ALLOC); - return s; -} - -void -fz_drop_storable(fz_context *ctx, fz_storable *s) -{ - int do_free = 0; - - if (s == NULL) - return; - fz_lock(ctx, FZ_LOCK_ALLOC); - if (s->refs < 0) - { - /* It's a static object. Dropping does nothing. */ - } - else if (--s->refs == 0) - { - /* If we are dropping the last reference to an object, then - * it cannot possibly be in the store (as the store always - * keeps a ref to everything in it, and doesn't drop via - * this method. So we can simply drop the storable object - * itself without any operations on the fz_store. */ - do_free = 1; - } - fz_unlock(ctx, FZ_LOCK_ALLOC); - if (do_free) - s->free(ctx, s); -} - -static void -evict(fz_context *ctx, fz_item *item) -{ - fz_store *store = ctx->store; - int drop; - - store->size -= item->size; - /* Unlink from the linked list */ - if (item->next) - item->next->prev = item->prev; - else - store->tail = item->prev; - if (item->prev) - item->prev->next = item->next; - else - store->head = item->next; - /* Drop a reference to the value (freeing if required) */ - drop = (item->val->refs > 0 && --item->val->refs == 0); - /* Remove from the hash table */ - if (item->type->make_hash_key) - { - 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 */ - item->type->drop_key(ctx, item->key); - fz_free(ctx, item); - fz_lock(ctx, FZ_LOCK_ALLOC); -} - -static int -ensure_space(fz_context *ctx, unsigned int tofree) -{ - fz_item *item, *prev; - unsigned int count; - fz_store *store = ctx->store; - - fz_assert_lock_held(ctx, FZ_LOCK_ALLOC); - - /* First check that we *can* free tofree; if not, we'd rather not - * cache this. */ - count = 0; - for (item = store->tail; item; item = item->prev) - { - if (item->val->refs == 1) - { - count += item->size; - if (count >= tofree) - break; - } - } - - /* If we ran out of items to search, then we can never free enough */ - if (item == NULL) - { - return 0; - } - - /* Actually free the items */ - count = 0; - for (item = store->tail; item; item = prev) - { - prev = item->prev; - if (item->val->refs == 1) - { - /* Free this item. Evict has to drop the lock to - * manage that, which could cause prev to be removed - * in the meantime. To avoid that we bump its reference - * count here. This may cause another simultaneous - * evict process to fail to make enough space as prev is - * pinned - but that will only happen if we're near to - * the limit anyway, and it will only cause something to - * not be cached. */ - count += item->size; - if (prev) - prev->val->refs++; - evict(ctx, item); /* Drops then retakes lock */ - /* So the store has 1 reference to prev, as do we, so - * no other evict process can have thrown prev away in - * the meantime. So we are safe to just decrement its - * reference count here. */ - if (prev) - --prev->val->refs; - - if (count >= tofree) - return count; - } - } - - return count; -} - -static void -touch(fz_store *store, fz_item *item) -{ - if (item->next != item) - { - /* Already in the list - unlink it */ - if (item->next) - item->next->prev = item->prev; - else - store->tail = item->prev; - if (item->prev) - item->prev->next = item->next; - else - store->head = item->next; - } - /* Now relink it at the start of the LRU chain */ - item->next = store->head; - if (item->next) - item->next->prev = item; - else - store->tail = item; - store->head = item; - item->prev = NULL; -} - -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; - fz_store_hash hash = { NULL }; - int use_hash = 0; - unsigned pos; - - if (!store) - return NULL; - - fz_var(item); - - if (store->max != FZ_STORE_UNLIMITED && store->max < itemsize) - { - /* Our item would take up more room than we can ever - * possibly have in the store. Just give up now. */ - return NULL; - } - - /* 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. */ - fz_try(ctx) - { - item = fz_malloc_struct(ctx, fz_item); - } - fz_catch(ctx) - { - 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); - - /* Fill out the item. To start with, we always set item->next == item - * and item->prev == item. This is so that we can spot items that have - * been put into the hash table without having made it into the linked - * list yet. */ - item->key = key; - item->val = val; - item->size = itemsize; - item->next = item; - item->prev = item; - item->type = type; - - /* If we can index it fast, put it into the hash table. This serves - * to check whether we have one there already. */ - if (use_hash) - { - fz_item *existing; - - fz_try(ctx) - { - /* May drop and retake the lock */ - existing = fz_hash_insert_with_pos(ctx, store->hash, &hash, item, &pos); - } - fz_catch(ctx) - { - /* Any error here means that item never made it into the - * hash - so no one else can have a reference. */ - fz_unlock(ctx, FZ_LOCK_ALLOC); - fz_free(ctx, item); - type->drop_key(ctx, key); - return NULL; - } - if (existing) - { - /* There was one there already! Take a new reference - * to the existing one, and drop our current one. */ - touch(store, existing); - if (existing->val->refs > 0) - existing->val->refs++; - fz_unlock(ctx, FZ_LOCK_ALLOC); - fz_free(ctx, item); - type->drop_key(ctx, key); - return existing->val; - } - } - /* Now bump the ref */ - if (val->refs > 0) - val->refs++; - /* If we haven't got an infinite store, check for space within it */ - if (store->max != FZ_STORE_UNLIMITED) - { - size = store->size + itemsize; - while (size > store->max) - { - /* ensure_space may drop, then retake the lock */ - int saved = ensure_space(ctx, size - store->max); - if (saved == 0) - { - /* Failed to free any space. */ - /* If we are using the hash table, then we've already - * inserted item - remove it. */ - if (use_hash) - { - /* If someone else has already picked up a reference - * to item, then we cannot remove it. Leave it in the - * store, and we'll live with being over budget. We - * know this is the case, if it's in the linked list. */ - if (item->next != item) - break; - fz_hash_remove_fast(ctx, store->hash, &hash, pos); - } - fz_unlock(ctx, FZ_LOCK_ALLOC); - fz_free(ctx, item); - type->drop_key(ctx, key); - if (val->refs > 0) - val->refs--; - return NULL; - } - size -= saved; - } - } - store->size += itemsize; - - /* Regardless of whether it's indexed, it goes into the linked list */ - touch(store, item); - fz_unlock(ctx, FZ_LOCK_ALLOC); - - return NULL; -} - -void * -fz_find_item(fz_context *ctx, fz_store_free_fn *free, void *key, fz_store_type *type) -{ - fz_item *item; - fz_store *store = ctx->store; - fz_store_hash hash = { NULL }; - int use_hash = 0; - - if (!store) - return NULL; - - if (!key) - return NULL; - - if (type->make_hash_key) - { - hash.free = free; - use_hash = type->make_hash_key(&hash, key); - } - - fz_lock(ctx, FZ_LOCK_ALLOC); - if (use_hash) - { - /* We can find objects keyed on indirected objects quickly */ - 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 && !type->cmp_key(item->key, key)) - break; - } - } - if (item) - { - /* LRU the block. This also serves to ensure that any item - * picked up from the hash before it has made it into the - * linked list does not get whipped out again due to the - * store being full. */ - touch(store, item); - /* And bump the refcount before returning */ - if (item->val->refs > 0) - item->val->refs++; - fz_unlock(ctx, FZ_LOCK_ALLOC); - return (void *)item->val; - } - fz_unlock(ctx, FZ_LOCK_ALLOC); - - return NULL; -} - -void -fz_remove_item(fz_context *ctx, fz_store_free_fn *free, void *key, fz_store_type *type) -{ - fz_item *item; - fz_store *store = ctx->store; - int drop; - fz_store_hash hash = { NULL }; - int use_hash = 0; - - if (type->make_hash_key) - { - hash.free = free; - use_hash = type->make_hash_key(&hash, key); - } - - fz_lock(ctx, FZ_LOCK_ALLOC); - if (use_hash) - { - /* We can find objects keyed on indirect objects quickly */ - item = fz_hash_find(ctx, store->hash, &hash); - if (item) - 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 && !type->cmp_key(item->key, key)) - break; - } - if (item) - { - /* Momentarily things can be in the hash table without being - * in the list. Don't attempt to unlink these. We indicate - * such items by setting item->next == item. */ - if (item->next != item) - { - if (item->next) - item->next->prev = item->prev; - else - store->tail = item->prev; - if (item->prev) - item->prev->next = item->next; - else - store->head = item->next; - } - drop = (item->val->refs > 0 && --item->val->refs == 0); - fz_unlock(ctx, FZ_LOCK_ALLOC); - if (drop) - item->val->free(ctx, item->val); - type->drop_key(ctx, item->key); - fz_free(ctx, item); - } - else - fz_unlock(ctx, FZ_LOCK_ALLOC); -} - -void -fz_empty_store(fz_context *ctx) -{ - fz_store *store = ctx->store; - - if (store == NULL) - return; - - fz_lock(ctx, FZ_LOCK_ALLOC); - /* Run through all the items in the store */ - while (store->head) - { - evict(ctx, store->head); /* Drops then retakes lock */ - } - fz_unlock(ctx, FZ_LOCK_ALLOC); -} - -fz_store * -fz_keep_store_context(fz_context *ctx) -{ - if (ctx == NULL || ctx->store == NULL) - return NULL; - fz_lock(ctx, FZ_LOCK_ALLOC); - ctx->store->refs++; - fz_unlock(ctx, FZ_LOCK_ALLOC); - return ctx->store; -} - -void -fz_drop_store_context(fz_context *ctx) -{ - int refs; - if (ctx == NULL || ctx->store == NULL) - return; - fz_lock(ctx, FZ_LOCK_ALLOC); - refs = --ctx->store->refs; - fz_unlock(ctx, FZ_LOCK_ALLOC); - if (refs != 0) - return; - - fz_empty_store(ctx); - fz_free_hash(ctx, ctx->store->hash); - fz_free(ctx, ctx->store); - ctx->store = NULL; -} - -#ifndef NDEBUG -static void -print_item(FILE *out, void *item_) -{ - fz_item *item = (fz_item *)item_; - fprintf(out, " val=%p item=%p\n", item->val, item); - fflush(out); -} - -void -fz_print_store_locked(fz_context *ctx, FILE *out) -{ - fz_item *item, *next; - fz_store *store = ctx->store; - - fprintf(out, "-- resource store contents --\n"); - fflush(out); - - for (item = store->head; item; item = next) - { - next = item->next; - if (next) - next->val->refs++; - fprintf(out, "store[*][refs=%d][size=%d] ", item->val->refs, item->size); - fz_unlock(ctx, FZ_LOCK_ALLOC); - item->type->debug(out, item->key); - fprintf(out, " = %p\n", item->val); - fflush(out); - fz_lock(ctx, FZ_LOCK_ALLOC); - if (next) - next->val->refs--; - } - fprintf(out, "-- resource store hash contents --\n"); - fz_print_hash_details(ctx, out, store->hash, print_item); - fprintf(out, "-- end --\n"); - fflush(out); -} - -void -fz_print_store(fz_context *ctx, FILE *out) -{ - fz_lock(ctx, FZ_LOCK_ALLOC); - fz_print_store_locked(ctx, out); - fz_unlock(ctx, FZ_LOCK_ALLOC); -} -#endif - -/* This is now an n^2 algorithm - not ideal, but it'll only be bad if we are - * actually managing to scavenge lots of blocks back. */ -static int -scavenge(fz_context *ctx, unsigned int tofree) -{ - fz_store *store = ctx->store; - unsigned int count = 0; - fz_item *item, *prev; - - /* Free the items */ - for (item = store->tail; item; item = prev) - { - prev = item->prev; - if (item->val->refs == 1) - { - /* Free this item */ - count += item->size; - evict(ctx, item); /* Drops then retakes lock */ - - if (count >= tofree) - break; - - /* Have to restart search again, as prev may no longer - * be valid due to release of lock in evict. */ - prev = store->tail; - } - } - /* Success is managing to evict any blocks */ - return count != 0; -} - -int fz_store_scavenge(fz_context *ctx, unsigned int size, int *phase) -{ - fz_store *store; - unsigned int max; - - if (ctx == NULL) - return 0; - store = ctx->store; - if (store == NULL) - return 0; - -#ifdef DEBUG_SCAVENGING - printf("Scavenging: store=%d size=%d phase=%d\n", store->size, size, *phase); - fz_print_store_locked(ctx, stderr); - Memento_stats(); -#endif - do - { - unsigned int tofree; - - /* Calculate 'max' as the maximum size of the store for this phase */ - if (*phase >= 16) - max = 0; - else if (store->max != FZ_STORE_UNLIMITED) - max = store->max / 16 * (16 - *phase); - else - max = store->size / (16 - *phase) * (15 - *phase); - (*phase)++; - - /* Slightly baroque calculations to avoid overflow */ - if (size > UINT_MAX - store->size) - tofree = UINT_MAX - max; - else if (size + store->size > max) - continue; - else - tofree = size + store->size - max; - - if (scavenge(ctx, tofree)) - { -#ifdef DEBUG_SCAVENGING - printf("scavenged: store=%d\n", store->size); - fz_print_store(ctx, stderr); - Memento_stats(); -#endif - return 1; - } - } - while (max > 0); - -#ifdef DEBUG_SCAVENGING - printf("scavenging failed\n"); - fz_print_store(ctx, stderr); - Memento_listBlocks(); -#endif - return 0; -} diff --git a/fitz/res_text.c b/fitz/res_text.c deleted file mode 100644 index 81e2e1d0..00000000 --- a/fitz/res_text.c +++ /dev/null @@ -1,154 +0,0 @@ -#include "mupdf/fitz.h" - -fz_text * -fz_new_text(fz_context *ctx, fz_font *font, const fz_matrix *trm, int wmode) -{ - fz_text *text; - - text = fz_malloc_struct(ctx, fz_text); - text->font = fz_keep_font(ctx, font); - text->trm = *trm; - text->wmode = wmode; - text->len = 0; - text->cap = 0; - text->items = NULL; - - return text; -} - -void -fz_free_text(fz_context *ctx, fz_text *text) -{ - if (text != NULL) - { - fz_drop_font(ctx, text->font); - fz_free(ctx, text->items); - } - fz_free(ctx, text); -} - -fz_text * -fz_clone_text(fz_context *ctx, fz_text *old) -{ - fz_text *text; - - text = fz_malloc_struct(ctx, fz_text); - text->len = old->len; - fz_try(ctx) - { - text->items = fz_malloc_array(ctx, text->len, sizeof(fz_text_item)); - } - fz_catch(ctx) - { - fz_free(ctx, text); - fz_rethrow(ctx); - } - memcpy(text->items, old->items, text->len * sizeof(fz_text_item)); - text->font = fz_keep_font(ctx, old->font); - text->trm = old->trm; - text->wmode = old->wmode; - text->cap = text->len; - - return text; -} - -fz_rect * -fz_bound_text(fz_context *ctx, fz_text *text, const fz_stroke_state *stroke, const fz_matrix *ctm, fz_rect *bbox) -{ - fz_matrix tm, trm; - fz_rect gbox; - int i; - - if (text->len == 0) - { - *bbox = fz_empty_rect; - return bbox; - } - - // TODO: stroke state - - tm = text->trm; - - tm.e = text->items[0].x; - tm.f = text->items[0].y; - fz_concat(&trm, &tm, ctm); - fz_bound_glyph(ctx, text->font, text->items[0].gid, &trm, bbox); - - for (i = 1; i < text->len; i++) - { - if (text->items[i].gid >= 0) - { - tm.e = text->items[i].x; - tm.f = text->items[i].y; - fz_concat(&trm, &tm, ctm); - fz_bound_glyph(ctx, text->font, text->items[i].gid, &trm, &gbox); - - bbox->x0 = fz_min(bbox->x0, gbox.x0); - bbox->y0 = fz_min(bbox->y0, gbox.y0); - bbox->x1 = fz_max(bbox->x1, gbox.x1); - bbox->y1 = fz_max(bbox->y1, gbox.y1); - } - } - - if (stroke) - fz_adjust_rect_for_stroke(bbox, stroke, ctm); - - /* Compensate for the glyph cache limited positioning precision */ - bbox->x0 -= 1; - bbox->y0 -= 1; - bbox->x1 += 1; - bbox->y1 += 1; - - return bbox; -} - -static void -fz_grow_text(fz_context *ctx, fz_text *text, int n) -{ - int new_cap = text->cap; - if (text->len + n < new_cap) - return; - while (text->len + n > new_cap) - new_cap = new_cap + 36; - text->items = fz_resize_array(ctx, text->items, new_cap, sizeof(fz_text_item)); - text->cap = new_cap; -} - -void -fz_add_text(fz_context *ctx, fz_text *text, int gid, int ucs, float x, float y) -{ - fz_grow_text(ctx, text, 1); - text->items[text->len].ucs = ucs; - text->items[text->len].gid = gid; - text->items[text->len].x = x; - text->items[text->len].y = y; - text->len++; -} - -static int -isxmlmeta(int c) -{ - return c < 32 || c >= 128 || c == '&' || c == '<' || c == '>' || c == '\'' || c == '"'; -} - -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++) - fputc(' ', out); - if (!isxmlmeta(text->items[i].ucs)) - fprintf(out, "\n", - text->items[i].ucs, text->items[i].gid, text->items[i].x, text->items[i].y); - else - fprintf(out, "\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 deleted file mode 100644 index 388e0461..00000000 --- a/fitz/stm_buffer.c +++ /dev/null @@ -1,390 +0,0 @@ -#include "mupdf/fitz.h" - -fz_buffer * -fz_new_buffer(fz_context *ctx, int size) -{ - fz_buffer *b; - - size = size > 1 ? size : 16; - - b = fz_malloc_struct(ctx, fz_buffer); - b->refs = 1; - fz_try(ctx) - { - b->data = fz_malloc(ctx, size); - } - fz_catch(ctx) - { - fz_free(ctx, b); - fz_rethrow(ctx); - } - b->cap = size; - b->len = 0; - b->unused_bits = 0; - - return b; -} - -fz_buffer * -fz_new_buffer_from_data(fz_context *ctx, unsigned char *data, int size) -{ - fz_buffer *b; - - b = fz_malloc_struct(ctx, fz_buffer); - b->refs = 1; - b->data = data; - b->cap = size; - b->len = size; - b->unused_bits = 0; - - return b; -} - -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; -} - -void -fz_drop_buffer(fz_context *ctx, fz_buffer *buf) -{ - if (!buf) - return; - if (--buf->refs == 0) - { - fz_free(ctx, buf->data); - fz_free(ctx, buf); - } -} - -void -fz_resize_buffer(fz_context *ctx, fz_buffer *buf, int size) -{ - buf->data = fz_resize_array(ctx, buf->data, size, 1); - buf->cap = size; - if (buf->len > buf->cap) - buf->len = buf->cap; -} - -void -fz_grow_buffer(fz_context *ctx, fz_buffer *buf) -{ - int newsize = (buf->cap * 3) / 2; - if (newsize == 0) - newsize = 256; - fz_resize_buffer(ctx, buf, newsize); -} - -static void -fz_ensure_buffer(fz_context *ctx, fz_buffer *buf, int min) -{ - int newsize = buf->cap; - while (newsize < min) - { - newsize = (newsize * 3) / 2; - } - fz_resize_buffer(ctx, buf, newsize); -} - -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); -} - -void -fz_buffer_cat(fz_context *ctx, fz_buffer *buf, fz_buffer *extra) -{ - if (buf->cap - buf->len < extra->len) - { - buf->data = fz_resize_array(ctx, buf->data, buf->len + extra->len, 1); - buf->cap = buf->len + extra->len; - } - - memcpy(buf->data + buf->len, extra->data, extra->len); - buf->len += extra->len; -} - -void fz_write_buffer(fz_context *ctx, fz_buffer *buf, const void *data, int len) -{ - if (buf->len + len > buf->cap) - fz_ensure_buffer(ctx, buf, buf->len + len); - memcpy(buf->data + buf->len, data, len); - buf->len += len; - buf->unused_bits = 0; -} - -void fz_write_buffer_byte(fz_context *ctx, fz_buffer *buf, int val) -{ - if (buf->len > buf->cap) - fz_grow_buffer(ctx, buf); - buf->data[buf->len++] = val; - buf->unused_bits = 0; -} - -void fz_write_buffer_rune(fz_context *ctx, fz_buffer *buf, int c) -{ - char data[10]; - int len = fz_runetochar(data, c); - if (buf->len + len > buf->cap) - fz_ensure_buffer(ctx, buf, buf->len + len); - memcpy(buf->data + buf->len, data, len); - buf->len += len; - buf->unused_bits = 0; -} - -void fz_write_buffer_bits(fz_context *ctx, fz_buffer *buf, int val, int bits) -{ - int shift; - - /* Throughout this code, the invariant is that we need to write the - * bottom 'bits' bits of 'val' into the stream. On entry we assume - * that val & ((1<len always covers all the bits in the buffer, including - * any unused ones in the last byte, which will always be 0. - * buf->unused_bits = the number of unused bits in the last byte. - */ - - /* Find the amount we need to shift val up by so that it will be in - * the correct position to be inserted into any existing data byte. */ - shift = (buf->unused_bits - bits); - - /* Extend the buffer as required before we start; that way we never - * fail part way during writing. If shift < 0, then we'll need -shift - * more bits. */ - if (shift < 0) - { - int extra = (7-shift)>>3; /* Round up to bytes */ - fz_ensure_buffer(ctx, buf, buf->len + extra); - } - - /* Write any bits that will fit into the existing byte */ - if (buf->unused_bits) - { - buf->data[buf->len-1] |= (shift >= 0 ? (((unsigned int)val)<>-shift)); - if (shift >= 0) - { - /* If we were shifting up, we're done. */ - buf->unused_bits -= bits; - return; - } - /* The number of bits left to write is the number that didn't - * fit in this first byte. */ - bits = -shift; - } - - /* Write any whole bytes */ - while (bits >= 8) - { - bits -= 8; - buf->data[buf->len++] = val>>bits; - } - - /* Write trailing bits (with 0's in unused bits) */ - if (bits > 0) - { - bits = 8-bits; - buf->data[buf->len++] = val<unused_bits = bits; -} - -void fz_write_buffer_pad(fz_context *ctx, fz_buffer *buf) -{ - buf->unused_bits = 0; -} - -int -fz_buffer_printf(fz_context *ctx, fz_buffer *buffer, const char *fmt, ...) -{ - int ret; - va_list args; - va_start(args, fmt); - - ret = fz_buffer_vprintf(ctx, buffer, fmt, args); - - va_end(args); - - return ret; -} - -int -fz_buffer_vprintf(fz_context *ctx, fz_buffer *buffer, const char *fmt, va_list old_args) -{ - int len; - - do - { - int slack = buffer->cap - buffer->len; - - if (slack > 0) - { - va_list args; -#ifdef _MSC_VER /* Microsoft Visual C */ - args = old_args; -#else - va_copy(args, old_args); -#endif - len = vsnprintf((char *)buffer->data + buffer->len, slack, fmt, args); -#ifndef _MSC_VER - va_end(args); -#endif - /* len = number of chars written, not including the terminating - * NULL, so len+1 > slack means "truncated". MSVC differs here - * and returns -1 for truncated. */ - if (len >= 0 && len+1 <= slack) - break; - } - /* Grow the buffer and retry */ - fz_grow_buffer(ctx, buffer); - } - while (1); - - buffer->len += len; - - return len; -} - -void -fz_buffer_cat_pdf_string(fz_context *ctx, fz_buffer *buffer, const char *text) -{ - int len = 2; - const char *s = text; - char *d; - char c; - - while ((c = *s++) != 0) - { - switch (c) - { - case '\n': - case '\r': - case '\t': - case '\b': - case '\f': - case '(': - case ')': - case '\\': - len++; - break; - } - len++; - } - - while(buffer->cap - buffer->len < len) - fz_grow_buffer(ctx, buffer); - - s = text; - d = (char *)buffer->data + buffer->len; - *d++ = '('; - while ((c = *s++) != 0) - { - switch (c) - { - case '\n': - *d++ = '\\'; - *d++ = 'n'; - break; - case '\r': - *d++ = '\\'; - *d++ = 'r'; - break; - case '\t': - *d++ = '\\'; - *d++ = 't'; - break; - case '\b': - *d++ = '\\'; - *d++ = 'b'; - break; - case '\f': - *d++ = '\\'; - *d++ = 'f'; - break; - case '(': - *d++ = '\\'; - *d++ = '('; - break; - case ')': - *d++ = '\\'; - *d++ = ')'; - break; - case '\\': - *d++ = '\\'; - *d++ = '\\'; - break; - default: - *d++ = c; - } - } - *d++ = ')'; - buffer->len += len; -} - -#ifdef TEST_BUFFER_WRITE - -#define TEST_LEN 1024 - -void -fz_test_buffer_write(fz_context *ctx) -{ - fz_buffer *master = fz_new_buffer(ctx, TEST_LEN); - fz_buffer *copy = fz_new_buffer(ctx, TEST_LEN); - fz_stream *stm; - int i, j, k; - - /* Make us a dummy buffer */ - for (i = 0; i < TEST_LEN; i++) - { - master->data[i] = rand(); - } - master->len = TEST_LEN; - - /* Now copy that buffer several times, checking it for validity */ - stm = fz_open_buffer(ctx, master); - for (i = 0; i < 256; i++) - { - memset(copy->data, i, TEST_LEN); - copy->len = 0; - j = TEST_LEN * 8; - do - { - k = (rand() & 31)+1; - if (k > j) - k = j; - fz_write_buffer_bits(ctx, copy, fz_read_bits(stm, k), k); - j -= k; - } - while (j); - - if (memcmp(copy->data, master->data, TEST_LEN) != 0) - fprintf(stderr, "Copied buffer is different!\n"); - fz_seek(stm, 0, 0); - } - fz_close(stm); - fz_drop_buffer(ctx, master); - fz_drop_buffer(ctx, copy); -} -#endif diff --git a/fitz/stm_comp_buf.c b/fitz/stm_comp_buf.c deleted file mode 100644 index acdf2747..00000000 --- a/fitz/stm_comp_buf.c +++ /dev/null @@ -1,75 +0,0 @@ -#include "mupdf/fitz.h" - -/* This code needs to be kept out of stm_buffer.c to avoid it being - * pulled into cmapdump.c */ - -void -fz_free_compressed_buffer(fz_context *ctx, fz_compressed_buffer *buf) -{ - if (!buf) - return; - - fz_drop_buffer(ctx, buf->buffer); - fz_free(ctx, buf); -} - -fz_stream * -fz_open_image_decomp_stream(fz_context *ctx, fz_compressed_buffer *buffer, int *l2factor) -{ - fz_stream *chain = fz_open_buffer(ctx, buffer->buffer); - fz_compression_params *params = &buffer->params; - - switch (params->type) - { - case FZ_IMAGE_FAX: - *l2factor = 0; - return fz_open_faxd(chain, - params->u.fax.k, - params->u.fax.end_of_line, - params->u.fax.encoded_byte_align, - params->u.fax.columns, - params->u.fax.rows, - params->u.fax.end_of_block, - params->u.fax.black_is_1); - case FZ_IMAGE_JPEG: - if (*l2factor > 3) - *l2factor = 3; - return fz_open_resized_dctd(chain, params->u.jpeg.color_transform, *l2factor); - case FZ_IMAGE_RLD: - *l2factor = 0; - return fz_open_rld(chain); - case FZ_IMAGE_FLATE: - *l2factor = 0; - chain = fz_open_flated(chain); - if (params->u.flate.predictor > 1) - chain = fz_open_predict(chain, params->u.flate.predictor, params->u.flate.columns, params->u.flate.colors, params->u.flate.bpc); - return chain; - case FZ_IMAGE_LZW: - *l2factor = 0; - chain = fz_open_lzwd(chain, params->u.lzw.early_change); - if (params->u.lzw.predictor > 1) - chain = fz_open_predict(chain, params->u.lzw.predictor, params->u.lzw.columns, params->u.lzw.colors, params->u.lzw.bpc); - return chain; - default: - *l2factor = 0; - break; - } - - return chain; -} - -fz_stream * -fz_open_compressed_buffer(fz_context *ctx, fz_compressed_buffer *buffer) -{ - int l2factor = 0; - - return fz_open_image_decomp_stream(ctx, buffer, &l2factor); -} - -unsigned int -fz_compressed_buffer_size(fz_compressed_buffer *buffer) -{ - if (!buffer || !buffer->buffer) - return 0; - return (unsigned int)buffer->buffer->cap; -} diff --git a/fitz/stm_open.c b/fitz/stm_open.c deleted file mode 100644 index 9e4dc8d4..00000000 --- a/fitz/stm_open.c +++ /dev/null @@ -1,210 +0,0 @@ -#include "mupdf/fitz.h" - -fz_stream * -fz_new_stream(fz_context *ctx, void *state, - int(*read)(fz_stream *stm, unsigned char *buf, int len), - void(*close)(fz_context *ctx, void *state)) -{ - fz_stream *stm; - - fz_try(ctx) - { - stm = fz_malloc_struct(ctx, fz_stream); - } - fz_catch(ctx) - { - close(ctx, state); - fz_rethrow(ctx); - } - - stm->refs = 1; - stm->error = 0; - stm->eof = 0; - stm->pos = 0; - - stm->bits = 0; - stm->avail = 0; - - stm->bp = stm->buf; - stm->rp = stm->bp; - stm->wp = stm->bp; - stm->ep = stm->buf + sizeof stm->buf; - - stm->state = state; - stm->read = read; - stm->close = close; - stm->seek = NULL; - stm->ctx = ctx; - - return stm; -} - -fz_stream * -fz_keep_stream(fz_stream *stm) -{ - if (stm) - stm->refs ++; - return stm; -} - -void -fz_close(fz_stream *stm) -{ - if (!stm) - return; - stm->refs --; - if (stm->refs == 0) - { - if (stm->close) - stm->close(stm->ctx, stm->state); - fz_free(stm->ctx, stm); - } -} - -/* File stream */ - -static int read_file(fz_stream *stm, unsigned char *buf, int len) -{ - int n = read(*(int*)stm->state, buf, len); - if (n < 0) - fz_throw(stm->ctx, FZ_ERROR_GENERIC, "read error: %s", strerror(errno)); - return n; -} - -static void seek_file(fz_stream *stm, int offset, int whence) -{ - int n = lseek(*(int*)stm->state, offset, whence); - if (n < 0) - fz_throw(stm->ctx, FZ_ERROR_GENERIC, "cannot lseek: %s", strerror(errno)); - stm->pos = n; - stm->rp = stm->bp; - stm->wp = stm->bp; -} - -static void close_file(fz_context *ctx, void *state) -{ - int n = close(*(int*)state); - if (n < 0) - fz_warn(ctx, "close error: %s", strerror(errno)); - fz_free(ctx, state); -} - -fz_stream * -fz_open_fd(fz_context *ctx, int fd) -{ - fz_stream *stm; - int *state; - - state = fz_malloc_struct(ctx, int); - *state = fd; - - fz_try(ctx) - { - stm = fz_new_stream(ctx, state, read_file, close_file); - } - fz_catch(ctx) - { - fz_free(ctx, state); - fz_rethrow(ctx); - } - stm->seek = seek_file; - - return stm; -} - -fz_stream * -fz_open_file(fz_context *ctx, const char *name) -{ -#ifdef _WIN32 - char *s = (char*)name; - wchar_t *wname, *d; - int c, fd; - d = wname = fz_malloc(ctx, (strlen(name)+1) * sizeof(wchar_t)); - while (*s) { - s += fz_chartorune(&c, s); - *d++ = c; - } - *d = 0; - fd = _wopen(wname, O_BINARY | O_RDONLY, 0); - fz_free(ctx, wname); -#else - int fd = open(name, O_BINARY | O_RDONLY, 0); -#endif - if (fd == -1) - fz_throw(ctx, FZ_ERROR_GENERIC, "cannot open %s", name); - return fz_open_fd(ctx, fd); -} - -#ifdef _WIN32 -fz_stream * -fz_open_file_w(fz_context *ctx, const wchar_t *name) -{ - int fd = _wopen(name, O_BINARY | O_RDONLY, 0); - if (fd == -1) - fz_throw(ctx, FZ_ERROR_GENERIC, "cannot open file %ls", name); - return fz_open_fd(ctx, fd); -} -#endif - -/* Memory stream */ - -static int read_buffer(fz_stream *stm, unsigned char *buf, int len) -{ - return 0; -} - -static void seek_buffer(fz_stream *stm, int offset, int whence) -{ - if (whence == 0) - stm->rp = stm->bp + offset; - if (whence == 1) - stm->rp += offset; - if (whence == 2) - stm->rp = stm->ep - offset; - stm->rp = fz_clampp(stm->rp, stm->bp, stm->ep); - stm->wp = stm->ep; -} - -static void close_buffer(fz_context *ctx, void *state_) -{ - fz_buffer *state = (fz_buffer *)state_; - if (state) - fz_drop_buffer(ctx, state); -} - -fz_stream * -fz_open_buffer(fz_context *ctx, fz_buffer *buf) -{ - fz_stream *stm; - - fz_keep_buffer(ctx, buf); - stm = fz_new_stream(ctx, buf, read_buffer, close_buffer); - stm->seek = seek_buffer; - - stm->bp = buf->data; - stm->rp = buf->data; - stm->wp = buf->data + buf->len; - stm->ep = buf->data + buf->len; - - stm->pos = buf->len; - - return stm; -} - -fz_stream * -fz_open_memory(fz_context *ctx, unsigned char *data, int len) -{ - fz_stream *stm; - - stm = fz_new_stream(ctx, NULL, read_buffer, close_buffer); - stm->seek = seek_buffer; - - stm->bp = data; - stm->rp = data; - stm->wp = data + len; - stm->ep = data + len; - - stm->pos = len; - - return stm; -} diff --git a/fitz/stm_output.c b/fitz/stm_output.c deleted file mode 100644 index f98b945e..00000000 --- a/fitz/stm_output.c +++ /dev/null @@ -1,100 +0,0 @@ -#include "mupdf/fitz.h" - -static int -file_printf(fz_output *out, const char *fmt, va_list ap) -{ - FILE *file = (FILE *)out->opaque; - - return vfprintf(file, fmt, ap); -} - -static int -file_write(fz_output *out, const void *buffer, int count) -{ - FILE *file = (FILE *)out->opaque; - - return fwrite(buffer, 1, count, file); -} - -fz_output * -fz_new_output_with_file(fz_context *ctx, FILE *file) -{ - fz_output *out = fz_malloc_struct(ctx, fz_output); - out->ctx = ctx; - out->opaque = file; - out->printf = file_printf; - out->write = file_write; - out->close = NULL; - return out; -} - -void -fz_close_output(fz_output *out) -{ - if (!out) - return; - if (out->close) - out->close(out); - fz_free(out->ctx, out); -} - -int -fz_printf(fz_output *out, const char *fmt, ...) -{ - int ret; - va_list ap; - - if (!out) - return 0; - - va_start(ap, fmt); - ret = out->printf(out, fmt, ap); - va_end(ap); - - return ret; -} - -int -fz_write(fz_output *out, const void *data, int len) -{ - if (!out) - return 0; - return out->write(out, data, len); -} - -int -fz_puts(fz_output *out, const char *str) -{ - if (!out) - return 0; - return out->write(out, str, strlen(str)); -} - -static int -buffer_printf(fz_output *out, const char *fmt, va_list list) -{ - fz_buffer *buffer = (fz_buffer *)out->opaque; - - return fz_buffer_vprintf(out->ctx, buffer, fmt, list); -} - -static int -buffer_write(fz_output *out, const void *data, int len) -{ - fz_buffer *buffer = (fz_buffer *)out->opaque; - - fz_write_buffer(out->ctx, buffer, (unsigned char *)data, len); - return len; -} - -fz_output * -fz_new_output_with_buffer(fz_context *ctx, fz_buffer *buf) -{ - fz_output *out = fz_malloc_struct(ctx, fz_output); - out->ctx = ctx; - out->opaque = buf; - out->printf = buffer_printf; - out->write = buffer_write; - out->close = NULL; - return out; -} diff --git a/fitz/stm_read.c b/fitz/stm_read.c deleted file mode 100644 index ee3d1cad..00000000 --- a/fitz/stm_read.c +++ /dev/null @@ -1,219 +0,0 @@ -#include "mupdf/fitz.h" - -#define MIN_BOMB (100 << 20) - -int -fz_read(fz_stream *stm, unsigned char *buf, int len) -{ - int count, n; - - count = fz_mini(len, stm->wp - stm->rp); - if (count) - { - memcpy(buf, stm->rp, count); - stm->rp += count; - } - - if (count == len || stm->error || stm->eof) - return count; - - assert(stm->rp == stm->wp); - - if (len - count < stm->ep - stm->bp) - { - n = stm->read(stm, stm->bp, stm->ep - stm->bp); - if (n == 0) - { - stm->eof = 1; - } - else if (n > 0) - { - stm->rp = stm->bp; - stm->wp = stm->bp + n; - stm->pos += n; - } - - n = fz_mini(len - count, stm->wp - stm->rp); - if (n) - { - memcpy(buf + count, stm->rp, n); - stm->rp += n; - count += n; - } - } - else - { - n = stm->read(stm, buf + count, len - count); - if (n == 0) - { - stm->eof = 1; - } - else if (n > 0) - { - stm->pos += n; - count += n; - } - } - - return count; -} - -void -fz_fill_buffer(fz_stream *stm) -{ - int n; - - assert(stm->rp == stm->wp); - - if (stm->error || stm->eof) - return; - - fz_try(stm->ctx) - { - n = stm->read(stm, stm->bp, stm->ep - stm->bp); - if (n == 0) - { - stm->eof = 1; - } - else if (n > 0) - { - stm->rp = stm->bp; - stm->wp = stm->bp + n; - stm->pos += n; - } - } - fz_catch(stm->ctx) - { - /* FIXME: TryLater */ - fz_warn(stm->ctx, "read error; treating as end of file"); - stm->error = 1; - } -} - -fz_buffer * -fz_read_all(fz_stream *stm, int initial) -{ - return fz_read_best(stm, initial, NULL); -} - -fz_buffer * -fz_read_best(fz_stream *stm, int initial, int *truncated) -{ - fz_buffer *buf = NULL; - int n; - fz_context *ctx = stm->ctx; - - fz_var(buf); - - if (truncated) - *truncated = 0; - - fz_try(ctx) - { - if (initial < 1024) - initial = 1024; - - buf = fz_new_buffer(ctx, initial+1); - - while (1) - { - if (buf->len == buf->cap) - fz_grow_buffer(ctx, buf); - - if (buf->len >= MIN_BOMB && buf->len / 200 > initial) - { - fz_throw(ctx, FZ_ERROR_GENERIC, "compression bomb detected"); - } - - n = fz_read(stm, buf->data + buf->len, buf->cap - buf->len); - if (n == 0) - break; - - buf->len += n; - } - } - fz_catch(ctx) - { - /* FIXME: TryLater */ - if (truncated) - { - *truncated = 1; - } - else - { - fz_drop_buffer(ctx, buf); - fz_rethrow(ctx); - } - } - fz_trim_buffer(ctx, buf); - - return buf; -} - -void -fz_read_line(fz_stream *stm, char *mem, int n) -{ - char *s = mem; - int c = EOF; - while (n > 1) - { - c = fz_read_byte(stm); - if (c == EOF) - break; - if (c == '\r') { - c = fz_peek_byte(stm); - if (c == '\n') - fz_read_byte(stm); - break; - } - if (c == '\n') - break; - *s++ = c; - n--; - } - if (n) - *s = '\0'; -} - -int -fz_tell(fz_stream *stm) -{ - return stm->pos - (stm->wp - stm->rp); -} - -void -fz_seek(fz_stream *stm, int offset, int whence) -{ - if (stm->seek) - { - if (whence == 1) - { - offset = fz_tell(stm) + offset; - whence = 0; - } - if (whence == 0) - { - int dist = stm->pos - offset; - if (dist >= 0 && dist <= stm->wp - stm->bp) - { - stm->rp = stm->wp - dist; - stm->eof = 0; - return; - } - } - stm->seek(stm, offset, whence); - stm->eof = 0; - } - else if (whence != 2) - { - if (whence == 0) - offset -= fz_tell(stm); - if (offset < 0) - fz_warn(stm->ctx, "cannot seek backwards"); - /* dog slow, but rare enough */ - while (offset-- > 0) - fz_read_byte(stm); - } - else - fz_warn(stm->ctx, "cannot seek"); -} diff --git a/fitz/text_extract.c b/fitz/text_extract.c deleted file mode 100644 index e3bf9d19..00000000 --- a/fitz/text_extract.c +++ /dev/null @@ -1,1027 +0,0 @@ -#include "mupdf/fitz.h" -#include "ucdn.h" - -/* Extract text into an unsorted span soup. */ - -#define LINE_DIST 0.9f -#define SPACE_DIST 0.2f -#define SPACE_MAX_DIST 0.8f -#define PARAGRAPH_DIST 0.5f - -#undef DEBUG_SPANS -#undef DEBUG_INTERNALS -#undef DEBUG_LINE_HEIGHTS -#undef DEBUG_MASKS -#undef DEBUG_ALIGN -#undef DEBUG_INDENTS - -#include -#include FT_FREETYPE_H -#include FT_ADVANCES_H - -typedef struct fz_text_device_s fz_text_device; - -typedef struct span_soup_s span_soup; - -struct fz_text_device_s -{ - fz_text_sheet *sheet; - fz_text_page *page; - span_soup *spans; - fz_text_span *cur_span; - int lastchar; -}; - -static fz_rect * -add_point_to_rect(fz_rect *a, const fz_point *p) -{ - if (p->x < a->x0) - a->x0 = p->x; - if (p->x > a->x1) - a->x1 = p->x; - if (p->y < a->y0) - a->y0 = p->y; - if (p->y > a->y1) - a->y1 = p->y; - return a; -} - -fz_rect * -fz_text_char_bbox(fz_rect *bbox, fz_text_span *span, int i) -{ - fz_point a, d; - const fz_point *max; - fz_text_char *ch; - - if (!span || i >= span->len) - { - *bbox = fz_empty_rect; - } - ch = &span->text[i]; - if (i == span->len-1) - max = &span->max; - else - max = &span->text[i+1].p; - a.x = 0; - a.y = span->ascender_max; - fz_transform_vector(&a, &span->transform); - d.x = 0; - d.y = span->descender_min; - fz_transform_vector(&d, &span->transform); - bbox->x0 = bbox->x1 = ch->p.x + a.x; - bbox->y0 = bbox->y1 = ch->p.y + a.y; - a.x += max->x; - a.y += max->y; - add_point_to_rect(bbox, &a); - a.x = ch->p.x + d.x; - a.y = ch->p.y + d.y; - add_point_to_rect(bbox, &a); - a.x = max->x + d.x; - a.y = max->y + d.y; - add_point_to_rect(bbox, &a); - return bbox; -} - -static void -add_bbox_to_span(fz_text_span *span) -{ - fz_point a, d; - fz_rect *bbox = &span->bbox; - - if (!span) - return; - a.x = 0; - a.y = span->ascender_max; - fz_transform_vector(&a, &span->transform); - d.x = 0; - d.y = span->descender_min; - fz_transform_vector(&d, &span->transform); - bbox->x0 = bbox->x1 = span->min.x + a.x; - bbox->y0 = bbox->y1 = span->min.y + a.y; - a.x += span->max.x; - a.y += span->max.y; - add_point_to_rect(bbox, &a); - a.x = span->min.x + d.x; - a.y = span->min.y + d.y; - add_point_to_rect(bbox, &a); - a.x = span->max.x + d.x; - a.y = span->max.y + d.y; - add_point_to_rect(bbox, &a); -} - -struct span_soup_s -{ - fz_context *ctx; - int len, cap; - fz_text_span **spans; -}; - -static span_soup * -new_span_soup(fz_context *ctx) -{ - span_soup *soup = fz_malloc_struct(ctx, span_soup); - soup->ctx = ctx; - soup->len = 0; - soup->cap = 0; - soup->spans = NULL; - return soup; -} - -static void -free_span_soup(span_soup *soup) -{ - int i; - - if (soup == NULL) - return; - for (i = 0; i < soup->len; i++) - { - fz_free(soup->ctx, soup->spans[i]); - } - fz_free(soup->ctx, soup->spans); - fz_free(soup->ctx, soup); -} - -static void -add_span_to_soup(span_soup *soup, fz_text_span *span) -{ - if (span == NULL) - return; - if (soup->len == soup->cap) - { - int newcap = (soup->cap ? soup->cap * 2 : 16); - soup->spans = fz_resize_array(soup->ctx, soup->spans, newcap, sizeof(*soup->spans)); - soup->cap = newcap; - } - add_bbox_to_span(span); - soup->spans[soup->len++] = span; -} - -static fz_text_line * -push_span(fz_context *ctx, fz_text_device *tdev, fz_text_span *span, int new_line, float distance) -{ - fz_text_line *line; - fz_text_block *block; - fz_text_page *page = tdev->page; - int prev_not_text = 0; - - if (page->len == 0 || page->blocks[page->len-1].type != FZ_PAGE_BLOCK_TEXT) - prev_not_text = 1; - - if (new_line || prev_not_text) - { - float size = fz_matrix_expansion(&span->transform); - /* So, a new line. Part of the same block or not? */ - if (distance == 0 || distance > size * 1.5 || distance < -size * PARAGRAPH_DIST || page->len == 0 || prev_not_text) - { - /* New block */ - if (page->len == page->cap) - { - int newcap = (page->cap ? page->cap*2 : 4); - page->blocks = fz_resize_array(ctx, page->blocks, newcap, sizeof(*page->blocks)); - page->cap = newcap; - } - block = fz_malloc_struct(ctx, fz_text_block); - page->blocks[page->len].type = FZ_PAGE_BLOCK_TEXT; - page->blocks[page->len].u.text = block; - block->cap = 0; - block->len = 0; - block->lines = 0; - block->bbox = fz_empty_rect; - page->len++; - distance = 0; - } - - /* New line */ - block = page->blocks[page->len-1].u.text; - if (block->len == block->cap) - { - int newcap = (block->cap ? block->cap*2 : 4); - block->lines = fz_resize_array(ctx, block->lines, newcap, sizeof(*block->lines)); - block->cap = newcap; - } - block->lines[block->len].first_span = NULL; - block->lines[block->len].last_span = NULL; - block->lines[block->len].distance = distance; - block->lines[block->len].bbox = fz_empty_rect; - block->len++; - } - - /* Find last line and append to it */ - block = page->blocks[page->len-1].u.text; - line = &block->lines[block->len-1]; - - fz_union_rect(&block->lines[block->len-1].bbox, &span->bbox); - fz_union_rect(&block->bbox, &span->bbox); - span->base_offset = (new_line ? 0 : distance); - - if (!line->first_span) - { - line->first_span = line->last_span = span; - span->next = NULL; - } - else - { - line->last_span->next = span; - line->last_span = span; - } - - return line; -} - -#if defined(DEBUG_SPANS) || defined(DEBUG_ALIGN) || defined(DEBUG_INDENTS) -static void -dump_span(fz_text_span *s) -{ - int i; - for (i=0; i < s->len; i++) - { - printf("%c", s->text[i].c); - } -} -#endif - -#ifdef DEBUG_ALIGN -static void -dump_line(fz_text_line *line) -{ - int i; - for (i=0; i < line->len; i++) - { - fz_text_span *s = line->spans[i]; - if (s->spacing > 1) - printf(" "); - dump_span(s); - } - printf("\n"); -} -#endif - -static void -strain_soup(fz_context *ctx, fz_text_device *tdev) -{ - span_soup *soup = tdev->spans; - fz_text_line *last_line = NULL; - fz_text_span *last_span = NULL; - int span_num; - - /* Really dumb implementation to match what we had before */ - for (span_num=0; span_num < soup->len; span_num++) - { - fz_text_span *span = soup->spans[span_num]; - int new_line = 1; - float distance = 0; - float spacing = 0; - soup->spans[span_num] = NULL; - if (last_span) - { - /* If we have a last_span, we must have a last_line */ - /* Do span and last_line share the same baseline? */ - fz_point p, q, perp_r; - float dot; - float size = fz_matrix_expansion(&span->transform); - -#ifdef DEBUG_SPANS - { - printf("Comparing: \""); - dump_span(last_span); - printf("\" and \""); - dump_span(span); - printf("\"\n"); - } -#endif - - p.x = last_line->first_span->max.x - last_line->first_span->min.x; - p.y = last_line->first_span->max.y - last_line->first_span->min.y; - fz_normalize_vector(&p); - q.x = span->max.x - span->min.x; - q.y = span->max.y - span->min.y; - fz_normalize_vector(&q); -#ifdef DEBUG_SPANS - printf("last_span=%g %g -> %g %g = %g %g\n", last_span->min.x, last_span->min.y, last_span->max.x, last_span->max.y, p.x, p.y); - printf("span =%g %g -> %g %g = %g %g\n", span->min.x, span->min.y, span->max.x, span->max.y, q.x, q.y); -#endif - perp_r.y = last_line->first_span->min.x - span->min.x; - perp_r.x = -(last_line->first_span->min.y - span->min.y); - /* Check if p and q are parallel. If so, then this - * line is parallel with the last one. */ - dot = p.x * q.x + p.y * q.y; - if (fabsf(dot) > 0.9995) - { - /* If we take the dot product of normalised(p) and - * perp(r), we get the perpendicular distance from - * one line to the next (assuming they are parallel). */ - distance = p.x * perp_r.x + p.y * perp_r.y; - /* We allow 'small' distances of baseline changes - * to cope with super/subscript. FIXME: We should - * gather subscript/superscript information here. */ - new_line = (fabsf(distance) > size * LINE_DIST); - } - else - { - new_line = 1; - distance = 0; - } - if (!new_line) - { - fz_point delta; - - delta.x = span->min.x - last_span->max.x; - delta.y = span->min.y - last_span->max.y; - - spacing = (p.x * delta.x + p.y * delta.y); - spacing = fabsf(spacing); - /* Only allow changes in baseline (subscript/superscript etc) - * when the spacing is small. */ - if (spacing * fabsf(distance) > size * LINE_DIST && fabsf(distance) > size * 0.1f) - { - new_line = 1; - distance = 0; - spacing = 0; - } - else - { - spacing /= size * SPACE_DIST; - /* Apply the same logic here as when we're adding chars to build spans. */ - if (spacing >= 1 && spacing < (SPACE_MAX_DIST/SPACE_DIST)) - spacing = 1; - } - } -#ifdef DEBUG_SPANS - printf("dot=%g new_line=%d distance=%g size=%g spacing=%g\n", dot, new_line, distance, size, spacing); -#endif - } - span->spacing = spacing; - last_line = push_span(ctx, tdev, span, new_line, distance); - last_span = span; - } -} - -fz_text_sheet * -fz_new_text_sheet(fz_context *ctx) -{ - fz_text_sheet *sheet = fz_malloc(ctx, sizeof *sheet); - sheet->maxid = 0; - sheet->style = NULL; - return sheet; -} - -void -fz_free_text_sheet(fz_context *ctx, fz_text_sheet *sheet) -{ - fz_text_style *style; - - if (sheet == NULL) - return; - - style = sheet->style; - while (style) - { - fz_text_style *next = style->next; - fz_drop_font(ctx, style->font); - fz_free(ctx, style); - style = next; - } - fz_free(ctx, sheet); -} - -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, const fz_matrix *ctm, - fz_colorspace *colorspace, float *color, float alpha, fz_stroke_state *stroke) -{ - 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; - fz_concat(&trm, &tm, ctm); - size = fz_matrix_expansion(&trm); - } - return fz_lookup_text_style_imp(ctx, sheet, size, font, wmode, 0); -} - -fz_text_page * -fz_new_text_page(fz_context *ctx) -{ - fz_text_page *page = fz_malloc(ctx, sizeof(*page)); - page->mediabox = fz_empty_rect; - page->len = 0; - page->cap = 0; - page->blocks = NULL; - page->next = NULL; - return page; -} - -static void -fz_free_text_line_contents(fz_context *ctx, fz_text_line *line) -{ - fz_text_span *span, *next; - for (span = line->first_span; span; span=next) - { - next = span->next; - fz_free(ctx, span->text); - fz_free(ctx, span); - } -} - -static void -fz_free_text_block(fz_context *ctx, fz_text_block *block) -{ - fz_text_line *line; - if (block == NULL) - return; - for (line = block->lines; line < block->lines + block->len; line++) - fz_free_text_line_contents(ctx, line); - fz_free(ctx, block->lines); - fz_free(ctx, block); -} - -static void -fz_free_image_block(fz_context *ctx, fz_image_block *block) -{ - if (block == NULL) - return; - fz_drop_image(ctx, block->image); - fz_drop_colorspace(ctx, block->cspace); - fz_free(ctx, block); -} - -void -fz_free_text_page(fz_context *ctx, fz_text_page *page) -{ - fz_page_block *block; - if (page == NULL) - return; - for (block = page->blocks; block < page->blocks + page->len; block++) - { - switch (block->type) - { - case FZ_PAGE_BLOCK_TEXT: - fz_free_text_block(ctx, block->u.text); - break; - case FZ_PAGE_BLOCK_IMAGE: - fz_free_image_block(ctx, block->u.image); - break; - } - } - fz_free(ctx, page->blocks); - fz_free(ctx, page); -} - -static fz_text_span * -fz_new_text_span(fz_context *ctx, const fz_point *p, int wmode, const fz_matrix *trm) -{ - fz_text_span *span = fz_malloc_struct(ctx, fz_text_span); - span->ascender_max = 0; - span->descender_min = 0; - span->cap = 0; - span->len = 0; - span->min = *p; - span->max = *p; - span->wmode = wmode; - span->transform.a = trm->a; - span->transform.b = trm->b; - span->transform.c = trm->c; - span->transform.d = trm->d; - span->transform.e = 0; - span->transform.f = 0; - span->text = NULL; - span->next = NULL; - return span; -} - -static void -add_char_to_span(fz_context *ctx, fz_text_span *span, int c, fz_point *p, fz_point *max, fz_text_style *style) -{ - if (span->len == span->cap) - { - int newcap = (span->cap ? span->cap * 2 : 16); - span->text = fz_resize_array(ctx, span->text, newcap, sizeof(fz_text_char)); - span->cap = newcap; - span->bbox = fz_empty_rect; - } - span->max = *max; - if (style->ascender > span->ascender_max) - span->ascender_max = style->ascender; - if (style->descender < span->descender_min) - span->descender_min = style->descender; - span->text[span->len].c = c; - span->text[span->len].p = *p; - span->text[span->len].style = style; - span->len++; -} - -static void -fz_add_text_char_imp(fz_context *ctx, fz_text_device *dev, fz_text_style *style, int c, fz_matrix *trm, float adv, int wmode) -{ - int can_append = 1; - int add_space = 0; - fz_point dir, ndir, p, q; - float size; - fz_point delta; - float spacing = 0; - float base_offset = 0; - - if (wmode == 0) - { - dir.x = 1; - dir.y = 0; - } - else - { - dir.x = 0; - dir.y = 1; - } - fz_transform_vector(&dir, trm); - ndir = dir; - fz_normalize_vector(&ndir); - /* dir = direction vector for motion. ndir = normalised(dir) */ - - size = fz_matrix_expansion(trm); - - if (dev->cur_span == NULL || - trm->a != dev->cur_span->transform.a || trm->b != dev->cur_span->transform.b || - trm->c != dev->cur_span->transform.c || trm->d != dev->cur_span->transform.d) - { - /* If the matrix has changed (or if we don't have a span at - * all), then we can't append. */ -#ifdef DEBUG_SPANS - printf("Transform changed\n"); -#endif - can_append = 0; - } - else - { - /* Calculate how far we've moved since the end of the current - * span. */ - delta.x = trm->e - dev->cur_span->max.x; - delta.y = trm->f - dev->cur_span->max.y; - - /* The transform has not changed, so we know we're in the same - * direction. Calculate 2 distances; how far off the previous - * baseline we are, together with how far along the baseline - * we are from the expected position. */ - spacing = ndir.x * delta.x + ndir.y * delta.y; - base_offset = -ndir.y * delta.x + ndir.x * delta.y; - - spacing /= size * SPACE_DIST; - spacing = fabsf(spacing); - if (fabsf(base_offset) < size * 0.1) - { - /* Only a small amount off the baseline - we'll take this */ - if (spacing < 1.0) - { - /* Motion is in line, and small. */ - } - else if (spacing >= 1 && spacing < (SPACE_MAX_DIST/SPACE_DIST)) - { - /* Motion is in line, but large enough - * to warrant us adding a space */ - if (dev->lastchar != ' ' && wmode == 0) - add_space = 1; - } - else - { - /* Motion is in line, but too large - split to a new span */ - can_append = 0; - } - } - else - { - can_append = 0; - spacing = 0; - } - } - -#ifdef DEBUG_SPANS - printf("%c%c append=%d space=%d size=%g spacing=%g base_offset=%g\n", dev->lastchar, c, can_append, add_space, size, spacing, base_offset); -#endif - - p.x = trm->e; - p.y = trm->f; - if (can_append == 0) - { - /* Start a new span */ - add_span_to_soup(dev->spans, dev->cur_span); - dev->cur_span = NULL; - dev->cur_span = fz_new_text_span(ctx, &p, wmode, trm); - dev->cur_span->spacing = 0; - } - if (add_space) - { - q.x = - 0.2f; - q.y = 0; - fz_transform_point(&q, trm); - add_char_to_span(ctx, dev->cur_span, ' ', &p, &q, style); - } - /* Advance the matrix */ - q.x = trm->e += adv * dir.x; - q.y = trm->f += adv * dir.y; - add_char_to_span(ctx, dev->cur_span, c, &p, &q, style); -} - -static void -fz_add_text_char(fz_context *ctx, fz_text_device *dev, fz_text_style *style, int c, fz_matrix *trm, float adv, int wmode) -{ - switch (c) - { - case -1: /* ignore when one unicode character maps to multiple glyphs */ - break; - case 0xFB00: /* ff */ - fz_add_text_char_imp(ctx, dev, style, 'f', trm, adv/2, wmode); - fz_add_text_char_imp(ctx, dev, style, 'f', trm, adv/2, wmode); - break; - case 0xFB01: /* fi */ - fz_add_text_char_imp(ctx, dev, style, 'f', trm, adv/2, wmode); - fz_add_text_char_imp(ctx, dev, style, 'i', trm, adv/2, wmode); - break; - case 0xFB02: /* fl */ - fz_add_text_char_imp(ctx, dev, style, 'f', trm, adv/2, wmode); - fz_add_text_char_imp(ctx, dev, style, 'l', trm, adv/2, wmode); - break; - case 0xFB03: /* ffi */ - fz_add_text_char_imp(ctx, dev, style, 'f', trm, adv/3, wmode); - fz_add_text_char_imp(ctx, dev, style, 'f', trm, adv/3, wmode); - fz_add_text_char_imp(ctx, dev, style, 'i', trm, adv/3, wmode); - break; - case 0xFB04: /* ffl */ - fz_add_text_char_imp(ctx, dev, style, 'f', trm, adv/3, wmode); - fz_add_text_char_imp(ctx, dev, style, 'f', trm, adv/3, wmode); - fz_add_text_char_imp(ctx, dev, style, 'l', trm, adv/3, wmode); - break; - case 0xFB05: /* long st */ - case 0xFB06: /* st */ - fz_add_text_char_imp(ctx, dev, style, 's', trm, adv/2, wmode); - fz_add_text_char_imp(ctx, dev, style, 't', trm, adv/2, wmode); - break; - default: - fz_add_text_char_imp(ctx, dev, style, c, trm, adv, wmode); - break; - } -} - -static void -fz_text_extract(fz_context *ctx, fz_text_device *dev, fz_text *text, const fz_matrix *ctm, fz_text_style *style) -{ - fz_font *font = text->font; - FT_Face face = font->ft_face; - fz_matrix tm = text->trm; - fz_matrix trm; - float adv; - float ascender = 1; - float descender = 0; - int multi; - int i, j, err; - - if (text->len == 0) - return; - - 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); - } - else if (font->t3procs && !fz_is_empty_rect(&font->bbox)) - { - ascender = font->bbox.y1; - descender = font->bbox.y0; - } - style->ascender = ascender; - style->descender = descender; - - tm.e = 0; - tm.f = 0; - fz_concat(&trm, &tm, ctm); - - for (i = 0; i < text->len; i++) - { - /* Calculate new pen location and delta */ - tm.e = text->items[i].x; - tm.f = text->items[i].y; - fz_concat(&trm, &tm, ctm); - - /* Calculate bounding box and new pen position based on font metrics */ - if (font->ft_face) - { - FT_Fixed ftadv = 0; - int mask = FT_LOAD_NO_BITMAP | FT_LOAD_NO_HINTING | FT_LOAD_IGNORE_TRANSFORM; - - /* 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); - } - else - { - adv = font->t3widths[text->items[i].gid]; - } - - /* 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, &trm, adv, text->wmode); - } - else - { - for (j = 0; j < multi; j++) - { - fz_add_text_char(ctx, dev, style, text->items[i + j].ucs, &trm, adv/multi, text->wmode); - } - i += j - 1; - } - - dev->lastchar = text->items[i].ucs; - } -} - -static void -fz_text_fill_text(fz_device *dev, fz_text *text, const fz_matrix *ctm, - fz_colorspace *colorspace, float *color, float alpha) -{ - fz_text_device *tdev = dev->user; - 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 -fz_text_stroke_text(fz_device *dev, fz_text *text, fz_stroke_state *stroke, const fz_matrix *ctm, - fz_colorspace *colorspace, float *color, float alpha) -{ - fz_text_device *tdev = dev->user; - 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, const fz_matrix *ctm, int accumulate) -{ - fz_text_device *tdev = dev->user; - 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, const fz_matrix *ctm) -{ - fz_text_device *tdev = dev->user; - 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, const fz_matrix *ctm) -{ - fz_text_device *tdev = dev->user; - 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_fill_image_mask(fz_device *dev, fz_image *img, const fz_matrix *ctm, - fz_colorspace *cspace, float *color, float alpha) -{ - fz_text_device *tdev = dev->user; - fz_text_page *page = tdev->page; - fz_image_block *block; - fz_context *ctx = dev->ctx; - - /* If the alpha is less than 50% then it's probably a watermark or - * effect or something. Skip it */ - if (alpha < 0.5) - return; - - /* New block */ - if (page->len == page->cap) - { - int newcap = (page->cap ? page->cap*2 : 4); - page->blocks = fz_resize_array(ctx, page->blocks, newcap, sizeof(*page->blocks)); - page->cap = newcap; - } - block = fz_malloc_struct(ctx, fz_image_block); - page->blocks[page->len].type = FZ_PAGE_BLOCK_IMAGE; - page->blocks[page->len].u.image = block; - block->image = fz_keep_image(ctx, img); - block->cspace = fz_keep_colorspace(ctx, cspace); - if (cspace) - memcpy(block->colors, color, sizeof(block->colors[0])*cspace->n); - page->len++; -} - -static void -fz_text_fill_image(fz_device *dev, fz_image *img, const fz_matrix *ctm, float alpha) -{ - fz_text_fill_image_mask(dev, img, ctm, NULL, NULL, alpha); -} - -static int -fz_bidi_direction(int bidiclass, int curdir) -{ - switch (bidiclass) - { - /* strong */ - case UCDN_BIDI_CLASS_L: return 1; - case UCDN_BIDI_CLASS_R: return -1; - case UCDN_BIDI_CLASS_AL: return -1; - - /* weak */ - case UCDN_BIDI_CLASS_EN: - case UCDN_BIDI_CLASS_ES: - case UCDN_BIDI_CLASS_ET: - case UCDN_BIDI_CLASS_AN: - case UCDN_BIDI_CLASS_CS: - case UCDN_BIDI_CLASS_NSM: - case UCDN_BIDI_CLASS_BN: - return curdir; - - /* neutral */ - case UCDN_BIDI_CLASS_B: - case UCDN_BIDI_CLASS_S: - case UCDN_BIDI_CLASS_WS: - case UCDN_BIDI_CLASS_ON: - return curdir; - - /* embedding, override, pop ... we don't support them */ - default: - return 0; - } -} - -static void -fz_bidi_reorder_run(fz_text_span *span, int a, int b, int dir) -{ - if (a < b && dir == -1) - { - fz_text_char c; - int m = a + (b - a) / 2; - while (a < m) - { - b--; - c = span->text[a]; - span->text[a] = span->text[b]; - span->text[b] = c; - a++; - } - } -} - -static void -fz_bidi_reorder_span(fz_text_span *span) -{ - int a, b, dir, curdir; - - a = 0; - curdir = 1; - for (b = 0; b < span->len; b++) - { - dir = fz_bidi_direction(ucdn_get_bidi_class(span->text[b].c), curdir); - if (dir != curdir) - { - fz_bidi_reorder_run(span, a, b, curdir); - curdir = dir; - a = b; - } - } - fz_bidi_reorder_run(span, a, b, curdir); -} - -static void -fz_bidi_reorder_text_page(fz_context *ctx, fz_text_page *page) -{ - fz_page_block *pageblock; - fz_text_block *block; - fz_text_line *line; - fz_text_span *span; - - for (pageblock = page->blocks; pageblock < page->blocks + page->len; pageblock++) - if (pageblock->type == FZ_PAGE_BLOCK_TEXT) - for (block = pageblock->u.text, line = block->lines; line < block->lines + block->len; line++) - for (span = line->first_span; span; span = span->next) - fz_bidi_reorder_span(span); -} - -static void -fz_text_begin_page(fz_device *dev, const fz_rect *mediabox, const fz_matrix *ctm) -{ - fz_context *ctx = dev->ctx; - fz_text_device *tdev = dev->user; - - if (tdev->page->len) - { - tdev->page->next = fz_new_text_page(ctx); - tdev->page = tdev->page->next; - } - - tdev->page->mediabox = *mediabox; - fz_transform_rect(&tdev->page->mediabox, ctm); - - tdev->spans = new_span_soup(ctx); -} - -static void -fz_text_end_page(fz_device *dev) -{ - fz_context *ctx = dev->ctx; - fz_text_device *tdev = dev->user; - - add_span_to_soup(tdev->spans, tdev->cur_span); - tdev->cur_span = NULL; - - strain_soup(ctx, tdev); - free_span_soup(tdev->spans); - tdev->spans = NULL; - - /* TODO: smart sorting of blocks in reading order */ - /* TODO: unicode NFC normalization */ - - fz_bidi_reorder_text_page(ctx, tdev->page); -} - -static void -fz_text_free_user(fz_device *dev) -{ - fz_text_device *tdev = dev->user; - free_span_soup(tdev->spans); - fz_free(dev->ctx, tdev); -} - -fz_device * -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->sheet = sheet; - tdev->page = page; - tdev->spans = NULL; - tdev->cur_span = NULL; - tdev->lastchar = ' '; - - dev = fz_new_device(ctx, tdev); - dev->hints = FZ_IGNORE_IMAGE | FZ_IGNORE_SHADE; - dev->begin_page = fz_text_begin_page; - dev->end_page = fz_text_end_page; - dev->free_user = fz_text_free_user; - dev->fill_text = fz_text_fill_text; - dev->stroke_text = fz_text_stroke_text; - dev->clip_text = fz_text_clip_text; - dev->clip_stroke_text = fz_text_clip_stroke_text; - dev->ignore_text = fz_text_ignore_text; - dev->fill_image = fz_text_fill_image; - dev->fill_image_mask = fz_text_fill_image_mask; - - return dev; -} diff --git a/fitz/text_output.c b/fitz/text_output.c deleted file mode 100644 index d3241131..00000000 --- a/fitz/text_output.c +++ /dev/null @@ -1,400 +0,0 @@ -#include "mupdf/fitz.h" - -#define SUBSCRIPT_OFFSET 0.2f -#define SUPERSCRIPT_OFFSET -0.2f - -#include -#include FT_FREETYPE_H - -/* 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(fz_output *out, fz_text_style *style) -{ - int script = style->script; - fz_printf(out, "", style->id); - while (script-- > 0) - fz_printf(out, ""); - while (++script < 0) - fz_printf(out, ""); -} - -static void -fz_print_style_end(fz_output *out, fz_text_style *style) -{ - int script = style->script; - while (script-- > 0) - fz_printf(out, ""); - while (++script < 0) - fz_printf(out, ""); - fz_printf(out, ""); -} - -static void -fz_print_style(fz_output *out, fz_text_style *style) -{ - char *s = strchr(style->font->name, '+'); - s = s ? s + 1 : style->font->name; - fz_printf(out, "span.s%d{font-family:\"%s\";font-size:%gpt;", - style->id, s, style->size); - if (font_is_italic(style->font)) - fz_printf(out, "font-style:italic;"); - if (font_is_bold(style->font)) - fz_printf(out, "font-weight:bold;"); - fz_printf(out, "}\n"); -} - -void -fz_print_text_sheet(fz_context *ctx, fz_output *out, fz_text_sheet *sheet) -{ - fz_text_style *style; - for (style = sheet->style; style; style = style->next) - fz_print_style(out, style); -} - -static void -send_data_base64(fz_output *out, fz_buffer *buffer) -{ - int i, len; - static const char set[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - - len = buffer->len/3; - for (i = 0; i < len; i++) - { - int c = buffer->data[3*i]; - int d = buffer->data[3*i+1]; - int e = buffer->data[3*i+2]; - if ((i & 15) == 0) - fz_printf(out, "\n"); - fz_printf(out, "%c%c%c%c", set[c>>2], set[((c&3)<<4)|(d>>4)], set[((d&15)<<2)|(e>>6)], set[e & 63]); - } - i *= 3; - switch (buffer->len-i) - { - case 2: - { - int c = buffer->data[i]; - int d = buffer->data[i+1]; - fz_printf(out, "%c%c%c=", set[c>>2], set[((c&3)<<4)|(d>>4)], set[((d&15)<<2)]); - break; - } - case 1: - { - int c = buffer->data[i]; - fz_printf(out, "%c%c==", set[c>>2], set[(c&3)<<4]); - break; - } - default: - case 0: - break; - } -} - -void -fz_print_text_page_html(fz_context *ctx, fz_output *out, fz_text_page *page) -{ - int block_n, line_n, ch_n; - fz_text_style *style = NULL; - fz_text_line *line; - fz_text_span *span; - void *last_region = NULL; - - fz_printf(out, "
\n"); - - for (block_n = 0; block_n < page->len; block_n++) - { - switch (page->blocks[block_n].type) - { - case FZ_PAGE_BLOCK_TEXT: - { - fz_text_block * block = page->blocks[block_n].u.text; - fz_printf(out, "

\n"); - for (line_n = 0; line_n < block->len; line_n++) - { - int lastcol=-1; - line = &block->lines[line_n]; - style = NULL; - - if (line->region != last_region) - { - if (last_region) - fz_printf(out, "

"); - fz_printf(out, "
"); - last_region = line->region; - } - fz_printf(out, "
region) - fz_printf(out, " region=\"%x\"", line->region); -#endif - fz_printf(out, ">"); - for (span = line->first_span; span; span = span->next) - { - float size = fz_matrix_expansion(&span->transform); - float base_offset = span->base_offset / size; - - if (lastcol != span->column) - { - if (lastcol >= 0) - { - fz_printf(out, "
"); - } - /* If we skipped any columns then output some spacer spans */ - while (lastcol < span->column-1) - { - fz_printf(out, "
"); - lastcol++; - } - lastcol++; - /* Now output the span to contain this entire column */ - fz_printf(out, "
next; sn; sn = sn->next) - { - if (sn->column != lastcol) - break; - } - fz_printf(out, "width:%g%%;align:%s", span->column_width, (span->align == 0 ? "left" : (span->align == 1 ? "center" : "right"))); - } - if (span->indent > 1) - fz_printf(out, ";padding-left:1em;text-indent:-1em"); - if (span->indent < -1) - fz_printf(out, ";text-indent:1em"); - fz_printf(out, "\">"); - } -#ifdef DEBUG_INTERNALS - fz_printf(out, "column) - fz_printf(out, " col=\"%x\"", span->column); - fz_printf(out, ">"); -#endif - if (span->spacing >= 1) - fz_printf(out, " "); - if (base_offset > SUBSCRIPT_OFFSET) - fz_printf(out, ""); - else if (base_offset < SUPERSCRIPT_OFFSET) - fz_printf(out, ""); - for (ch_n = 0; ch_n < span->len; ch_n++) - { - fz_text_char *ch = &span->text[ch_n]; - if (style != ch->style) - { - if (style) - fz_print_style_end(out, style); - fz_print_style_begin(out, ch->style); - style = ch->style; - } - - if (ch->c == '<') - fz_printf(out, "<"); - else if (ch->c == '>') - fz_printf(out, ">"); - else if (ch->c == '&') - fz_printf(out, "&"); - else if (ch->c >= 32 && ch->c <= 127) - fz_printf(out, "%c", ch->c); - else - fz_printf(out, "&#x%x;", ch->c); - } - if (style) - { - fz_print_style_end(out, style); - style = NULL; - } - if (base_offset > SUBSCRIPT_OFFSET) - fz_printf(out, ""); - else if (base_offset < SUPERSCRIPT_OFFSET) - fz_printf(out, ""); -#ifdef DEBUG_INTERNALS - fz_printf(out, ""); -#endif - } - /* Close our floating span */ - fz_printf(out, "
"); - /* Close the line */ - fz_printf(out, "
"); - fz_printf(out, "\n"); - } - /* Close the metaline */ - fz_printf(out, "
"); - last_region = NULL; - fz_printf(out, "

\n"); - break; - } - case FZ_PAGE_BLOCK_IMAGE: - { - fz_image_block *image = page->blocks[block_n].u.image; - fz_printf(out, "image->w, image->image->h); - switch (image->image->buffer == NULL ? FZ_IMAGE_JPX : image->image->buffer->params.type) - { - case FZ_IMAGE_JPEG: - fz_printf(out, "image/jpeg;base64,"); - send_data_base64(out, image->image->buffer->buffer); - break; - case FZ_IMAGE_PNG: - fz_printf(out, "image/png;base64,"); - send_data_base64(out, image->image->buffer->buffer); - break; - default: - { - fz_buffer *buf = fz_image_as_png(ctx, image->image, image->image->w, image->image->h); - fz_printf(out, "image/png;base64,"); - send_data_base64(out, buf); - fz_drop_buffer(ctx, buf); - break; - } - } - fz_printf(out, "\">\n"); - break; - } - } - } - - fz_printf(out, "\n"); -} - -void -fz_print_text_page_xml(fz_context *ctx, fz_output *out, fz_text_page *page) -{ - int block_n; - - fz_printf(out, "\n", - page->mediabox.x1 - page->mediabox.x0, - page->mediabox.y1 - page->mediabox.y0); - - for (block_n = 0; block_n < page->len; block_n++) - { - switch (page->blocks[block_n].type) - { - case FZ_PAGE_BLOCK_TEXT: - { - fz_text_block *block = page->blocks[block_n].u.text; - fz_text_line *line; - char *s; - - fz_printf(out, "\n", - block->bbox.x0, block->bbox.y0, block->bbox.x1, block->bbox.y1); - for (line = block->lines; line < block->lines + block->len; line++) - { - fz_text_span *span; - fz_printf(out, "\n", - line->bbox.x0, line->bbox.y0, line->bbox.x1, line->bbox.y1); - for (span = line->first_span; span; span = span->next) - { - fz_text_style *style = NULL; - int char_num; - for (char_num = 0; char_num < span->len; char_num++) - { - fz_text_char *ch = &span->text[char_num]; - if (ch->style != style) - { - if (style) - { - fz_printf(out, "\n"); - } - style = ch->style; - s = strchr(style->font->name, '+'); - s = s ? s + 1 : style->font->name; - fz_printf(out, "\n", - span->bbox.x0, span->bbox.y0, span->bbox.x1, span->bbox.y1, - s, style->size); - } - { - fz_rect rect; - fz_text_char_bbox(&rect, span, char_num); - fz_printf(out, "p.x, ch->p.y); - } - switch (ch->c) - { - case '<': fz_printf(out, "<"); break; - case '>': fz_printf(out, ">"); break; - case '&': fz_printf(out, "&"); break; - case '"': fz_printf(out, """); break; - case '\'': fz_printf(out, "'"); break; - default: - if (ch->c >= 32 && ch->c <= 127) - fz_printf(out, "%c", ch->c); - else - fz_printf(out, "&#x%x;", ch->c); - break; - } - fz_printf(out, "\"/>\n"); - } - if (style) - fz_printf(out, "\n"); - } - fz_printf(out, "\n"); - } - fz_printf(out, "\n"); - break; - } - case FZ_PAGE_BLOCK_IMAGE: - { - break; - } - } - } - fz_printf(out, "\n"); -} - -void -fz_print_text_page(fz_context *ctx, fz_output *out, fz_text_page *page) -{ - int block_n; - - for (block_n = 0; block_n < page->len; block_n++) - { - switch (page->blocks[block_n].type) - { - case FZ_PAGE_BLOCK_TEXT: - { - fz_text_block *block = page->blocks[block_n].u.text; - fz_text_line *line; - fz_text_char *ch; - char utf[10]; - int i, n; - - for (line = block->lines; line < block->lines + block->len; line++) - { - fz_text_span *span; - for (span = line->first_span; span; span = span->next) - { - for (ch = span->text; ch < span->text + span->len; ch++) - { - n = fz_runetochar(utf, ch->c); - for (i = 0; i < n; i++) - fz_printf(out, "%c", utf[i]); - } - } - fz_printf(out, "\n"); - } - fz_printf(out, "\n"); - break; - } - case FZ_PAGE_BLOCK_IMAGE: - break; - } - } -} diff --git a/fitz/text_paragraph.c b/fitz/text_paragraph.c deleted file mode 100644 index 51062938..00000000 --- a/fitz/text_paragraph.c +++ /dev/null @@ -1,1500 +0,0 @@ -#include "mupdf/fitz.h" - -/* Assemble span soup into blocks and lines. */ - -#define MY_EPSILON 0.001f - -#undef DEBUG_LINE_HEIGHTS -#undef DEBUG_MASKS -#undef DEBUG_ALIGN -#undef DEBUG_INDENTS - -#undef SPOT_LINE_NUMBERS - -typedef struct line_height_s -{ - float height; - int count; - fz_text_style *style; -} line_height; - -typedef struct line_heights_s -{ - fz_context *ctx; - int cap; - int len; - line_height *lh; -} line_heights; - -static line_heights * -new_line_heights(fz_context *ctx) -{ - line_heights *lh = fz_malloc_struct(ctx, line_heights); - lh->ctx = ctx; - return lh; -} - -static void -free_line_heights(line_heights *lh) -{ - if (!lh) - return; - fz_free(lh->ctx, lh->lh); - fz_free(lh->ctx, lh); -} - -static void -insert_line_height(line_heights *lh, fz_text_style *style, float height) -{ - int i; - -#ifdef DEBUG_LINE_HEIGHTS - printf("style=%x height=%g\n", style, height); -#endif - - /* If we have one already, add it in */ - for (i=0; i < lh->len; i++) - { - /* Match if we are within 5% */ - if (lh->lh[i].style == style && lh->lh[i].height * 0.95 <= height && lh->lh[i].height * 1.05 >= height) - { - /* Ensure that the average height is correct */ - lh->lh[i].height = (lh->lh[i].height * lh->lh[i].count + height) / (lh->lh[i].count+1); - lh->lh[i].count++; - return; - } - } - - /* Otherwise extend (if required) and add it */ - if (lh->cap == lh->len) - { - int newcap = (lh->cap ? lh->cap * 2 : 4); - lh->lh = fz_resize_array(lh->ctx, lh->lh, newcap, sizeof(line_height)); - lh->cap = newcap; - } - - lh->lh[lh->len].count = 1; - lh->lh[lh->len].height = height; - lh->lh[lh->len].style = style; - lh->len++; -} - -static void -cull_line_heights(line_heights *lh) -{ - int i, j, k; - -#ifdef DEBUG_LINE_HEIGHTS - printf("Before culling:\n"); - for (i = 0; i < lh->len; i++) - { - fz_text_style *style = lh->lh[i].style; - printf("style=%x height=%g count=%d\n", style, lh->lh[i].height, lh->lh[i].count); - } -#endif - for (i = 0; i < lh->len; i++) - { - fz_text_style *style = lh->lh[i].style; - int count = lh->lh[i].count; - int max = i; - - /* Find the max for this style */ - for (j = i+1; j < lh->len; j++) - { - if (lh->lh[j].style == style && lh->lh[j].count > count) - { - max = j; - count = lh->lh[j].count; - } - } - - /* Destroy all the ones other than the max */ - if (max != i) - { - lh->lh[i].count = count; - lh->lh[i].height = lh->lh[max].height; - lh->lh[max].count = 0; - } - j = i+1; - for (k = j; k < lh->len; k++) - { - if (lh->lh[k].style != style) - lh->lh[j++] = lh->lh[k]; - } - lh->len = j; - } -#ifdef DEBUG_LINE_HEIGHTS - printf("After culling:\n"); - for (i = 0; i < lh->len; i++) - { - fz_text_style *style = lh->lh[i].style; - printf("style=%x height=%g count=%d\n", style, lh->lh[i].height, lh->lh[i].count); - } -#endif -} - -static float -line_height_for_style(line_heights *lh, fz_text_style *style) -{ - int i; - - for (i=0; i < lh->len; i++) - { - if (lh->lh[i].style == style) - return lh->lh[i].height; - } - return 0.0; /* Never reached */ -} - -static void -split_block(fz_context *ctx, fz_text_page *page, int block_num, int linenum) -{ - int split_len; - fz_text_block *block, *block2; - - if (page->len == page->cap) - { - int new_cap = fz_maxi(16, page->cap * 2); - page->blocks = fz_resize_array(ctx, page->blocks, new_cap, sizeof(*page->blocks)); - page->cap = new_cap; - } - - memmove(page->blocks+block_num+1, page->blocks+block_num, (page->len - block_num)*sizeof(*page->blocks)); - page->len++; - - block2 = fz_malloc_struct(ctx, fz_text_block); - block = page->blocks[block_num].u.text; - - page->blocks[block_num+1].type = FZ_PAGE_BLOCK_TEXT; - page->blocks[block_num+1].u.text = block2; - split_len = block->len - linenum; - block2->bbox = block->bbox; /* FIXME! */ - block2->cap = 0; - block2->len = 0; - block2->lines = NULL; - block2->lines = fz_malloc_array(ctx, split_len, sizeof(fz_text_line)); - block2->cap = block2->len; - block2->len = split_len; - block->len = linenum; - memcpy(block2->lines, block->lines + linenum, split_len * sizeof(fz_text_line)); - block2->lines[0].distance = 0; -} - -static inline int -is_unicode_wspace(int c) -{ - return (c == 9 || /* TAB */ - c == 0x0a || /* HT */ - c == 0x0b || /* LF */ - c == 0x0c || /* VT */ - c == 0x0d || /* FF */ - c == 0x20 || /* CR */ - c == 0x85 || /* NEL */ - c == 0xA0 || /* No break space */ - c == 0x1680 || /* Ogham space mark */ - c == 0x180E || /* Mongolian Vowel Separator */ - c == 0x2000 || /* En quad */ - c == 0x2001 || /* Em quad */ - c == 0x2002 || /* En space */ - c == 0x2003 || /* Em space */ - c == 0x2004 || /* Three-per-Em space */ - c == 0x2005 || /* Four-per-Em space */ - c == 0x2006 || /* Five-per-Em space */ - c == 0x2007 || /* Figure space */ - c == 0x2008 || /* Punctuation space */ - c == 0x2009 || /* Thin space */ - c == 0x200A || /* Hair space */ - c == 0x2028 || /* Line separator */ - c == 0x2029 || /* Paragraph separator */ - c == 0x202F || /* Narrow no-break space */ - c == 0x205F || /* Medium mathematical space */ - c == 0x3000); /* Ideographic space */ -} - -static inline int -is_unicode_bullet(int c) -{ - /* The last 2 aren't strictly bullets, but will do for our usage here */ - return (c == 0x2022 || /* Bullet */ - c == 0x2023 || /* Triangular bullet */ - c == 0x25e6 || /* White bullet */ - c == 0x2043 || /* Hyphen bullet */ - c == 0x2219 || /* Bullet operator */ - c == 149 || /* Ascii bullet */ - c == '*'); -} - -static inline int -is_number(int c) -{ - return ((c >= '0' && c <= '9') || - (c == '.')); -} - -static inline int -is_latin_char(int c) -{ - return ((c >= 'A' && c <= 'Z') || - (c >= 'a' && c <= 'z')); -} - -static inline int -is_roman(int c) -{ - return (c == 'i' || c == 'I' || - c == 'v' || c == 'V' || - c == 'x' || c == 'X' || - c == 'l' || c == 'L' || - c == 'c' || c == 'C' || - c == 'm' || c == 'M'); -} - -static int -is_list_entry(fz_text_line *line, fz_text_span *span, int *char_num_ptr) -{ - int char_num; - fz_text_char *chr; - - /* First, skip over any whitespace */ - for (char_num = 0; char_num < span->len; char_num++) - { - chr = &span->text[char_num]; - if (!is_unicode_wspace(chr->c)) - break; - } - *char_num_ptr = char_num; - - if (span != line->first_span || char_num >= span->len) - return 0; - - /* Now we check for various special cases, which we consider to mean - * that this is probably a list entry and therefore should always count - * as a separate paragraph (and hence not be entered in the line height - * table). */ - chr = &span->text[char_num]; - - /* Is the first char on the line, a bullet point? */ - if (is_unicode_bullet(chr->c)) - return 1; - -#ifdef SPOT_LINE_NUMBERS - /* Is the entire first span a number? Or does it start with a number - * followed by ) or : ? Allow to involve single latin chars too. */ - if (is_number(chr->c) || is_latin_char(chr->c)) - { - int cn = char_num; - int met_char = is_latin_char(chr->c); - for (cn = char_num+1; cn < span->len; cn++) - { - fz_text_char *chr2 = &span->text[cn]; - - if (is_latin_char(chr2->c) && !met_char) - { - met_char = 1; - continue; - } - met_char = 0; - if (!is_number(chr2->c) && !is_unicode_wspace(chr2->c)) - break; - else if (chr2->c == ')' || chr2->c == ':') - { - cn = span->len; - break; - } - } - if (cn == span->len) - return 1; - } - - /* Is the entire first span a roman numeral? Or does it start with - * a roman numeral followed by ) or : ? */ - if (is_roman(chr->c)) - { - int cn = char_num; - for (cn = char_num+1; cn < span->len; cn++) - { - fz_text_char *chr2 = &span->text[cn]; - - if (!is_roman(chr2->c) && !is_unicode_wspace(chr2->c)) - break; - else if (chr2->c == ')' || chr2->c == ':') - { - cn = span->len; - break; - } - } - if (cn == span->len) - return 1; - } -#endif - return 0; -} - -typedef struct region_masks_s region_masks; - -typedef struct region_mask_s region_mask; - -typedef struct region_s region; - -struct region_s -{ - float start; - float stop; - float ave_start; - float ave_stop; - int align; - float colw; -}; - -struct region_mask_s -{ - fz_context *ctx; - int freq; - fz_point blv; - int cap; - int len; - float size; - region *mask; -}; - -struct region_masks_s -{ - fz_context *ctx; - int cap; - int len; - region_mask **mask; -}; - -static region_masks * -new_region_masks(fz_context *ctx) -{ - region_masks *rms = fz_malloc_struct(ctx, region_masks); - rms->ctx = ctx; - rms->cap = 0; - rms->len = 0; - rms->mask = NULL; - return rms; -} - -static void -free_region_mask(region_mask *rm) -{ - if (!rm) - return; - fz_free(rm->ctx, rm->mask); - fz_free(rm->ctx, rm); -} - -static void -free_region_masks(region_masks *rms) -{ - int i; - - if (!rms) - return; - for (i=0; i < rms->len; i++) - { - free_region_mask(rms->mask[i]); - } - fz_free(rms->ctx, rms->mask); - fz_free(rms->ctx, rms); -} - -static int region_masks_mergeable(const region_mask *rm1, const region_mask *rm2, float *score) -{ - int i1, i2; - int count = 0; - - *score = 0; - if (fabsf(rm1->blv.x-rm2->blv.x) >= MY_EPSILON || fabsf(rm1->blv.y-rm2->blv.y) >= MY_EPSILON) - return 0; - - for (i1 = 0, i2 = 0; i1 < rm1->len && i2 < rm2->len; ) - { - if (rm1->mask[i1].stop < rm2->mask[i2].start) - { - /* rm1's region is entirely before rm2's */ - *score += rm1->mask[i1].stop - rm1->mask[i1].start; - i1++; - } - else if (rm1->mask[i1].start > rm2->mask[i2].stop) - { - /* rm2's region is entirely before rm1's */ - *score += rm2->mask[i2].stop - rm2->mask[i2].start; - i2++; - } - else - { - float lscore, rscore; - if (rm1->mask[i1].start < rm2->mask[i2].start) - { - if (i2 > 0 && rm2->mask[i2-1].stop >= rm1->mask[i1].start) - return 0; /* Not compatible */ - lscore = rm2->mask[i2].start - rm1->mask[i1].start; - } - else - { - if (i1 > 0 && rm1->mask[i1-1].stop >= rm2->mask[i2].start) - return 0; /* Not compatible */ - lscore = rm1->mask[i1].start - rm2->mask[i2].start; - } - if (rm1->mask[i1].stop > rm2->mask[i2].stop) - { - if (i2+1 < rm2->len && rm2->mask[i2+1].start <= rm1->mask[i1].stop) - return 0; /* Not compatible */ - rscore = rm1->mask[i1].stop - rm2->mask[i2].stop; - } - else - { - if (i1+1 < rm1->len && rm1->mask[i1+1].start <= rm2->mask[i2].stop) - return 0; /* Not compatible */ - rscore = rm2->mask[i2].stop - rm1->mask[i1].stop; - } - /* In order to allow a region to merge, either the - * left, the right, or the centre must agree */ - if (lscore < 1) - { - if (rscore < 1) - { - rscore = 0; - } - lscore = 0; - } - else if (rscore < 1) - { - rscore = 0; - } - else - { - /* Neither Left or right agree. Does the centre? */ - float ave1 = rm1->mask[i1].start + rm1->mask[i1].stop; - float ave2 = rm2->mask[i2].start + rm2->mask[i2].stop; - if (fabsf(ave1-ave2) > 1) - { - /* Nothing agrees, so don't merge */ - return 0; - } - lscore = 0; - rscore = 0; - } - *score += lscore + rscore; - /* These two regions could be merged */ - i1++; - i2++; - } - count++; - } - count += rm1->len-i1 + rm2->len-i2; - return count; -} - -static int region_mask_matches(const region_mask *rm1, const region_mask *rm2, float *score) -{ - int i1, i2; - int close = 1; - - *score = 0; - if (fabsf(rm1->blv.x-rm2->blv.x) >= MY_EPSILON || fabsf(rm1->blv.y-rm2->blv.y) >= MY_EPSILON) - return 0; - - for (i1 = 0, i2 = 0; i1 < rm1->len && i2 < rm2->len; ) - { - if (rm1->mask[i1].stop < rm2->mask[i2].start) - { - /* rm1's region is entirely before rm2's */ - *score += rm1->mask[i1].stop - rm1->mask[i1].start; - i1++; - } - else if (rm1->mask[i1].start > rm2->mask[i2].stop) - { - /* Not compatible */ - return 0; - } - else - { - float lscore, rscore; - if (rm1->mask[i1].start > rm2->mask[i2].start) - { - /* Not compatible */ - return 0; - } - if (rm1->mask[i1].stop < rm2->mask[i2].stop) - { - /* Not compatible */ - return 0; - } - lscore = rm2->mask[i2].start - rm1->mask[i1].start; - rscore = rm1->mask[i1].stop - rm2->mask[i2].stop; - if (lscore < 1) - { - if (rscore < 1) - close++; - close++; - } - else if (rscore < 1) - close++; - else if (fabsf(lscore - rscore) < 1) - { - lscore = fabsf(lscore-rscore); - rscore = 0; - close++; - } - *score += lscore + rscore; - i1++; - i2++; - } - } - if (i1 < rm1->len) - { - /* Still more to go in rm1 */ - if (rm1->mask[i1].start < rm2->mask[rm2->len-1].stop) - return 0; - } - else if (i2 < rm2->len) - { - /* Still more to go in rm2 */ - if (rm2->mask[i2].start < rm1->mask[rm1->len-1].stop) - return 0; - } - - return close; -} - -static void region_mask_merge(region_mask *rm1, const region_mask *rm2, int newlen) -{ - int o, i1, i2; - - /* First, ensure that rm1 is long enough */ - if (rm1->cap < newlen) - { - int newcap = rm1->cap ? rm1->cap : 2; - do - { - newcap *= 2; - } - while (newcap < newlen); - rm1->mask = fz_resize_array(rm1->ctx, rm1->mask, newcap, sizeof(*rm1->mask)); - rm1->cap = newcap; - } - - /* Now run backwards along rm1, filling it out with the merged regions */ - for (o = newlen-1, i1 = rm1->len-1, i2 = rm2->len-1; o >= 0; o--) - { - /* So we read from i1 and i2 and store in o */ - if (i1 < 0) - { - /* Just copy i2 */ - rm1->mask[o] = rm2->mask[i2]; - i2--; - } - else if (i2 < 0) - { - /* Just copy i1 */ - rm1->mask[o] = rm1->mask[i1]; - i1--; - } - else if (rm1->mask[i1].stop < rm2->mask[i2].start) - { - /* rm1's region is entirely before rm2's - copy rm2's */ - rm1->mask[o] = rm2->mask[i2]; - i2--; - } - else if (rm2->mask[i2].stop < rm1->mask[i1].start) - { - /* rm2's region is entirely before rm1's - copy rm1's */ - rm1->mask[o] = rm1->mask[i1]; - i1--; - } - else - { - /* We must be merging */ - rm1->mask[o].ave_start = (rm1->mask[i1].start * rm1->freq + rm2->mask[i2].start * rm2->freq)/(rm1->freq + rm2->freq); - rm1->mask[o].ave_stop = (rm1->mask[i1].stop * rm1->freq + rm2->mask[i2].stop * rm2->freq)/(rm1->freq + rm2->freq); - rm1->mask[o].start = fz_min(rm1->mask[i1].start, rm2->mask[i2].start); - rm1->mask[o].stop = fz_max(rm1->mask[i1].stop, rm2->mask[i2].stop); - i1--; - i2--; - } - } - rm1->freq += rm2->freq; - rm1->len = newlen; -} - -static region_mask *region_masks_match(const region_masks *rms, const region_mask *rm, fz_text_line *line, region_mask *prev_match) -{ - int i; - float best_score = 9999999; - float score; - int best = -1; - int best_count = 0; - - /* If the 'previous match' matches, use it regardless. */ - if (prev_match && region_mask_matches(prev_match, rm, &score)) - { - return prev_match; - } - - /* Run through and find the 'most compatible' region mask. We are - * guaranteed that there will always be at least one compatible one! - */ - for (i=0; i < rms->len; i++) - { - int count = region_mask_matches(rms->mask[i], rm, &score); - if (count > best_count || (count == best_count && (score < best_score || best == -1))) - { - best = i; - best_score = score; - best_count = count; - } - } - assert(best >= 0 && best < rms->len); - - /* So we have the matching mask. */ - return rms->mask[best]; -} - -#ifdef DEBUG_MASKS -static void -dump_region_mask(const region_mask *rm) -{ - int j; - for (j = 0; j < rm->len; j++) - { - printf("%g->%g ", rm->mask[j].start, rm->mask[j].stop); - } - printf("* %d\n", rm->freq); -} - -static void -dump_region_masks(const region_masks *rms) -{ - int i; - - for (i = 0; i < rms->len; i++) - { - region_mask *rm = rms->mask[i]; - dump_region_mask(rm); - } -} -#endif - -static void region_masks_add(region_masks *rms, region_mask *rm) -{ - /* Add rm to rms */ - if (rms->len == rms->cap) - { - int newcap = (rms->cap ? rms->cap * 2 : 4); - rms->mask = fz_resize_array(rms->ctx, rms->mask, newcap, sizeof(*rms->mask)); - rms->cap = newcap; - } - rms->mask[rms->len] = rm; - rms->len++; -} - -static void region_masks_sort(region_masks *rms) -{ - int i, j; - - /* First calculate sizes */ - for (i=0; i < rms->len; i++) - { - region_mask *rm = rms->mask[i]; - float size = 0; - for (j=0; j < rm->len; j++) - { - size += rm->mask[j].stop - rm->mask[j].start; - } - rm->size = size; - } - - /* Now, sort on size */ - /* FIXME: bubble sort - use heapsort for efficiency */ - for (i=0; i < rms->len-1; i++) - { - for (j=i+1; j < rms->len; j++) - { - if (rms->mask[i]->size < rms->mask[j]->size) - { - region_mask *tmp = rms->mask[i]; - rms->mask[i] = rms->mask[j]; - rms->mask[j] = tmp; - } - } - } -} - -static void region_masks_merge(region_masks *rms, region_mask *rm) -{ - int i; - float best_score = 9999999; - float score; - int best = -1; - int best_count = 0; - -#ifdef DEBUG_MASKS - printf("\nAdding:\n"); - dump_region_mask(rm); - printf("To:\n"); - dump_region_masks(rms); -#endif - for (i=0; i < rms->len; i++) - { - int count = region_masks_mergeable(rms->mask[i], rm, &score); - if (count && (score < best_score || best == -1)) - { - best = i; - best_count = count; - best_score = score; - } - } - if (best != -1) - { - region_mask_merge(rms->mask[best], rm, best_count); -#ifdef DEBUG_MASKS - printf("Merges to give:\n"); - dump_region_masks(rms); -#endif - free_region_mask(rm); - return; - } - region_masks_add(rms, rm); -#ifdef DEBUG_MASKS - printf("Adding new one to give:\n"); - dump_region_masks(rms); -#endif -} - -static region_mask * -new_region_mask(fz_context *ctx, const fz_point *blv) -{ - region_mask *rm = fz_malloc_struct(ctx, region_mask); - rm->ctx = ctx; - rm->freq = 1; - rm->blv = *blv; - rm->cap = 0; - rm->len = 0; - rm->mask = NULL; - return rm; -} - -static void -region_mask_project(const region_mask *rm, const fz_point *min, const fz_point *max, float *start, float *end) -{ - /* We project min and max down onto the blv */ - float s = min->x * rm->blv.x + min->y * rm->blv.y; - float e = max->x * rm->blv.x + max->y * rm->blv.y; - if (s > e) - { - *start = e; - *end = s; - } - else - { - *start = s; - *end = e; - } -} - -static void -region_mask_add(region_mask *rm, const fz_point *min, const fz_point *max) -{ - float start, end; - int i, j; - - region_mask_project(rm, min, max, &start, &end); - - /* Now add start/end into our region list. Typically we will be adding - * to the end of the region list, so search from there backwards. */ - for (i = rm->len; i > 0;) - { - if (start > rm->mask[i-1].stop) - break; - i--; - } - /* So we know that our interval can only affect list items >= i. - * We know that start is after our previous end. */ - if (i == rm->len || end < rm->mask[i].start) - { - /* Insert new one. No overlap. No merging */ - if (rm->len == rm->cap) - { - int newcap = (rm->cap ? rm->cap * 2 : 4); - rm->mask = fz_resize_array(rm->ctx, rm->mask, newcap, sizeof(*rm->mask)); - rm->cap = newcap; - } - if (rm->len > i) - memmove(&rm->mask[i+1], &rm->mask[i], (rm->len - i) * sizeof(*rm->mask)); - rm->mask[i].ave_start = start; - rm->mask[i].ave_stop = end; - rm->mask[i].start = start; - rm->mask[i].stop = end; - rm->len++; - } - else - { - /* Extend current one down. */ - rm->mask[i].ave_start = start; - rm->mask[i].start = start; - if (rm->mask[i].stop < end) - { - rm->mask[i].stop = end; - rm->mask[i].ave_stop = end; - /* Our region may now extend upwards too far */ - i++; - j = i; - while (j < rm->len && rm->mask[j].start <= end) - { - rm->mask[i-1].stop = end = rm->mask[j].stop; - j++; - } - if (i != j) - { - /* Move everything from j down to i */ - while (j < rm->len) - { - rm->mask[i++] = rm->mask[j++]; - } - } - rm->len -= j-i; - } - } -} - -static int -region_mask_column(region_mask *rm, const fz_point *min, const fz_point *max, int *align, float *colw, float *left_) -{ - float start, end, left, right; - int i; - - region_mask_project(rm, min, max, &start, &end); - - for (i = 0; i < rm->len; i++) - { - /* The use of MY_EPSILON here is because we might be matching - * start/end values calculated with slightly different blv's */ - if (rm->mask[i].start - MY_EPSILON <= start && rm->mask[i].stop + MY_EPSILON >= end) - break; - } - if (i >= rm->len) - { - *align = 0; - *colw = 0; - return 0; - } - left = start - rm->mask[i].start; - right = rm->mask[i].stop - end; - if (left < 1 && right < 1) - *align = rm->mask[i].align; - else if (left*2 <= right) - *align = 0; /* Left */ - else if (right * 2 < left) - *align = 2; /* Right */ - else - *align = 1; - *left_ = left; - *colw = rm->mask[i].colw; - return i; -} - -static void -region_mask_alignment(region_mask *rm) -{ - int i; - float width = 0; - - for (i = 0; i < rm->len; i++) - { - width += rm->mask[i].stop - rm->mask[i].start; - } - for (i = 0; i < rm->len; i++) - { - region *r = &rm->mask[i]; - float left = r->ave_start - r->start; - float right = r->stop - r->ave_stop; - if (left*2 <= right) - r->align = 0; /* Left */ - else if (right * 2 < left) - r->align = 2; /* Right */ - else - r->align = 1; - r->colw = 100 * (rm->mask[i].stop - rm->mask[i].start) / width; - } -} - -static void -region_masks_alignment(region_masks *rms) -{ - int i; - - for (i = 0; i < rms->len; i++) - { - region_mask_alignment(rms->mask[i]); - } -} - -static int -is_unicode_hyphen(int c) -{ - /* We omit 0x2011 (Non breaking hyphen) and 0x2043 (Hyphen Bullet) - * from this list. */ - return (c == '-' || - c == 0x2010 || /* Hyphen */ - c == 0x002d || /* Hyphen-Minus */ - c == 0x00ad || /* Soft hyphen */ - c == 0x058a || /* Armenian Hyphen */ - c == 0x1400 || /* Canadian Syllabive Hyphen */ - c == 0x1806); /* Mongolian Todo soft hyphen */ -} - -static int -is_unicode_hyphenatable(int c) -{ - /* This is a pretty ad-hoc collection. It may need tuning. */ - return ((c >= 'A' && c <= 'Z') || - (c >= 'a' && c <= 'z') || - (c >= 0x00c0 && c <= 0x00d6) || - (c >= 0x00d8 && c <= 0x00f6) || - (c >= 0x00f8 && c <= 0x02af) || - (c >= 0x1d00 && c <= 0x1dbf) || - (c >= 0x1e00 && c <= 0x1eff) || - (c >= 0x2c60 && c <= 0x2c7f) || - (c >= 0xa722 && c <= 0xa78e) || - (c >= 0xa790 && c <= 0xa793) || - (c >= 0xa7a8 && c <= 0xa7af) || - (c >= 0xfb00 && c <= 0xfb07) || - (c >= 0xff21 && c <= 0xff3a) || - (c >= 0xff41 && c <= 0xff5a)); -} - -static void -dehyphenate(fz_text_span *s1, fz_text_span *s2) -{ - int i; - - for (i = s1->len-1; i > 0; i--) - if (!is_unicode_wspace(s1->text[i].c)) - break; - /* Can't leave an empty span. */ - if (i == 0) - return; - - if (!is_unicode_hyphen(s1->text[i].c)) - return; - if (!is_unicode_hyphenatable(s1->text[i-1].c)) - return; - if (!is_unicode_hyphenatable(s2->text[0].c)) - return; - s1->len = i; - s2->spacing = 0; -} - -void -fz_analyze_text(fz_context *ctx, fz_text_sheet *sheet, fz_text_page *page) -{ - fz_text_line *line; - fz_text_span *span; - line_heights *lh; - region_masks *rms; - int block_num; - - /* Simple paragraph analysis; look for the most common 'inter line' - * spacing. This will be assumed to be our line spacing. Anything - * more than 25% wider than this will be assumed to be a paragraph - * space. */ - - /* Step 1: Gather the line height information */ - lh = new_line_heights(ctx); - for (block_num = 0; block_num < page->len; block_num++) - { - fz_text_block *block; - - if (page->blocks[block_num].type != FZ_PAGE_BLOCK_TEXT) - continue; - block = page->blocks[block_num].u.text; - - for (line = block->lines; line < block->lines + block->len; line++) - { - /* For every style in the line, add lineheight to the - * record for that style. FIXME: This is a nasty n^2 - * algorithm at the moment. */ - fz_text_style *style = NULL; - - if (line->distance == 0) - continue; - - for (span = line->first_span; span; span = span->next) - { - int char_num; - - if (is_list_entry(line, span, &char_num)) - goto list_entry; - - for (; char_num < span->len; char_num++) - { - fz_text_char *chr = &span->text[char_num]; - - /* Ignore any whitespace chars */ - if (is_unicode_wspace(chr->c)) - continue; - - if (chr->style != style) - { - /* Have we had this style before? */ - int match = 0; - fz_text_span *span2; - for (span2 = line->first_span; span2; span2 = span2->next) - { - int char_num2; - for (char_num2 = 0; char_num2 < span2->len; char_num2++) - { - fz_text_char *chr2 = &span2->text[char_num2]; - if (chr2->style == chr->style) - { - match = 1; - break; - } - } - } - if (char_num > 0 && match == 0) - { - fz_text_span *span2 = span; - int char_num2; - for (char_num2 = 0; char_num2 < char_num; char_num2++) - { - fz_text_char *chr2 = &span2->text[char_num2]; - if (chr2->style == chr->style) - { - match = 1; - break; - } - } - } - if (match == 0) - insert_line_height(lh, chr->style, line->distance); - style = chr->style; - } - } -list_entry: - {} - } - } - } - - /* Step 2: Find the most popular line height for each style */ - cull_line_heights(lh); - - /* Step 3: Run through the blocks, breaking each block into two if - * the line height isn't right. */ - for (block_num = 0; block_num < page->len; block_num++) - { - int line_num; - fz_text_block *block; - - if (page->blocks[block_num].type != FZ_PAGE_BLOCK_TEXT) - continue; - block = page->blocks[block_num].u.text; - - for (line_num = 0; line_num < block->len; line_num++) - { - /* For every style in the line, check to see if lineheight - * is correct for that style. FIXME: We check each style - * more than once, currently. */ - int ok = 0; /* -1 = early exit, split now. 0 = split. 1 = don't split. */ - fz_text_style *style = NULL; - line = &block->lines[line_num]; - - if (line->distance == 0) - continue; - -#ifdef DEBUG_LINE_HEIGHTS - printf("line height=%g nspans=%d\n", line->distance, line->len); -#endif - for (span = line->first_span; span; span = span->next) - { - int char_num; - - if (is_list_entry(line, span, &char_num)) - goto force_paragraph; - - /* Now we do the rest of the line */ - for (; char_num < span->len; char_num++) - { - fz_text_char *chr = &span->text[char_num]; - - /* Ignore any whitespace chars */ - if (is_unicode_wspace(chr->c)) - continue; - - if (chr->style != style) - { - float proper_step = line_height_for_style(lh, chr->style); - if (proper_step * 0.95 <= line->distance && line->distance <= proper_step * 1.05) - { - ok = 1; - break; - } - style = chr->style; - } - } - if (ok) - break; - } - if (!ok) - { -force_paragraph: - split_block(ctx, page, block_num, line_num); - break; - } - } - } - free_line_heights(lh); - - /* Simple line region analysis: - * For each line: - * form a list of 'start/stop' points (henceforth a 'region mask') - * find the normalised baseline vector for the line. - * Store the region mask and baseline vector. - * Collate lines that have compatible region masks and identical - * baseline vectors. - * If the collated masks are column-like, then split into columns. - * Otherwise split into tables. - */ - rms = new_region_masks(ctx); - - /* Step 1: Form the region masks and store them into a list with the - * normalised baseline vectors. */ - for (block_num = 0; block_num < page->len; block_num++) - { - fz_text_block *block; - - if (page->blocks[block_num].type != FZ_PAGE_BLOCK_TEXT) - continue; - block = page->blocks[block_num].u.text; - - for (line = block->lines; line < block->lines + block->len; line++) - { - fz_point blv; - region_mask *rm; - -#ifdef DEBUG_MASKS - printf("Line: "); - dump_line(line); -#endif - blv = line->first_span->max; - blv.x -= line->first_span->min.x; - blv.y -= line->first_span->min.y; - fz_normalize_vector(&blv); - - rm = new_region_mask(ctx, &blv); - for (span = line->first_span; span; span = span->next) - { - fz_point *region_min = &span->min; - fz_point *region_max = &span->max; - - /* Treat adjacent spans as one big region */ - while (span->next && span->next->spacing < 1.5) - { - span = span->next; - region_max = &span->max; - } - - region_mask_add(rm, region_min, region_max); - } -#ifdef DEBUG_MASKS - dump_region_mask(rm); -#endif - region_masks_add(rms, rm); - } - } - - /* Step 2: Sort the region_masks by size of masked region */ - region_masks_sort(rms); - -#ifdef DEBUG_MASKS - printf("Sorted list of regions:\n"); - dump_region_masks(rms); -#endif - /* Step 3: Merge the region masks where possible (large ones first) */ - { - int i; - region_masks *rms2; - rms2 = new_region_masks(ctx); - for (i=0; i < rms->len; i++) - { - region_mask *rm = rms->mask[i]; - rms->mask[i] = NULL; - region_masks_merge(rms2, rm); - } - free_region_masks(rms); - rms = rms2; - } - -#ifdef DEBUG_MASKS - printf("Merged list of regions:\n"); - dump_region_masks(rms); -#endif - - /* Step 4: Figure out alignment */ - region_masks_alignment(rms); - - /* Step 5: At this point, we should probably look at the region masks - * to try to guess which ones represent columns on the page. With our - * current code, we could only get blocks of lines that span 2 or more - * columns if the PDF producer wrote text out horizontally across 2 - * or more columns, and we've never seen that (yet!). So we skip this - * step for now. */ - - /* Step 6: Run through the lines again, deciding which ones fit into - * which region mask. */ - { - region_mask *prev_match = NULL; - for (block_num = 0; block_num < page->len; block_num++) - { - fz_text_block *block; - - if (page->blocks[block_num].type != FZ_PAGE_BLOCK_TEXT) - continue; - block = page->blocks[block_num].u.text; - - for (line = block->lines; line < block->lines + block->len; line++) - { - fz_point blv; - region_mask *rm; - region_mask *match; - - blv = line->first_span->max; - blv.x -= line->first_span->min.x; - blv.y -= line->first_span->min.y; - fz_normalize_vector(&blv); - -#ifdef DEBUG_MASKS - dump_line(line); -#endif - rm = new_region_mask(ctx, &blv); - for (span = line->first_span; span; span = span->next) - { - fz_point *region_min = &span->min; - fz_point *region_max = &span->max; - - /* Treat adjacent spans as one big region */ - while (span->next && span->next->spacing < 1.5) - { - span = span->next; - region_max = &span->max; - } - - region_mask_add(rm, region_min, region_max); - } -#ifdef DEBUG_MASKS - printf("Mask: "); - dump_region_mask(rm); -#endif - match = region_masks_match(rms, rm, line, prev_match); - prev_match = match; -#ifdef DEBUG_MASKS - printf("Matches: "); - dump_region_mask(match); -#endif - free_region_mask(rm); - span = line->first_span; - while (span) - { - fz_point *region_min = &span->min; - fz_point *region_max = &span->max; - fz_text_span *sn; - int col, align; - float colw, left; - - /* Treat adjacent spans as one big region */ -#ifdef DEBUG_ALIGN - dump_span(span); -#endif - for (sn = span->next; sn && sn->spacing < 1.5; sn = sn->next) - { - region_max = &sn->max; -#ifdef DEBUG_ALIGN - dump_span(sn); -#endif - } - col = region_mask_column(match, region_min, region_max, &align, &colw, &left); -#ifdef DEBUG_ALIGN - printf(" = col%d colw=%g align=%d\n", col, colw, align); -#endif - do - { - span->column = col; - span->align = align; - span->indent = left; - span->column_width = colw; - span = span->next; - } - while (span != sn); - - if (span) - span = span->next; - } - line->region = match; - } - } - free_region_masks(rms); - } - - /* Step 7: Collate lines within a block that share the same region - * mask. */ - for (block_num = 0; block_num < page->len; block_num++) - { - int line_num; - int prev_line_num; - - fz_text_block *block; - - if (page->blocks[block_num].type != FZ_PAGE_BLOCK_TEXT) - continue; - block = page->blocks[block_num].u.text; - - /* First merge lines. This may leave empty lines behind. */ - for (prev_line_num = 0, line_num = 1; line_num < block->len; line_num++) - { - fz_text_line *prev_line; - line = &block->lines[line_num]; - if (!line->first_span) - continue; - prev_line = &block->lines[prev_line_num]; - if (prev_line->region == line->region) - { - /* We only merge lines if the second line - * only uses 1 of the columns. */ - int col = line->first_span->column; - /* Copy the left value for the first span - * in the first column in this line forward - * for all the rest of the spans in the same - * column. */ - float indent = line->first_span->indent; - for (span = line->first_span->next; span; span = span->next) - { - if (col != span->column) - break; - span->indent = indent; - } - if (span) - { - prev_line_num = line_num; - continue; - } - - /* Merge line into prev_line */ - { - fz_text_span **prev_line_span = &prev_line->first_span; - int try_dehyphen = -1; - fz_text_span *prev_span = NULL; - span = line->first_span; - while (span) - { - /* Skip forwards through the original - * line, until we find a place where - * span should go. */ - if ((*prev_line_span)->column <= span->column) - { - /* The current span we are considering - * in prev_line is earlier than span. - * Just skip forwards in prev_line. */ - prev_span = (*prev_line_span); - prev_line_span = &prev_span->next; - try_dehyphen = span->column; - } - else - { - /* We want to copy span into prev_line. */ - fz_text_span *next = (*prev_line_span)->next; - - if (prev_line_span == &prev_line->first_span) - prev_line->first_span = span; - if (next == NULL) - prev_line->last_span = span; - if (try_dehyphen == span->column) - dehyphenate(prev_span, span); - try_dehyphen = -1; - prev_span = *prev_line_span = span; - span = span->next; - (*prev_line_span)->next = next; - prev_line_span = &span->next; - } - } - while (span || *prev_line_span); - line->first_span = NULL; - line->last_span = NULL; - } - } - else - prev_line_num = line_num; - } - - /* Now get rid of the empty lines */ - for (prev_line_num = 0, line_num = 0; line_num < block->len; line_num++) - { - line = &block->lines[line_num]; - if (line->first_span) - block->lines[prev_line_num++] = *line; - } - block->len = prev_line_num; - - /* Now try to spot indents */ - for (line_num = 0; line_num < block->len; line_num++) - { - fz_text_span *span_num, *sn; - int col, count; - line = &block->lines[line_num]; - - /* Run through the spans... */ - span_num = line->first_span; - { - float indent = 0; - /* For each set of spans that share the same - * column... */ - col = span_num->column; -#ifdef DEBUG_INDENTS - printf("Indent %g: ", span_num->indent); - dump_span(span_num); - printf("\n"); -#endif - - /* find the average indent of all but the first.. */ - for (sn = span_num->next, count = 0; sn && sn->column == col; sn = sn->next, count++) - { -#ifdef DEBUG_INDENTS - printf("Indent %g: ", sn->indent); - dump_span(sn); - printf("\n"); -#endif - indent += sn->indent; - sn->indent = 0; - } - if (sn != span_num->next) - indent /= count; - - /* And compare this indent with the first one... */ -#ifdef DEBUG_INDENTS - printf("Average indent %g ", indent); -#endif - indent -= span_num->indent; -#ifdef DEBUG_INDENTS - printf("delta %g ", indent); -#endif - if (fabsf(indent) < 1) - { - /* No indent worth speaking of */ - indent = 0; - } -#ifdef DEBUG_INDENTS - printf("recorded %g\n", indent); -#endif - span_num->indent = indent; - span_num = sn; - } - for (; span_num; span_num = span_num->next) - { - span_num->indent = 0; - } - } - } -} diff --git a/fitz/text_search.c b/fitz/text_search.c deleted file mode 100644 index f1f0d203..00000000 --- a/fitz/text_search.c +++ /dev/null @@ -1,279 +0,0 @@ -#include "mupdf/fitz.h" - -static inline int fz_tolower(int c) -{ - /* TODO: proper unicode case folding */ - if (c >= 'A' && c <= 'Z') - return c - 'A' + 'a'; - return c; -} - -static inline int iswhite(int c) -{ - return c == ' ' || c == '\r' || c == '\n' || c == '\t'; -} - -fz_char_and_box *fz_text_char_at(fz_char_and_box *cab, fz_text_page *page, int idx) -{ - int block_num; - int ofs = 0; - - for (block_num = 0; block_num < page->len; block_num++) - { - fz_text_block *block; - fz_text_line *line; - fz_text_span *span; - - if (page->blocks[block_num].type != FZ_PAGE_BLOCK_TEXT) - continue; - block = page->blocks[block_num].u.text; - for (line = block->lines; line < block->lines + block->len; line++) - { - for (span = line->first_span; span; span = span->next) - { - if (idx < ofs + span->len) - { - cab->c = span->text[idx - ofs].c; - fz_text_char_bbox(&cab->bbox, span, idx - ofs); - return cab; - } - ofs += span->len; - } - /* pseudo-newline */ - if (idx == ofs) - { - cab->bbox = fz_empty_rect; - cab->c = ' '; - return cab; - } - ofs++; - } - } - cab->bbox = fz_empty_rect; - cab->c = 0; - return cab; -} - -static int charat(fz_text_page *page, int idx) -{ - fz_char_and_box cab; - return fz_text_char_at(&cab, page, idx)->c; -} - -static fz_rect *bboxat(fz_text_page *page, int idx, fz_rect *bbox) -{ - fz_char_and_box cab; - /* FIXME: Nasty extra copy */ - *bbox = fz_text_char_at(&cab, page, idx)->bbox; - return bbox; -} - -static int textlen(fz_text_page *page) -{ - int len = 0; - int block_num; - - for (block_num = 0; block_num < page->len; block_num++) - { - fz_text_block *block; - fz_text_line *line; - fz_text_span *span; - - if (page->blocks[block_num].type != FZ_PAGE_BLOCK_TEXT) - continue; - block = page->blocks[block_num].u.text; - for (line = block->lines; line < block->lines + block->len; line++) - { - for (span = line->first_span; span; span = span->next) - { - len += span->len; - } - len++; /* pseudo-newline */ - } - } - return len; -} - -static int match(fz_text_page *page, const char *s, int n) -{ - int orig = n; - int c; - while (*s) - { - s += fz_chartorune(&c, (char *)s); - if (iswhite(c) && iswhite(charat(page, n))) - { - const char *s_next; - - /* Skip over whitespace in the document */ - do - n++; - while (iswhite(charat(page, n))); - - /* Skip over multiple whitespace in the search string */ - while (s_next = s + fz_chartorune(&c, (char *)s), iswhite(c)) - s = s_next; - } - else - { - if (fz_tolower(c) != fz_tolower(charat(page, n))) - return 0; - n++; - } - } - return n - orig; -} - -int -fz_search_text_page(fz_context *ctx, fz_text_page *text, const char *needle, fz_rect *hit_bbox, int hit_max) -{ - int pos, len, i, n, hit_count; - - if (strlen(needle) == 0) - return 0; - - hit_count = 0; - len = textlen(text); - for (pos = 0; pos < len; pos++) - { - n = match(text, needle, pos); - if (n) - { - fz_rect linebox = fz_empty_rect; - for (i = 0; i < n; i++) - { - fz_rect charbox; - bboxat(text, pos + i, &charbox); - if (!fz_is_empty_rect(&charbox)) - { - if (charbox.y0 != linebox.y0 || fz_abs(charbox.x0 - linebox.x1) > 5) - { - if (!fz_is_empty_rect(&linebox) && hit_count < hit_max) - hit_bbox[hit_count++] = linebox; - linebox = charbox; - } - else - { - fz_union_rect(&linebox, &charbox); - } - } - } - if (!fz_is_empty_rect(&linebox) && hit_count < hit_max) - hit_bbox[hit_count++] = linebox; - } - } - - return hit_count; -} - -int -fz_highlight_selection(fz_context *ctx, fz_text_page *page, fz_rect rect, fz_rect *hit_bbox, int hit_max) -{ - fz_rect linebox, charbox; - fz_text_block *block; - fz_text_line *line; - fz_text_span *span; - int i, block_num, hit_count; - - float x0 = rect.x0; - float x1 = rect.x1; - float y0 = rect.y0; - float y1 = rect.y1; - - hit_count = 0; - - for (block_num = 0; block_num < page->len; block_num++) - { - if (page->blocks[block_num].type != FZ_PAGE_BLOCK_TEXT) - continue; - block = page->blocks[block_num].u.text; - for (line = block->lines; line < block->lines + block->len; line++) - { - linebox = fz_empty_rect; - for (span = line->first_span; span; span = span->next) - { - for (i = 0; i < span->len; i++) - { - fz_text_char_bbox(&charbox, span, i); - if (charbox.x1 >= x0 && charbox.x0 <= x1 && charbox.y1 >= y0 && charbox.y0 <= y1) - { - if (charbox.y0 != linebox.y0 || fz_abs(charbox.x0 - linebox.x1) > 5) - { - if (!fz_is_empty_rect(&linebox) && hit_count < hit_max) - hit_bbox[hit_count++] = linebox; - linebox = charbox; - } - else - { - fz_union_rect(&linebox, &charbox); - } - } - } - } - if (!fz_is_empty_rect(&linebox) && hit_count < hit_max) - hit_bbox[hit_count++] = linebox; - } - } - - return hit_count; -} - -char * -fz_copy_selection(fz_context *ctx, fz_text_page *page, fz_rect rect) -{ - fz_buffer *buffer; - fz_rect hitbox; - int c, i, block_num, seen = 0; - char *s; - - float x0 = rect.x0; - float x1 = rect.x1; - float y0 = rect.y0; - float y1 = rect.y1; - - buffer = fz_new_buffer(ctx, 1024); - - for (block_num = 0; block_num < page->len; block_num++) - { - fz_text_block *block; - fz_text_line *line; - fz_text_span *span; - - if (page->blocks[block_num].type != FZ_PAGE_BLOCK_TEXT) - continue; - block = page->blocks[block_num].u.text; - for (line = block->lines; line < block->lines + block->len; line++) - { - for (span = line->first_span; span; span = span->next) - { - if (seen) - { - fz_write_buffer_byte(ctx, buffer, '\n'); - } - - seen = 0; - - for (i = 0; i < span->len; i++) - { - fz_text_char_bbox(&hitbox, span, i); - c = span->text[i].c; - if (c < 32) - c = '?'; - if (hitbox.x1 >= x0 && hitbox.x0 <= x1 && hitbox.y1 >= y0 && hitbox.y0 <= y1) - { - fz_write_buffer_rune(ctx, buffer, c); - seen = 1; - } - } - - seen = (seen && span == line->last_span); - } - } - } - - fz_write_buffer_byte(ctx, buffer, 0); - - s = (char*)buffer->data; - fz_free(ctx, buffer); - return s; -} -- cgit v1.2.3