From f744dace3f0f91b8505979bf244453c9ec713b4b Mon Sep 17 00:00:00 2001 From: Tor Andersson Date: Sat, 28 Feb 2009 13:00:34 +0100 Subject: Moved Fitz files into one directory. --- Jamfile | 6 +- apps/Jamfile | 2 +- base/Jamfile | 23 -- base/base_cleanname.c | 52 --- base/base_cpudep.c | 326 ---------------- base/base_error.c | 71 ---- base/base_hash.c | 276 -------------- base/base_matrix.c | 183 --------- base/base_memory.c | 79 ---- base/base_rect.c | 75 ---- base/base_rune.c | 174 --------- base/util_getopt.c | 117 ------ base/util_gettimeofday.c | 50 --- base/util_strlcpy.c | 65 ---- base/util_strsep.c | 11 - fitz/Jamfile | 102 +++++ fitz/base_cleanname.c | 52 +++ fitz/base_cpudep.c | 326 ++++++++++++++++ fitz/base_error.c | 71 ++++ fitz/base_hash.c | 276 ++++++++++++++ fitz/base_matrix.c | 183 +++++++++ fitz/base_memory.c | 79 ++++ fitz/base_rect.c | 75 ++++ fitz/base_rune.c | 174 +++++++++ fitz/crypt_arc4.c | 100 +++++ fitz/crypt_crc32.c | 86 +++++ fitz/crypt_md5.c | 274 ++++++++++++++ fitz/filt_a85d.c | 128 +++++++ fitz/filt_a85e.c | 126 ++++++ fitz/filt_ahxd.c | 112 ++++++ fitz/filt_ahxe.c | 64 ++++ fitz/filt_arc4.c | 47 +++ fitz/filt_dctc.h | 39 ++ fitz/filt_dctd.c | 232 ++++++++++++ fitz/filt_dcte.c | 254 +++++++++++++ fitz/filt_faxc.h | 125 ++++++ fitz/filt_faxd.c | 470 +++++++++++++++++++++++ fitz/filt_faxd.h | 61 +++ fitz/filt_faxdtab.c | 931 +++++++++++++++++++++++++++++++++++++++++++++ fitz/filt_faxe.c | 407 ++++++++++++++++++++ fitz/filt_faxe.h | 37 ++ fitz/filt_faxetab.c | 131 +++++++ fitz/filt_flate.c | 208 ++++++++++ fitz/filt_jbig2d.c | 119 ++++++ fitz/filt_jpxd.c | 146 +++++++ fitz/filt_lzwd.c | 254 +++++++++++++ fitz/filt_lzwe.c | 261 +++++++++++++ fitz/filt_null.c | 54 +++ fitz/filt_pipeline.c | 139 +++++++ fitz/filt_predict.c | 254 +++++++++++++ fitz/filt_rld.c | 73 ++++ fitz/filt_rle.c | 238 ++++++++++++ fitz/node_misc1.c | 155 ++++++++ fitz/node_misc2.c | 296 +++++++++++++++ fitz/node_optimize.c | 235 ++++++++++++ fitz/node_path.c | 347 +++++++++++++++++ fitz/node_text.c | 143 +++++++ fitz/node_toxml.c | 185 +++++++++ fitz/node_tree.c | 108 ++++++ fitz/obj_array.c | 230 +++++++++++ fitz/obj_dict.c | 399 +++++++++++++++++++ fitz/obj_parse.c | 492 ++++++++++++++++++++++++ fitz/obj_print.c | 339 +++++++++++++++++ fitz/obj_simple.c | 323 ++++++++++++++++ fitz/res_colorspace.c | 88 +++++ fitz/res_font.c | 408 ++++++++++++++++++++ fitz/res_image.c | 23 ++ fitz/res_shade.c | 29 ++ fitz/stm_buffer.c | 105 +++++ fitz/stm_filter.c | 61 +++ fitz/stm_misc.c | 97 +++++ fitz/stm_open.c | 242 ++++++++++++ fitz/stm_read.c | 313 +++++++++++++++ fitz/stm_write.c | 313 +++++++++++++++ fitz/util_getopt.c | 117 ++++++ fitz/util_gettimeofday.c | 50 +++ fitz/util_strlcpy.c | 65 ++++ fitz/util_strsep.c | 11 + fitzdraw/Jamfile | 21 + fitzdraw/archppc.c | 67 ++++ fitzdraw/archsparc.c | 23 ++ fitzdraw/archx86.c | 232 ++++++++++++ fitzdraw/blendmodes.c | 213 +++++++++++ fitzdraw/glyphcache.c | 406 ++++++++++++++++++++ fitzdraw/imagedraw.c | 242 ++++++++++++ fitzdraw/imagescale.c | 358 +++++++++++++++++ fitzdraw/imageunpack.c | 233 ++++++++++++ fitzdraw/meshdraw.c | 408 ++++++++++++++++++++ fitzdraw/pathfill.c | 134 +++++++ fitzdraw/pathscan.c | 531 ++++++++++++++++++++++++++ fitzdraw/pathstroke.c | 737 +++++++++++++++++++++++++++++++++++ fitzdraw/pixmap.c | 188 +++++++++ fitzdraw/porterduff.c | 361 ++++++++++++++++++ fitzdraw/render.c | 969 +++++++++++++++++++++++++++++++++++++++++++++++ fonts/Jamfile | 9 +- raster/Jamfile | 21 - raster/archppc.c | 67 ---- raster/archsparc.c | 23 -- raster/archx86.c | 232 ------------ raster/blendmodes.c | 213 ----------- raster/glyphcache.c | 406 -------------------- raster/imagedraw.c | 242 ------------ raster/imagescale.c | 358 ----------------- raster/imageunpack.c | 233 ------------ raster/meshdraw.c | 408 -------------------- raster/pathfill.c | 134 ------- raster/pathscan.c | 531 -------------------------- raster/pathstroke.c | 737 ----------------------------------- raster/pixmap.c | 188 --------- raster/porterduff.c | 361 ------------------ raster/render.c | 969 ----------------------------------------------- stream/Jamfile | 47 --- stream/crypt_arc4.c | 100 ----- stream/crypt_crc32.c | 86 ----- stream/crypt_md5.c | 274 -------------- stream/filt_a85d.c | 128 ------- stream/filt_a85e.c | 126 ------ stream/filt_ahxd.c | 112 ------ stream/filt_ahxe.c | 64 ---- stream/filt_arc4.c | 47 --- stream/filt_dctc.h | 39 -- stream/filt_dctd.c | 232 ------------ stream/filt_dcte.c | 254 ------------- stream/filt_faxc.h | 125 ------ stream/filt_faxd.c | 470 ----------------------- stream/filt_faxd.h | 61 --- stream/filt_faxdtab.c | 931 --------------------------------------------- stream/filt_faxe.c | 407 -------------------- stream/filt_faxe.h | 37 -- stream/filt_faxetab.c | 131 ------- stream/filt_flate.c | 208 ---------- stream/filt_jbig2d.c | 119 ------ stream/filt_jpxd.c | 146 ------- stream/filt_lzwd.c | 254 ------------- stream/filt_lzwe.c | 261 ------------- stream/filt_null.c | 54 --- stream/filt_pipeline.c | 139 ------- stream/filt_predict.c | 254 ------------- stream/filt_rld.c | 73 ---- stream/filt_rle.c | 238 ------------ stream/obj_array.c | 230 ----------- stream/obj_dict.c | 399 ------------------- stream/obj_parse.c | 492 ------------------------ stream/obj_print.c | 339 ----------------- stream/obj_simple.c | 323 ---------------- stream/stm_buffer.c | 105 ----- stream/stm_filter.c | 61 --- stream/stm_misc.c | 97 ----- stream/stm_open.c | 242 ------------ stream/stm_read.c | 313 --------------- stream/stm_write.c | 313 --------------- world/Jamfile | 19 - world/node_misc1.c | 155 -------- world/node_misc2.c | 296 --------------- world/node_optimize.c | 235 ------------ world/node_path.c | 347 ----------------- world/node_text.c | 143 ------- world/node_tolisp.c | 192 ---------- world/node_toxml.c | 185 --------- world/node_tree.c | 108 ------ world/res_colorspace.c | 88 ----- world/res_font.c | 408 -------------------- world/res_image.c | 23 -- world/res_shade.c | 29 -- 164 files changed, 17014 insertions(+), 17192 deletions(-) delete mode 100644 base/Jamfile delete mode 100644 base/base_cleanname.c delete mode 100644 base/base_cpudep.c delete mode 100644 base/base_error.c delete mode 100644 base/base_hash.c delete mode 100644 base/base_matrix.c delete mode 100644 base/base_memory.c delete mode 100644 base/base_rect.c delete mode 100644 base/base_rune.c delete mode 100644 base/util_getopt.c delete mode 100644 base/util_gettimeofday.c delete mode 100644 base/util_strlcpy.c delete mode 100644 base/util_strsep.c create mode 100644 fitz/Jamfile create mode 100644 fitz/base_cleanname.c create mode 100644 fitz/base_cpudep.c create mode 100644 fitz/base_error.c create mode 100644 fitz/base_hash.c create mode 100644 fitz/base_matrix.c create mode 100644 fitz/base_memory.c create mode 100644 fitz/base_rect.c create mode 100644 fitz/base_rune.c create mode 100644 fitz/crypt_arc4.c create mode 100644 fitz/crypt_crc32.c create mode 100644 fitz/crypt_md5.c create mode 100644 fitz/filt_a85d.c create mode 100644 fitz/filt_a85e.c create mode 100644 fitz/filt_ahxd.c create mode 100644 fitz/filt_ahxe.c create mode 100644 fitz/filt_arc4.c create mode 100644 fitz/filt_dctc.h create mode 100644 fitz/filt_dctd.c create mode 100644 fitz/filt_dcte.c create mode 100644 fitz/filt_faxc.h create mode 100644 fitz/filt_faxd.c create mode 100644 fitz/filt_faxd.h create mode 100644 fitz/filt_faxdtab.c create mode 100644 fitz/filt_faxe.c create mode 100644 fitz/filt_faxe.h create mode 100644 fitz/filt_faxetab.c create mode 100644 fitz/filt_flate.c create mode 100644 fitz/filt_jbig2d.c create mode 100644 fitz/filt_jpxd.c create mode 100644 fitz/filt_lzwd.c create mode 100644 fitz/filt_lzwe.c create mode 100644 fitz/filt_null.c create mode 100644 fitz/filt_pipeline.c create mode 100644 fitz/filt_predict.c create mode 100644 fitz/filt_rld.c create mode 100644 fitz/filt_rle.c create mode 100644 fitz/node_misc1.c create mode 100644 fitz/node_misc2.c create mode 100644 fitz/node_optimize.c create mode 100644 fitz/node_path.c create mode 100644 fitz/node_text.c create mode 100644 fitz/node_toxml.c create mode 100644 fitz/node_tree.c create mode 100644 fitz/obj_array.c create mode 100644 fitz/obj_dict.c create mode 100644 fitz/obj_parse.c create mode 100644 fitz/obj_print.c create mode 100644 fitz/obj_simple.c create mode 100644 fitz/res_colorspace.c create mode 100644 fitz/res_font.c create mode 100644 fitz/res_image.c create mode 100644 fitz/res_shade.c create mode 100644 fitz/stm_buffer.c create mode 100644 fitz/stm_filter.c create mode 100644 fitz/stm_misc.c create mode 100644 fitz/stm_open.c create mode 100644 fitz/stm_read.c create mode 100644 fitz/stm_write.c create mode 100644 fitz/util_getopt.c create mode 100644 fitz/util_gettimeofday.c create mode 100644 fitz/util_strlcpy.c create mode 100644 fitz/util_strsep.c create mode 100644 fitzdraw/Jamfile create mode 100644 fitzdraw/archppc.c create mode 100644 fitzdraw/archsparc.c create mode 100644 fitzdraw/archx86.c create mode 100644 fitzdraw/blendmodes.c create mode 100644 fitzdraw/glyphcache.c create mode 100644 fitzdraw/imagedraw.c create mode 100644 fitzdraw/imagescale.c create mode 100644 fitzdraw/imageunpack.c create mode 100644 fitzdraw/meshdraw.c create mode 100644 fitzdraw/pathfill.c create mode 100644 fitzdraw/pathscan.c create mode 100644 fitzdraw/pathstroke.c create mode 100644 fitzdraw/pixmap.c create mode 100644 fitzdraw/porterduff.c create mode 100644 fitzdraw/render.c delete mode 100644 raster/Jamfile delete mode 100644 raster/archppc.c delete mode 100644 raster/archsparc.c delete mode 100644 raster/archx86.c delete mode 100644 raster/blendmodes.c delete mode 100644 raster/glyphcache.c delete mode 100644 raster/imagedraw.c delete mode 100644 raster/imagescale.c delete mode 100644 raster/imageunpack.c delete mode 100644 raster/meshdraw.c delete mode 100644 raster/pathfill.c delete mode 100644 raster/pathscan.c delete mode 100644 raster/pathstroke.c delete mode 100644 raster/pixmap.c delete mode 100644 raster/porterduff.c delete mode 100644 raster/render.c delete mode 100644 stream/Jamfile delete mode 100644 stream/crypt_arc4.c delete mode 100644 stream/crypt_crc32.c delete mode 100644 stream/crypt_md5.c delete mode 100644 stream/filt_a85d.c delete mode 100644 stream/filt_a85e.c delete mode 100644 stream/filt_ahxd.c delete mode 100644 stream/filt_ahxe.c delete mode 100644 stream/filt_arc4.c delete mode 100644 stream/filt_dctc.h delete mode 100644 stream/filt_dctd.c delete mode 100644 stream/filt_dcte.c delete mode 100644 stream/filt_faxc.h delete mode 100644 stream/filt_faxd.c delete mode 100644 stream/filt_faxd.h delete mode 100644 stream/filt_faxdtab.c delete mode 100644 stream/filt_faxe.c delete mode 100644 stream/filt_faxe.h delete mode 100644 stream/filt_faxetab.c delete mode 100644 stream/filt_flate.c delete mode 100644 stream/filt_jbig2d.c delete mode 100644 stream/filt_jpxd.c delete mode 100644 stream/filt_lzwd.c delete mode 100644 stream/filt_lzwe.c delete mode 100644 stream/filt_null.c delete mode 100644 stream/filt_pipeline.c delete mode 100644 stream/filt_predict.c delete mode 100644 stream/filt_rld.c delete mode 100644 stream/filt_rle.c delete mode 100644 stream/obj_array.c delete mode 100644 stream/obj_dict.c delete mode 100644 stream/obj_parse.c delete mode 100644 stream/obj_print.c delete mode 100644 stream/obj_simple.c delete mode 100644 stream/stm_buffer.c delete mode 100644 stream/stm_filter.c delete mode 100644 stream/stm_misc.c delete mode 100644 stream/stm_open.c delete mode 100644 stream/stm_read.c delete mode 100644 stream/stm_write.c delete mode 100644 world/Jamfile delete mode 100644 world/node_misc1.c delete mode 100644 world/node_misc2.c delete mode 100644 world/node_optimize.c delete mode 100644 world/node_path.c delete mode 100644 world/node_text.c delete mode 100644 world/node_tolisp.c delete mode 100644 world/node_toxml.c delete mode 100644 world/node_tree.c delete mode 100644 world/res_colorspace.c delete mode 100644 world/res_font.c delete mode 100644 world/res_image.c delete mode 100644 world/res_shade.c diff --git a/Jamfile b/Jamfile index 851379d2..6fd4a7b9 100644 --- a/Jamfile +++ b/Jamfile @@ -13,10 +13,8 @@ HDRS = [ FDirName $(TOP) include ] ; Main hexdump : hexdump.c ; Main strdump : strdump.c ; -SubInclude TOP base ; -SubInclude TOP stream ; -SubInclude TOP world ; -SubInclude TOP raster ; +SubInclude TOP fitz ; +SubInclude TOP fitzdraw ; SubInclude TOP fonts ; SubInclude TOP cmaps ; diff --git a/apps/Jamfile b/apps/Jamfile index 84c02f2c..f7b5391d 100644 --- a/apps/Jamfile +++ b/apps/Jamfile @@ -1,6 +1,6 @@ # -FITZLIBS = libmupdf libbase libstream libworld libraster libfonts libcmaps ; +FITZLIBS = libmupdf libfitz libfitzdraw libfonts libcmaps ; SubDir TOP apps ; Main mupdftool : pdftool.c ; diff --git a/base/Jamfile b/base/Jamfile deleted file mode 100644 index 0b9e1239..00000000 --- a/base/Jamfile +++ /dev/null @@ -1,23 +0,0 @@ -SubDir TOP base ; - -Library libbase : - base_cpudep.c - base_error.c - base_hash.c - base_matrix.c - base_memory.c - base_rect.c - base_rune.c - base_cleanname.c - ; - -if $(NEED_STRLCPY) { Library libbase : util_strlcpy.c ; } -if $(NEED_STRSEP) { Library libbase : util_strsep.c ; } -if $(NEED_GETOPT) { Library libbase : util_getopt.c ; } - -# MSVC does not have gettimeofday() -if $(OS) = NT -{ - Library libbase : util_gettimeofday.c ; -} - diff --git a/base/base_cleanname.c b/base/base_cleanname.c deleted file mode 100644 index 54764630..00000000 --- a/base/base_cleanname.c +++ /dev/null @@ -1,52 +0,0 @@ -/* - * In place, rewrite name to compress multiple /, eliminate ., and process .. - */ - -#define SEP(x) ((x)=='/' || (x) == 0) - -char * -cleanname(char *name) -{ - char *p, *q, *dotdot; - int rooted; - - rooted = name[0] == '/'; - - /* - * invariants: - * p points at beginning of path element we're considering. - * q points just past the last path element we wrote (no slash). - * dotdot points just past the point where .. cannot backtrack - * any further (no slash). - */ - p = q = dotdot = name+rooted; - while(*p) { - if(p[0] == '/') /* null element */ - p++; - else if(p[0] == '.' && SEP(p[1])) - p += 1; /* don't count the separator in case it is nul */ - else if(p[0] == '.' && p[1] == '.' && SEP(p[2])) { - p += 2; - if(q > dotdot) { /* can backtrack */ - while(--q > dotdot && *q != '/') - ; - } else if(!rooted) { /* /.. is / but ./../ is .. */ - if(q != name) - *q++ = '/'; - *q++ = '.'; - *q++ = '.'; - dotdot = q; - } - } else { /* real path element */ - if(q != name+rooted) - *q++ = '/'; - while((*q = *p) != '/' && *q != 0) - p++, q++; - } - } - if(q == name) /* empty string is really ``.'' */ - *q++ = '.'; - *q = '\0'; - return name; -} - diff --git a/base/base_cpudep.c b/base/base_cpudep.c deleted file mode 100644 index 51273a59..00000000 --- a/base/base_cpudep.c +++ /dev/null @@ -1,326 +0,0 @@ -/* -run-time cpu feature detection code -mm, alphabet soup... - -Glenn Kennard -*/ - -#include "fitz-base.h" - -/* global run-time constant */ -unsigned fz_cpuflags = 0; - -#ifndef HAVE_CPUDEP - -void fz_accelerate(void) -{ -} - -void fz_cpudetect(void) -{ -} - -#else - -#ifndef WIN32 -#include /* signal/sigaction */ -#include /* sigsetjmp/siglongjmp */ -#endif - -/* -#ifdef WIN32 -#define sigjmp_buf jmp_buf -#define sigsetjmp(a,b) setjmp(a) -#define siglongjmp longjmp -#endif -*/ - -typedef struct { - void (*test)(void); - const unsigned flag; - const char *name; -} featuretest; - - -#if defined(ARCH_X86) || defined(ARCH_X86_64) - -#ifdef __GNUC__ -static void mmx(void) -{ __asm__ ("pand %mm0, %mm0\n\t"); } - -static void m3dnow(void) -{ __asm__ ("pavgusb %mm0, %mm0\n\t"); } - -static void mmxext(void) /* aka Extended 3DNow! */ -{ __asm__ ("pmaxsw %mm0, %mm0\n\t"); } - -static void sse(void) -{ __asm__ ("andps %xmm0, %xmm0\n\t"); } - -static void sse2(void) -{ __asm__ ("andpd %xmm0, %xmm0\n\t"); } - -/* -static void sse3(void) -{ __asm__ ("haddps %%xmm0, %%xmm0\n\t" : : : "%xmm0"); } -*/ -#else -static void mmx(void) -{ __asm pand mm0, mm0; } - -static void m3dnow(void) -{ __asm pavgusb mm0, mm0; } - -static void mmxext(void) /* aka Extended 3DNow! */ -{ __asm pmaxsw mm0, mm0; } - -static void sse(void) -{ __asm andps xmm0, xmm0; } - -static void sse2(void) -{ __asm andpd xmm0, xmm0; } -#endif - - -#ifdef ARCH_X86_64 -static void amd64(void) -#ifdef __GNUC__ -{ __asm__ ("and %rax, %rax\n\t"); } -#else -{ __asm and rax, rax; } -#endif -#endif - - -static const featuretest features[] = { - { mmx, HAVE_MMX, "mmx" }, - { m3dnow, HAVE_3DNOW, "3dnow" }, - { mmxext, HAVE_MMXEXT, "mmxext" }, - { sse, HAVE_SSE, "sse" }, - { sse2, HAVE_SSE2, "sse2" }, -/* { sse3, HAVE_SSE3, "sse3" }, */ -#ifdef ARCH_X86_64 - { amd64, HAVE_AMD64, "amd64" } -#endif -}; - -#endif - - -#if defined(ARCH_SPARC) -static void vis(void) -/* -Stupidly Sun assembler decides to mark anything using VIS instructions in the -ELF header, which causes link errors if using the following (which also -requires passing -xarch=v8plusa|v9a passed to the assembler so it accepts the -instruction in the first place, v9a for 64 bit binaries): - -{ __asm__ ("fand %f8, %f8, %f8\n\t"); } - -so instead we just emit the opcode directly, bypassing that check. -*/ -{ __asm__ (".word 0x91B20E08"); } - -/* static void vis2(void) -{ __asm__ ("edge8n %%l0, %%l0, %%l0\n\t" : : : "%l0"); } */ - -static const featuretest features[] = { - { vis, HAVE_VIS, "vis" } -}; - -#endif - - -#if defined(ARCH_PPC) - -static void altivec(void) -{ __asm__ ("vand v0, v0, v0\n\t"); } - - -static const featuretest features[] = { - { altivec, HAVE_ALTIVEC, "altivec" }, -}; - -#endif - -static int -enabled(char *env, const char *ext) -{ - int len; - char *s; - if (!env) - return 1; - len = strlen(ext); - s = env; - while ((s = strstr(s, ext))) - { - int atstart = s == env || *(s-1) == ',' || *(s-1) == ' '; - s += len; - if (atstart && (*s == ' ' || *s == ',' || *s == '\0')) { - return 1; - } - } - return 0; -} - -static void -dumpflags(void) -{ - unsigned f = fz_cpuflags; - int i, n; - - fputs("detected cpu features:", stdout); - n = 0; - for (i = 0; i < sizeof(features) / sizeof(featuretest); i++) - { - if (f & features[i].flag) - { - fputc(' ', stdout); - fputs(features[i].name, stdout); - n ++; - } - } - if (!n) - fputs(" none", stdout); - fputc('\n', stdout); -} - -#ifndef WIN32 - -static sigjmp_buf jmpbuf; -static volatile sig_atomic_t canjump; - -static void -sigillhandler(int sig) -{ - if (!canjump) { - signal(sig, SIG_DFL); - raise(sig); - } - - canjump = 0; - siglongjmp(jmpbuf, 1); -} - -void fz_cpudetect(void) -{ - static int hasrun = 0; - - unsigned flags = 0; - int i; - void (*oldhandler)(int) = NULL; - void (*tmphandler)(int); - char *env; - - if (hasrun) - return; - hasrun = 1; - - env = getenv("CPUACCEL"); - - for (i = 0; i < sizeof(features) / sizeof(featuretest); i++) - { - canjump = 0; - - tmphandler = signal(SIGILL, sigillhandler); - if (!oldhandler) - oldhandler = tmphandler; - - if (sigsetjmp(jmpbuf, 1)) - { - /* test failed - disable feature */ - flags &= ~features[i].flag; - continue; - } - - canjump = 1; - - features[i].test(); - -#if defined(ARCH_X86) || defined(ARCH_X86_64) - /* reset mmx/x87 pipeline state */ - if (features[i].flag & (HAVE_MMX | HAVE_3DNOW | HAVE_MMXEXT)) { - __asm__ __volatile__ ("emms\n\t"); - } -#endif - - /* if we got here the test succeeded */ - if (enabled(env, features[i].name)) - flags |= features[i].flag; - else - flags &= ~features[i].flag; - } - - /* restore previous signal handler */ - signal(SIGILL, oldhandler); - - fz_cpuflags = flags; - -#if defined(ARCH_X86) || defined(ARCH_X86_64) - __asm__ __volatile__ ("emms\n\t"); -#endif - - dumpflags(); -} - -/* -static __attribute__((constructor, used)) void fzcpudetect(void) -{ - fz_cpudetect(); -} -*/ - - -#else /* WIN32 */ - -void fz_cpudetect(void) -{ - static int hasrun = 0; - - unsigned flags = 0; - int i; - char *env; - - if (hasrun) - return; - hasrun = 1; - - env = getenv("CPUACCEL"); - - for (i = 0; i < sizeof(features) / sizeof(featuretest); i++) - { - __try - { - features[i].test(); - } - __except(EXCEPTION_EXECUTE_HANDLER) - { - /* test failed - disable feature */ - flags &= ~features[i].flag; - continue; - } - -#if defined(ARCH_X86) || defined(ARCH_X86_64) - if (features[i].flag & (HAVE_MMX | HAVE_3DNOW | HAVE_MMXEXT)) { - /* reset mmx/x87 pipeline state */ - __asm emms; - } -#endif - - /* if we got here the test succeeded */ - if (enabled(env, features[i].name)) - flags |= features[i].flag; - else - flags &= ~features[i].flag; - } - - fz_cpuflags = flags; - - dumpflags(); -} - - -#endif - -#endif - diff --git a/base/base_error.c b/base/base_error.c deleted file mode 100644 index 461ffc60..00000000 --- a/base/base_error.c +++ /dev/null @@ -1,71 +0,0 @@ -#include "fitz-base.h" - -void -fz_droperror(fz_error *eo) -{ - if (eo->cause) - fz_droperror(eo->cause); - fz_free(eo); -} - -void -fz_printerror(fz_error *eo) -{ -#if 1 - if (eo->cause) - { - fz_printerror(eo->cause); - fprintf(stderr, "| %s:%d: %s(): %s\n", eo->file, eo->line, eo->func, eo->msg); - } - else - { - fprintf(stderr, "+ %s:%d: %s(): %s\n", eo->file, eo->line, eo->func, eo->msg); - } -#else - fprintf(stderr, "+ %s:%d: %s(): %s\n", eo->file, eo->line, eo->func, eo->msg); - eo = eo->cause; - - while (eo) - { - fprintf(stderr, "| %s:%d: %s(): %s\n", eo->file, eo->line, eo->func, eo->msg); - eo = eo->cause; - } -#endif -} - - -void -fz_warn(char *fmt, ...) -{ - va_list ap; - fprintf(stderr, "warning: "); - va_start(ap, fmt); - vfprintf(stderr, fmt, ap); - va_end(ap); - fprintf(stderr, "\n"); -} - -fz_error * -fz_throwimp(fz_error *cause, const char *func, const char *file, int line, char *fmt, ...) -{ - va_list ap; - fz_error *eo; - - eo = fz_malloc(sizeof(fz_error)); - if (!eo) - return fz_outofmem; /* oops. we're *really* out of memory here. */ - - va_start(ap, fmt); - vsnprintf(eo->msg, sizeof eo->msg, fmt, ap); - eo->msg[sizeof(eo->msg) - 1] = '\0'; - va_end(ap); - - strlcpy(eo->func, func, sizeof eo->func); - strlcpy(eo->file, file, sizeof eo->file); - eo->line = line; - - eo->cause = cause; - - return eo; -} - diff --git a/base/base_hash.c b/base/base_hash.c deleted file mode 100644 index c7086ca9..00000000 --- a/base/base_hash.c +++ /dev/null @@ -1,276 +0,0 @@ -/* Linear probe hash table. - * 2004 (C) Tor Andersson. - * BSD license. - * - * Simple hashtable with open adressing 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. - */ - -#include "fitz-base.h" - -enum { MAXKEYLEN = 16 }; - -typedef struct fz_hashentry_s fz_hashentry; - -struct fz_hashentry_s -{ - unsigned char key[MAXKEYLEN]; - void *val; -}; - -struct fz_hashtable_s -{ - int keylen; - int size; - int load; - fz_hashentry *ents; -}; - -static unsigned hash(unsigned char *s, int len) -{ - unsigned hash = 0; - int i; - for (i = 0; i < len; i++) - { - hash += s[i]; - hash += (hash << 10); - hash ^= (hash >> 6); - } - hash += (hash << 3); - hash ^= (hash >> 11); - hash += (hash << 15); - return hash; -} - -fz_error * -fz_newhash(fz_hashtable **tablep, int initialsize, int keylen) -{ - fz_hashtable *table; - - assert(keylen <= MAXKEYLEN); - - table = *tablep = fz_malloc(sizeof(fz_hashtable)); - if (!table) - return fz_throw("outofmem: hash table struct"); - - table->keylen = keylen; - table->size = initialsize; - table->load = 0; - - table->ents = fz_malloc(sizeof(fz_hashentry) * table->size); - if (!table->ents) - { - fz_free(table); - *tablep = nil; - return fz_throw("outofmem: hash table entries (size=%d)", initialsize); - } - - memset(table->ents, 0, sizeof(fz_hashentry) * table->size); - - return fz_okay; -} - -void -fz_emptyhash(fz_hashtable *table) -{ - table->load = 0; - memset(table->ents, 0, sizeof(fz_hashentry) * table->size); -} - -int -fz_hashlen(fz_hashtable *table) -{ - return table->size; -} - -void * -fz_hashgetkey(fz_hashtable *table, int idx) -{ - return table->ents[idx].key; -} - -void * -fz_hashgetval(fz_hashtable *table, int idx) -{ - return table->ents[idx].val; -} - -void -fz_drophash(fz_hashtable *table) -{ - fz_free(table->ents); - fz_free(table); -} - -fz_error * -fz_resizehash(fz_hashtable *table, int newsize) -{ - fz_error *error; - fz_hashentry *newents; - fz_hashentry *oldents; - int oldload; - int oldsize; - int i; - - oldsize = table->size; - oldload = table->load; - oldents = table->ents; - - if (newsize < oldload * 8 / 10) - return fz_throw("assert: resize hash too small"); - - newents = fz_malloc(sizeof(fz_hashentry) * newsize); - if (!newents) - return fz_throw("outofmem: hash table (size=%d)", newsize); - - table->size = newsize; - table->load = 0; - table->ents = newents; - memset(table->ents, 0, sizeof(fz_hashentry) * table->size); - - for (i = 0; i < oldsize; i++) - { - if (oldents[i].val) - { - error = fz_hashinsert(table, oldents[i].key, oldents[i].val); - if (error) - { - table->size = oldsize; - table->load = oldload; - table->ents = oldents; - fz_free(newents); - return fz_rethrow(error, "cannot re-insert old entries"); - } - } - } - - fz_free(oldents); - - return fz_okay; -} - -void * -fz_hashfind(fz_hashtable *table, void *key) -{ - fz_hashentry *ents = table->ents; - unsigned size = table->size; - unsigned pos = hash(key, table->keylen) % size; - - while (1) - { - if (!ents[pos].val) - return nil; - - if (memcmp(key, &ents[pos].key, table->keylen) == 0) - return ents[pos].val; - - pos = (pos + 1) % size; - } -} - -fz_error * -fz_hashinsert(fz_hashtable *table, void *key, void *val) -{ - fz_error *error; - fz_hashentry *ents; - unsigned size; - unsigned pos; - - if (table->load > table->size * 8 / 10) - { - error = fz_resizehash(table, table->size * 2); - if (error) - return fz_rethrow(error, "cannot resize hash table"); - } - - ents = table->ents; - size = table->size; - pos = hash(key, table->keylen) % size; - - while (1) - { - if (!ents[pos].val) - { - memcpy(ents[pos].key, key, table->keylen); - ents[pos].val = val; - table->load ++; - return fz_okay; - } - - if (memcmp(key, &ents[pos].key, table->keylen) == 0) - return fz_throw("assert: overwrite hash slot"); - - pos = (pos + 1) % size; - } - - return fz_okay; -} - -fz_error * -fz_hashremove(fz_hashtable *table, void *key) -{ - fz_hashentry *ents = table->ents; - unsigned size = table->size; - unsigned pos = hash(key, table->keylen) % size; - unsigned hole, look, code; - - while (1) - { - if (!ents[pos].val) - return fz_throw("assert: remove inexistant hash entry"); - - if (memcmp(key, &ents[pos].key, table->keylen) == 0) - { - ents[pos].val = nil; - - hole = pos; - look = (hole + 1) % size; - - 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 = nil; - hole = look; - } - - look = (look + 1) % size; - } - - table->load --; - - return fz_okay; - } - - pos = (pos + 1) % size; - } -} - -void -fz_debughash(fz_hashtable *table) -{ - int i, k; - - printf("cache load %d / %d\n", table->load, table->size); - - for (i = 0; i < table->size; i++) - { - if (!table->ents[i].val) - printf("table % 4d: empty\n", i); - else - { - printf("table % 4d: key=", i); - for (k = 0; k < MAXKEYLEN; k++) - printf("%02x", ((char*)table->ents[i].key)[k]); - printf(" val=$%p\n", table->ents[i].val); - } - } -} - diff --git a/base/base_matrix.c b/base/base_matrix.c deleted file mode 100644 index 364b287c..00000000 --- a/base/base_matrix.c +++ /dev/null @@ -1,183 +0,0 @@ -#include "fitz-base.h" - -void fz_invert3x3(float *dst, float *m) -{ - float det; - int i; - -#define M3(m,i,j) (m)[3*i+j] -#define D2(a,b,c,d) (a * d - b * c) -#define D3(a1,a2,a3,b1,b2,b3,c1,c2,c3) \ - (a1 * D2(b2,b3,c2,c3)) - \ - (b1 * D2(a2,a3,c2,c3)) + \ - (c1 * D2(a2,a3,b2,b3)) - - det = D3(M3(m,0,0), M3(m,1,0), M3(m,2,0), - M3(m,0,1), M3(m,1,1), M3(m,2,1), - M3(m,0,2), M3(m,1,2), M3(m,2,2)); - if (det == 0) - det = 1.0; - det = 1.0 / det; - - M3(dst,0,0) = M3(m,1,1) * M3(m,2,2) - M3(m,1,2) * M3(m,2,1); - M3(dst,0,1) = -M3(m,0,1) * M3(m,2,2) + M3(m,0,2) * M3(m,2,1); - M3(dst,0,2) = M3(m,0,1) * M3(m,1,2) - M3(m,0,2) * M3(m,1,1); - - M3(dst,1,0) = -M3(m,1,0) * M3(m,2,2) + M3(m,1,2) * M3(m,2,0); - M3(dst,1,1) = M3(m,0,0) * M3(m,2,2) - M3(m,0,2) * M3(m,2,0); - M3(dst,1,2) = -M3(m,0,0) * M3(m,1,2) + M3(m,0,2) * M3(m,1,0); - - M3(dst,2,0) = M3(m,1,0) * M3(m,2,1) - M3(m,1,1) * M3(m,2,0); - M3(dst,2,1) = -M3(m,0,0) * M3(m,2,1) + M3(m,0,1) * M3(m,2,0); - M3(dst,2,2) = M3(m,0,0) * M3(m,1,1) - M3(m,0,1) * M3(m,1,0); - - for (i = 0; i < 9; i++) - dst[i] *= det; -} - -fz_matrix -fz_concat(fz_matrix one, fz_matrix two) -{ - fz_matrix dst; - dst.a = one.a * two.a + one.b * two.c; - dst.b = one.a * two.b + one.b * two.d; - dst.c = one.c * two.a + one.d * two.c; - dst.d = one.c * two.b + one.d * two.d; - dst.e = one.e * two.a + one.f * two.c + two.e; - dst.f = one.e * two.b + one.f * two.d + two.f; - return dst; -} - -fz_matrix -fz_identity(void) -{ - fz_matrix m; - m.a = 1; m.b = 0; - m.c = 0; m.d = 1; - m.e = 0; m.f = 0; - return m; -} - -fz_matrix -fz_scale(float sx, float sy) -{ - fz_matrix m; - m.a = sx; m.b = 0; - m.c = 0; m.d = sy; - m.e = 0; m.f = 0; - return m; -} - -fz_matrix -fz_rotate(float theta) -{ - fz_matrix m; - float s; - float c; - - while (theta < 0.0f) - theta += 360.0f; - while (theta >= 360.0f) - theta -= 360.0f; - - if (fabs(0.0f - theta) < FLT_EPSILON) - { - s = 0.0f; - c = 1.0f; - } - else if (fabs(90.0f - theta) < FLT_EPSILON) - { - s = 1.0f; - c = 0.0f; - } - else if (fabs(180.0f - theta) < FLT_EPSILON) - { - s = 0.0f; - c = -1.0f; - } - else if (fabs(270.0f - theta) < FLT_EPSILON) - { - s = -1.0f; - c = 0.0f; - } - else - { - s = sin(theta * M_PI / 180.0); - c = cos(theta * M_PI / 180.0); - } - - m.a = c; m.b = s; - m.c = -s; m.d = c; - m.e = 0; m.f = 0; - return m; -} - -fz_matrix -fz_translate(float tx, float ty) -{ - fz_matrix m; - m.a = 1; m.b = 0; - m.c = 0; m.d = 1; - m.e = tx; m.f = ty; - return m; -} - -fz_matrix -fz_invertmatrix(fz_matrix src) -{ - fz_matrix dst; - float rdet = 1.0 / (src.a * src.d - src.b * src.c); - dst.a = src.d * rdet; - dst.b = -src.b * rdet; - dst.c = -src.c * rdet; - dst.d = src.a * rdet; - dst.e = -src.e * dst.a - src.f * dst.c; - dst.f = -src.e * dst.b - src.f * dst.d; - return dst; -} - -int -fz_isrectilinear(fz_matrix m) -{ - return (fabs(m.b) < FLT_EPSILON && fabs(m.c) < FLT_EPSILON) || - (fabs(m.a) < FLT_EPSILON && fabs(m.d) < FLT_EPSILON); -} - -float -fz_matrixexpansion(fz_matrix m) -{ - return sqrt(fabs(m.a * m.d - m.b * m.c)); -} - -fz_point -fz_transformpoint(fz_matrix m, fz_point p) -{ - fz_point t; - t.x = p.x * m.a + p.y * m.c + m.e; - t.y = p.x * m.b + p.y * m.d + m.f; - return t; -} - -fz_rect -fz_transformaabb(fz_matrix m, fz_rect r) -{ - fz_point s, t, u, v; - - if (fz_isinfiniterect(r)) - 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; - s = fz_transformpoint(m, s); - t = fz_transformpoint(m, t); - u = fz_transformpoint(m, u); - v = fz_transformpoint(m, v); - 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; -} - diff --git a/base/base_memory.c b/base/base_memory.c deleted file mode 100644 index 8c2c0249..00000000 --- a/base/base_memory.c +++ /dev/null @@ -1,79 +0,0 @@ -#include "fitz-base.h" - -/* Make this thread local storage if you wish. */ - -static void *stdmalloc(fz_memorycontext *mem, int n) -{ - return malloc(n); -} - -static void *stdrealloc(fz_memorycontext *mem, void *p, int n) -{ - return realloc(p, n); -} - -static void stdfree(fz_memorycontext *mem, void *p) -{ - free(p); -} - -static fz_memorycontext defmem = { stdmalloc, stdrealloc, stdfree }; -static fz_memorycontext *curmem = &defmem; - -fz_error fz_koutofmem = { - {"out of memory"}, - {""}, - {""}, - 0, - nil -}; - -fz_memorycontext * -fz_currentmemorycontext() -{ - return curmem; -} - -void -fz_setmemorycontext(fz_memorycontext *mem) -{ - curmem = mem; -} - -void * -fz_malloc(int n) -{ - fz_memorycontext *mem = fz_currentmemorycontext(); - void *p = mem->malloc(mem, n); - if (!p) - fz_warn("cannot malloc %d bytes", n); - return p; -} - -void * -fz_realloc(void *p, int n) -{ - fz_memorycontext *mem = fz_currentmemorycontext(); - void *np = mem->realloc(mem, p, n); - if (np == nil) - fz_warn("cannot realloc %d bytes", n); - return np; -} - -void -fz_free(void *p) -{ - fz_memorycontext *mem = fz_currentmemorycontext(); - mem->free(mem, p); -} - -char * -fz_strdup(char *s) -{ - int len = strlen(s); - char *ns = fz_malloc(len + 1); - if (ns) - strcpy(ns, s); - return ns; -} - diff --git a/base/base_rect.c b/base/base_rect.c deleted file mode 100644 index 3c00cb94..00000000 --- a/base/base_rect.c +++ /dev/null @@ -1,75 +0,0 @@ -#include "fitz-base.h" - -fz_rect fz_infiniterect = { 1, 1, -1, -1 }; -fz_rect fz_emptyrect = { 0, 0, 0, 0 }; - -static fz_irect infinite = { 1, 1, -1, -1 }; -static fz_irect empty = { 0, 0, 0, 0 }; - -fz_irect -fz_roundrect(fz_rect f) -{ - fz_irect i; - i.x0 = fz_floor(f.x0); - i.y0 = fz_floor(f.y0); - i.x1 = fz_ceil(f.x1); - i.y1 = fz_ceil(f.y1); - return i; -} - -fz_rect -fz_intersectrects(fz_rect a, fz_rect b) -{ - fz_rect r; - if (fz_isinfiniterect(a)) return b; - if (fz_isinfiniterect(b)) return a; - r.x0 = MAX(a.x0, b.x0); - r.y0 = MAX(a.y0, b.y0); - r.x1 = MIN(a.x1, b.x1); - r.y1 = MIN(a.y1, b.y1); - return (r.x1 < r.x0 || r.y1 < r.y0) ? fz_emptyrect : r; -} - -fz_rect -fz_mergerects(fz_rect a, fz_rect b) -{ - fz_rect r; - if (fz_isinfiniterect(a) || fz_isinfiniterect(b)) - return fz_infiniterect; - if (fz_isemptyrect(a)) return b; - if (fz_isemptyrect(b)) return a; - r.x0 = MIN(a.x0, b.x0); - r.y0 = MIN(a.y0, b.y0); - r.x1 = MAX(a.x1, b.x1); - r.y1 = MAX(a.y1, b.y1); - return r; -} - -fz_irect -fz_intersectirects(fz_irect a, fz_irect b) -{ - fz_irect r; - if (fz_isinfiniterect(a)) return b; - if (fz_isinfiniterect(b)) return a; - r.x0 = MAX(a.x0, b.x0); - r.y0 = MAX(a.y0, b.y0); - r.x1 = MIN(a.x1, b.x1); - r.y1 = MIN(a.y1, b.y1); - return (r.x1 < r.x0 || r.y1 < r.y0) ? empty : r; -} - -fz_irect -fz_mergeirects(fz_irect a, fz_irect b) -{ - fz_irect r; - if (fz_isinfiniterect(a) || fz_isinfiniterect(b)) - return infinite; - if (fz_isemptyrect(a)) return b; - if (fz_isemptyrect(b)) return a; - r.x0 = MIN(a.x0, b.x0); - r.y0 = MIN(a.y0, b.y0); - r.x1 = MAX(a.x1, b.x1); - r.y1 = MAX(a.y1, b.y1); - return r; -} - diff --git a/base/base_rune.c b/base/base_rune.c deleted file mode 100644 index 32168792..00000000 --- a/base/base_rune.c +++ /dev/null @@ -1,174 +0,0 @@ -enum -{ - UTFmax = 3, /* maximum bytes per rune */ - Runesync = 0x80, /* cannot represent part of a UTF sequence (<) */ - Runeself = 0x80, /* rune and UTF sequences are the same (<) */ - Runeerror = 0x80 /* decoding error in UTF */ -}; - -enum -{ - Bit1 = 7, - Bitx = 6, - Bit2 = 5, - Bit3 = 4, - Bit4 = 3, - - 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 */ - - 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 */ - - Maskx = (1< T1 - */ - c = *(unsigned char*)str; - if (c < Tx) - { - *rune = c; - return 1; - } - - /* - * two character sequence - * 0080-07FF => T2 Tx - */ - c1 = *(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 = *(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; - } - - /* - * bad decoding - */ -bad: - *rune = Bad; - return 1; -} - -int -runetochar(char *str, int *rune) -{ - int c; - - /* - * one character sequence - * 00000-0007F => 00-7F - */ - c = *rune; - 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; - } - - /* - * three character sequence - * 0800-FFFF => T3 Tx Tx - */ - str[0] = T3 | (c >> 2*Bitx); - str[1] = Tx | ((c >> 1*Bitx) & Maskx); - str[2] = Tx | (c & Maskx); - return 3; -} - -int -runelen(int c) -{ - int rune; - char str[10]; - - rune = c; - return runetochar(str, &rune); -} - -int -runenlen(int *r, int nrune) -{ - int nb, c; - - nb = 0; - while (nrune--) - { - c = *r++; - if (c <= Rune1) - nb++; - else if (c <= Rune2) - nb += 2; - else - nb += 3; - } - return nb; -} - -int -fullrune(char *str, int n) -{ - int c; - - if (n > 0) - { - c = *(unsigned char*)str; - if (c < Tx) - return 1; - if (n > 1) - if (c < T3 || n > 2) - return 1; - } - return 0; -} - diff --git a/base/util_getopt.c b/base/util_getopt.c deleted file mode 100644 index 8025334e..00000000 --- a/base/util_getopt.c +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright (c) 1987 Regents of the University of California. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. - */ - -#if defined(LIBC_SCCS) && !defined(lint) -static char sccsid[] = "@(#)getopt.c 4.13 (Berkeley) 2/23/91"; -#endif /* LIBC_SCCS and not lint */ - -#include -#include -#include - -/* - * get option letter from argument vector - */ -int opterr = 1, /* if error message should be printed */ - optind = 1, /* index into parent argv vector */ - optopt; /* character checked for validity */ -char *optarg; /* argument associated with option */ - -#define BADCH (int)'?' -#define EMSG "" - -int getopt(int nargc, char * const * nargv, const char *ostr) -{ - static char *place = EMSG; /* option letter processing */ - register char *oli; /* option letter list index */ - char *p; - - if (!*place) { /* update scanning pointer */ - if (optind >= nargc || *(place = nargv[optind]) != '-') { - place = EMSG; - return(EOF); - } - if (place[1] && *++place == '-') { /* found "--" */ - ++optind; - place = EMSG; - return(EOF); - } - } /* option letter okay? */ - if ((optopt = (int)*place++) == (int)':' || - !(oli = strchr(ostr, optopt))) { - /* - * if the user didn't specify '-' as an option, - * assume it means EOF. - */ - if (optopt == (int)'-') - return(EOF); - if (!*place) - ++optind; - if (opterr) { - if (!(p = strrchr(*nargv, '/'))) - p = *nargv; - else - ++p; - (void)fprintf(stderr, "%s: illegal option -- %c\n", - p, optopt); - } - return(BADCH); - } - if (*++oli != ':') { /* don't need argument */ - optarg = NULL; - if (!*place) - ++optind; - } - else { /* need an argument */ - if (*place) /* no white space */ - optarg = place; - else if (nargc <= ++optind) { /* no arg */ - place = EMSG; - if (!(p = strrchr(*nargv, '/'))) - p = *nargv; - else - ++p; - if (opterr) - (void)fprintf(stderr, - "%s: option requires an argument -- %c\n", - p, optopt); - return(BADCH); - } - else /* white space */ - optarg = nargv[optind]; - place = EMSG; - ++optind; - } - return(optopt); /* dump back option letter */ -} - diff --git a/base/util_gettimeofday.c b/base/util_gettimeofday.c deleted file mode 100644 index fee36673..00000000 --- a/base/util_gettimeofday.c +++ /dev/null @@ -1,50 +0,0 @@ -#include -#include -#include - -#if defined(_MSC_VER) || defined(_MSC_EXTENSIONS) - #define DELTA_EPOCH_IN_MICROSECS 11644473600000000Ui64 -#else - #define DELTA_EPOCH_IN_MICROSECS 11644473600000000ULL -#endif - -struct timezone -{ - int tz_minuteswest; /* minutes W of Greenwich */ - int tz_dsttime; /* type of dst correction */ -}; - -int gettimeofday(struct timeval *tv, struct timezone *tz) -{ - FILETIME ft; - unsigned __int64 tmpres = 0; - static int tzflag = 0; - - if (NULL != 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); - } - - if (NULL != tz) - { - if (!tzflag) - { - _tzset(); - tzflag++; - } - tz->tz_minuteswest = _timezone / 60; - tz->tz_dsttime = _daylight; - } - - return 0; -} diff --git a/base/util_strlcpy.c b/base/util_strlcpy.c deleted file mode 100644 index 15b378b2..00000000 --- a/base/util_strlcpy.c +++ /dev/null @@ -1,65 +0,0 @@ -#include - -/* Copy src to string dst of size siz. At most siz-1 characters - * will be copied. Always NUL terminates (unless siz == 0). - * Returns strlen(src); if retval >= siz, truncation occurred. - */ - -int 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 */ -} - -/* Appends src to string dst of size siz (unlike strncat, siz is the - * full size of dst, not space left). At most siz-1 characters - * will be copied. Always NUL terminates (unless siz == 0). - * Returns strlen(src); if retval >= siz, truncation occurred. - */ - -int 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 */ -} - diff --git a/base/util_strsep.c b/base/util_strsep.c deleted file mode 100644 index e54903ce..00000000 --- a/base/util_strsep.c +++ /dev/null @@ -1,11 +0,0 @@ -#include - -char *strsep(char **stringp, const char *delim) -{ - char *ret = *stringp; - if (ret == NULL) return NULL; - if ((*stringp = strpbrk(*stringp, delim)) != NULL) - *((*stringp)++) = '\0'; - return ret; -} - diff --git a/fitz/Jamfile b/fitz/Jamfile new file mode 100644 index 00000000..1cfbd3a5 --- /dev/null +++ b/fitz/Jamfile @@ -0,0 +1,102 @@ +# +# +# + +SubDir TOP fitz ; + +# +# The base runtime support, and patching over +# platform specific wonkyness. +# + +Library libfitz : + base_cpudep.c + base_error.c + base_hash.c + base_matrix.c + base_memory.c + base_rect.c + base_rune.c + base_cleanname.c + ; + +if $(NEED_STRLCPY) { Library libfitz : util_strlcpy.c ; } +if $(NEED_STRSEP) { Library libfitz : util_strsep.c ; } +if $(NEED_GETOPT) { Library libfitz : util_getopt.c ; } + +# MSVC does not have gettimeofday() +if $(OS) = NT +{ + Library libfitz : util_gettimeofday.c ; +} + +# +# Encryption, carousel-object-system, filters, buffers and streams. +# + +Library libfitz : + + crypt_arc4.c + crypt_crc32.c + crypt_md5.c + + obj_array.c + obj_dict.c + obj_parse.c + obj_print.c + obj_simple.c + + stm_buffer.c + stm_filter.c + stm_open.c + stm_read.c + stm_write.c + stm_misc.c + + filt_pipeline.c + filt_arc4.c + filt_null.c + + filt_a85d.c + filt_a85e.c + filt_ahxd.c + filt_ahxe.c + filt_dctd.c + filt_dcte.c + filt_faxd.c + filt_faxdtab.c + filt_faxe.c + filt_faxetab.c + filt_flate.c + filt_lzwd.c + filt_lzwe.c + filt_predict.c + filt_rld.c + filt_rle.c + + ; + +if $(HAVE_JASPER) { Library libstream : filt_jpxd.c ; } +if $(HAVE_JBIG2DEC) { Library libstream : filt_jbig2d.c ; } + +# +# Resources and display tree. +# + +Library libfitz : + + node_toxml.c + node_misc1.c + node_misc2.c + node_optimize.c + node_path.c + node_text.c + node_tree.c + + res_colorspace.c + res_font.c + res_image.c + res_shade.c + + ; + diff --git a/fitz/base_cleanname.c b/fitz/base_cleanname.c new file mode 100644 index 00000000..54764630 --- /dev/null +++ b/fitz/base_cleanname.c @@ -0,0 +1,52 @@ +/* + * In place, rewrite name to compress multiple /, eliminate ., and process .. + */ + +#define SEP(x) ((x)=='/' || (x) == 0) + +char * +cleanname(char *name) +{ + char *p, *q, *dotdot; + int rooted; + + rooted = name[0] == '/'; + + /* + * invariants: + * p points at beginning of path element we're considering. + * q points just past the last path element we wrote (no slash). + * dotdot points just past the point where .. cannot backtrack + * any further (no slash). + */ + p = q = dotdot = name+rooted; + while(*p) { + if(p[0] == '/') /* null element */ + p++; + else if(p[0] == '.' && SEP(p[1])) + p += 1; /* don't count the separator in case it is nul */ + else if(p[0] == '.' && p[1] == '.' && SEP(p[2])) { + p += 2; + if(q > dotdot) { /* can backtrack */ + while(--q > dotdot && *q != '/') + ; + } else if(!rooted) { /* /.. is / but ./../ is .. */ + if(q != name) + *q++ = '/'; + *q++ = '.'; + *q++ = '.'; + dotdot = q; + } + } else { /* real path element */ + if(q != name+rooted) + *q++ = '/'; + while((*q = *p) != '/' && *q != 0) + p++, q++; + } + } + if(q == name) /* empty string is really ``.'' */ + *q++ = '.'; + *q = '\0'; + return name; +} + diff --git a/fitz/base_cpudep.c b/fitz/base_cpudep.c new file mode 100644 index 00000000..51273a59 --- /dev/null +++ b/fitz/base_cpudep.c @@ -0,0 +1,326 @@ +/* +run-time cpu feature detection code +mm, alphabet soup... + +Glenn Kennard +*/ + +#include "fitz-base.h" + +/* global run-time constant */ +unsigned fz_cpuflags = 0; + +#ifndef HAVE_CPUDEP + +void fz_accelerate(void) +{ +} + +void fz_cpudetect(void) +{ +} + +#else + +#ifndef WIN32 +#include /* signal/sigaction */ +#include /* sigsetjmp/siglongjmp */ +#endif + +/* +#ifdef WIN32 +#define sigjmp_buf jmp_buf +#define sigsetjmp(a,b) setjmp(a) +#define siglongjmp longjmp +#endif +*/ + +typedef struct { + void (*test)(void); + const unsigned flag; + const char *name; +} featuretest; + + +#if defined(ARCH_X86) || defined(ARCH_X86_64) + +#ifdef __GNUC__ +static void mmx(void) +{ __asm__ ("pand %mm0, %mm0\n\t"); } + +static void m3dnow(void) +{ __asm__ ("pavgusb %mm0, %mm0\n\t"); } + +static void mmxext(void) /* aka Extended 3DNow! */ +{ __asm__ ("pmaxsw %mm0, %mm0\n\t"); } + +static void sse(void) +{ __asm__ ("andps %xmm0, %xmm0\n\t"); } + +static void sse2(void) +{ __asm__ ("andpd %xmm0, %xmm0\n\t"); } + +/* +static void sse3(void) +{ __asm__ ("haddps %%xmm0, %%xmm0\n\t" : : : "%xmm0"); } +*/ +#else +static void mmx(void) +{ __asm pand mm0, mm0; } + +static void m3dnow(void) +{ __asm pavgusb mm0, mm0; } + +static void mmxext(void) /* aka Extended 3DNow! */ +{ __asm pmaxsw mm0, mm0; } + +static void sse(void) +{ __asm andps xmm0, xmm0; } + +static void sse2(void) +{ __asm andpd xmm0, xmm0; } +#endif + + +#ifdef ARCH_X86_64 +static void amd64(void) +#ifdef __GNUC__ +{ __asm__ ("and %rax, %rax\n\t"); } +#else +{ __asm and rax, rax; } +#endif +#endif + + +static const featuretest features[] = { + { mmx, HAVE_MMX, "mmx" }, + { m3dnow, HAVE_3DNOW, "3dnow" }, + { mmxext, HAVE_MMXEXT, "mmxext" }, + { sse, HAVE_SSE, "sse" }, + { sse2, HAVE_SSE2, "sse2" }, +/* { sse3, HAVE_SSE3, "sse3" }, */ +#ifdef ARCH_X86_64 + { amd64, HAVE_AMD64, "amd64" } +#endif +}; + +#endif + + +#if defined(ARCH_SPARC) +static void vis(void) +/* +Stupidly Sun assembler decides to mark anything using VIS instructions in the +ELF header, which causes link errors if using the following (which also +requires passing -xarch=v8plusa|v9a passed to the assembler so it accepts the +instruction in the first place, v9a for 64 bit binaries): + +{ __asm__ ("fand %f8, %f8, %f8\n\t"); } + +so instead we just emit the opcode directly, bypassing that check. +*/ +{ __asm__ (".word 0x91B20E08"); } + +/* static void vis2(void) +{ __asm__ ("edge8n %%l0, %%l0, %%l0\n\t" : : : "%l0"); } */ + +static const featuretest features[] = { + { vis, HAVE_VIS, "vis" } +}; + +#endif + + +#if defined(ARCH_PPC) + +static void altivec(void) +{ __asm__ ("vand v0, v0, v0\n\t"); } + + +static const featuretest features[] = { + { altivec, HAVE_ALTIVEC, "altivec" }, +}; + +#endif + +static int +enabled(char *env, const char *ext) +{ + int len; + char *s; + if (!env) + return 1; + len = strlen(ext); + s = env; + while ((s = strstr(s, ext))) + { + int atstart = s == env || *(s-1) == ',' || *(s-1) == ' '; + s += len; + if (atstart && (*s == ' ' || *s == ',' || *s == '\0')) { + return 1; + } + } + return 0; +} + +static void +dumpflags(void) +{ + unsigned f = fz_cpuflags; + int i, n; + + fputs("detected cpu features:", stdout); + n = 0; + for (i = 0; i < sizeof(features) / sizeof(featuretest); i++) + { + if (f & features[i].flag) + { + fputc(' ', stdout); + fputs(features[i].name, stdout); + n ++; + } + } + if (!n) + fputs(" none", stdout); + fputc('\n', stdout); +} + +#ifndef WIN32 + +static sigjmp_buf jmpbuf; +static volatile sig_atomic_t canjump; + +static void +sigillhandler(int sig) +{ + if (!canjump) { + signal(sig, SIG_DFL); + raise(sig); + } + + canjump = 0; + siglongjmp(jmpbuf, 1); +} + +void fz_cpudetect(void) +{ + static int hasrun = 0; + + unsigned flags = 0; + int i; + void (*oldhandler)(int) = NULL; + void (*tmphandler)(int); + char *env; + + if (hasrun) + return; + hasrun = 1; + + env = getenv("CPUACCEL"); + + for (i = 0; i < sizeof(features) / sizeof(featuretest); i++) + { + canjump = 0; + + tmphandler = signal(SIGILL, sigillhandler); + if (!oldhandler) + oldhandler = tmphandler; + + if (sigsetjmp(jmpbuf, 1)) + { + /* test failed - disable feature */ + flags &= ~features[i].flag; + continue; + } + + canjump = 1; + + features[i].test(); + +#if defined(ARCH_X86) || defined(ARCH_X86_64) + /* reset mmx/x87 pipeline state */ + if (features[i].flag & (HAVE_MMX | HAVE_3DNOW | HAVE_MMXEXT)) { + __asm__ __volatile__ ("emms\n\t"); + } +#endif + + /* if we got here the test succeeded */ + if (enabled(env, features[i].name)) + flags |= features[i].flag; + else + flags &= ~features[i].flag; + } + + /* restore previous signal handler */ + signal(SIGILL, oldhandler); + + fz_cpuflags = flags; + +#if defined(ARCH_X86) || defined(ARCH_X86_64) + __asm__ __volatile__ ("emms\n\t"); +#endif + + dumpflags(); +} + +/* +static __attribute__((constructor, used)) void fzcpudetect(void) +{ + fz_cpudetect(); +} +*/ + + +#else /* WIN32 */ + +void fz_cpudetect(void) +{ + static int hasrun = 0; + + unsigned flags = 0; + int i; + char *env; + + if (hasrun) + return; + hasrun = 1; + + env = getenv("CPUACCEL"); + + for (i = 0; i < sizeof(features) / sizeof(featuretest); i++) + { + __try + { + features[i].test(); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + /* test failed - disable feature */ + flags &= ~features[i].flag; + continue; + } + +#if defined(ARCH_X86) || defined(ARCH_X86_64) + if (features[i].flag & (HAVE_MMX | HAVE_3DNOW | HAVE_MMXEXT)) { + /* reset mmx/x87 pipeline state */ + __asm emms; + } +#endif + + /* if we got here the test succeeded */ + if (enabled(env, features[i].name)) + flags |= features[i].flag; + else + flags &= ~features[i].flag; + } + + fz_cpuflags = flags; + + dumpflags(); +} + + +#endif + +#endif + diff --git a/fitz/base_error.c b/fitz/base_error.c new file mode 100644 index 00000000..461ffc60 --- /dev/null +++ b/fitz/base_error.c @@ -0,0 +1,71 @@ +#include "fitz-base.h" + +void +fz_droperror(fz_error *eo) +{ + if (eo->cause) + fz_droperror(eo->cause); + fz_free(eo); +} + +void +fz_printerror(fz_error *eo) +{ +#if 1 + if (eo->cause) + { + fz_printerror(eo->cause); + fprintf(stderr, "| %s:%d: %s(): %s\n", eo->file, eo->line, eo->func, eo->msg); + } + else + { + fprintf(stderr, "+ %s:%d: %s(): %s\n", eo->file, eo->line, eo->func, eo->msg); + } +#else + fprintf(stderr, "+ %s:%d: %s(): %s\n", eo->file, eo->line, eo->func, eo->msg); + eo = eo->cause; + + while (eo) + { + fprintf(stderr, "| %s:%d: %s(): %s\n", eo->file, eo->line, eo->func, eo->msg); + eo = eo->cause; + } +#endif +} + + +void +fz_warn(char *fmt, ...) +{ + va_list ap; + fprintf(stderr, "warning: "); + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + fprintf(stderr, "\n"); +} + +fz_error * +fz_throwimp(fz_error *cause, const char *func, const char *file, int line, char *fmt, ...) +{ + va_list ap; + fz_error *eo; + + eo = fz_malloc(sizeof(fz_error)); + if (!eo) + return fz_outofmem; /* oops. we're *really* out of memory here. */ + + va_start(ap, fmt); + vsnprintf(eo->msg, sizeof eo->msg, fmt, ap); + eo->msg[sizeof(eo->msg) - 1] = '\0'; + va_end(ap); + + strlcpy(eo->func, func, sizeof eo->func); + strlcpy(eo->file, file, sizeof eo->file); + eo->line = line; + + eo->cause = cause; + + return eo; +} + diff --git a/fitz/base_hash.c b/fitz/base_hash.c new file mode 100644 index 00000000..c7086ca9 --- /dev/null +++ b/fitz/base_hash.c @@ -0,0 +1,276 @@ +/* Linear probe hash table. + * 2004 (C) Tor Andersson. + * BSD license. + * + * Simple hashtable with open adressing 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. + */ + +#include "fitz-base.h" + +enum { MAXKEYLEN = 16 }; + +typedef struct fz_hashentry_s fz_hashentry; + +struct fz_hashentry_s +{ + unsigned char key[MAXKEYLEN]; + void *val; +}; + +struct fz_hashtable_s +{ + int keylen; + int size; + int load; + fz_hashentry *ents; +}; + +static unsigned hash(unsigned char *s, int len) +{ + unsigned hash = 0; + int i; + for (i = 0; i < len; i++) + { + hash += s[i]; + hash += (hash << 10); + hash ^= (hash >> 6); + } + hash += (hash << 3); + hash ^= (hash >> 11); + hash += (hash << 15); + return hash; +} + +fz_error * +fz_newhash(fz_hashtable **tablep, int initialsize, int keylen) +{ + fz_hashtable *table; + + assert(keylen <= MAXKEYLEN); + + table = *tablep = fz_malloc(sizeof(fz_hashtable)); + if (!table) + return fz_throw("outofmem: hash table struct"); + + table->keylen = keylen; + table->size = initialsize; + table->load = 0; + + table->ents = fz_malloc(sizeof(fz_hashentry) * table->size); + if (!table->ents) + { + fz_free(table); + *tablep = nil; + return fz_throw("outofmem: hash table entries (size=%d)", initialsize); + } + + memset(table->ents, 0, sizeof(fz_hashentry) * table->size); + + return fz_okay; +} + +void +fz_emptyhash(fz_hashtable *table) +{ + table->load = 0; + memset(table->ents, 0, sizeof(fz_hashentry) * table->size); +} + +int +fz_hashlen(fz_hashtable *table) +{ + return table->size; +} + +void * +fz_hashgetkey(fz_hashtable *table, int idx) +{ + return table->ents[idx].key; +} + +void * +fz_hashgetval(fz_hashtable *table, int idx) +{ + return table->ents[idx].val; +} + +void +fz_drophash(fz_hashtable *table) +{ + fz_free(table->ents); + fz_free(table); +} + +fz_error * +fz_resizehash(fz_hashtable *table, int newsize) +{ + fz_error *error; + fz_hashentry *newents; + fz_hashentry *oldents; + int oldload; + int oldsize; + int i; + + oldsize = table->size; + oldload = table->load; + oldents = table->ents; + + if (newsize < oldload * 8 / 10) + return fz_throw("assert: resize hash too small"); + + newents = fz_malloc(sizeof(fz_hashentry) * newsize); + if (!newents) + return fz_throw("outofmem: hash table (size=%d)", newsize); + + table->size = newsize; + table->load = 0; + table->ents = newents; + memset(table->ents, 0, sizeof(fz_hashentry) * table->size); + + for (i = 0; i < oldsize; i++) + { + if (oldents[i].val) + { + error = fz_hashinsert(table, oldents[i].key, oldents[i].val); + if (error) + { + table->size = oldsize; + table->load = oldload; + table->ents = oldents; + fz_free(newents); + return fz_rethrow(error, "cannot re-insert old entries"); + } + } + } + + fz_free(oldents); + + return fz_okay; +} + +void * +fz_hashfind(fz_hashtable *table, void *key) +{ + fz_hashentry *ents = table->ents; + unsigned size = table->size; + unsigned pos = hash(key, table->keylen) % size; + + while (1) + { + if (!ents[pos].val) + return nil; + + if (memcmp(key, &ents[pos].key, table->keylen) == 0) + return ents[pos].val; + + pos = (pos + 1) % size; + } +} + +fz_error * +fz_hashinsert(fz_hashtable *table, void *key, void *val) +{ + fz_error *error; + fz_hashentry *ents; + unsigned size; + unsigned pos; + + if (table->load > table->size * 8 / 10) + { + error = fz_resizehash(table, table->size * 2); + if (error) + return fz_rethrow(error, "cannot resize hash table"); + } + + ents = table->ents; + size = table->size; + pos = hash(key, table->keylen) % size; + + while (1) + { + if (!ents[pos].val) + { + memcpy(ents[pos].key, key, table->keylen); + ents[pos].val = val; + table->load ++; + return fz_okay; + } + + if (memcmp(key, &ents[pos].key, table->keylen) == 0) + return fz_throw("assert: overwrite hash slot"); + + pos = (pos + 1) % size; + } + + return fz_okay; +} + +fz_error * +fz_hashremove(fz_hashtable *table, void *key) +{ + fz_hashentry *ents = table->ents; + unsigned size = table->size; + unsigned pos = hash(key, table->keylen) % size; + unsigned hole, look, code; + + while (1) + { + if (!ents[pos].val) + return fz_throw("assert: remove inexistant hash entry"); + + if (memcmp(key, &ents[pos].key, table->keylen) == 0) + { + ents[pos].val = nil; + + hole = pos; + look = (hole + 1) % size; + + 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 = nil; + hole = look; + } + + look = (look + 1) % size; + } + + table->load --; + + return fz_okay; + } + + pos = (pos + 1) % size; + } +} + +void +fz_debughash(fz_hashtable *table) +{ + int i, k; + + printf("cache load %d / %d\n", table->load, table->size); + + for (i = 0; i < table->size; i++) + { + if (!table->ents[i].val) + printf("table % 4d: empty\n", i); + else + { + printf("table % 4d: key=", i); + for (k = 0; k < MAXKEYLEN; k++) + printf("%02x", ((char*)table->ents[i].key)[k]); + printf(" val=$%p\n", table->ents[i].val); + } + } +} + diff --git a/fitz/base_matrix.c b/fitz/base_matrix.c new file mode 100644 index 00000000..364b287c --- /dev/null +++ b/fitz/base_matrix.c @@ -0,0 +1,183 @@ +#include "fitz-base.h" + +void fz_invert3x3(float *dst, float *m) +{ + float det; + int i; + +#define M3(m,i,j) (m)[3*i+j] +#define D2(a,b,c,d) (a * d - b * c) +#define D3(a1,a2,a3,b1,b2,b3,c1,c2,c3) \ + (a1 * D2(b2,b3,c2,c3)) - \ + (b1 * D2(a2,a3,c2,c3)) + \ + (c1 * D2(a2,a3,b2,b3)) + + det = D3(M3(m,0,0), M3(m,1,0), M3(m,2,0), + M3(m,0,1), M3(m,1,1), M3(m,2,1), + M3(m,0,2), M3(m,1,2), M3(m,2,2)); + if (det == 0) + det = 1.0; + det = 1.0 / det; + + M3(dst,0,0) = M3(m,1,1) * M3(m,2,2) - M3(m,1,2) * M3(m,2,1); + M3(dst,0,1) = -M3(m,0,1) * M3(m,2,2) + M3(m,0,2) * M3(m,2,1); + M3(dst,0,2) = M3(m,0,1) * M3(m,1,2) - M3(m,0,2) * M3(m,1,1); + + M3(dst,1,0) = -M3(m,1,0) * M3(m,2,2) + M3(m,1,2) * M3(m,2,0); + M3(dst,1,1) = M3(m,0,0) * M3(m,2,2) - M3(m,0,2) * M3(m,2,0); + M3(dst,1,2) = -M3(m,0,0) * M3(m,1,2) + M3(m,0,2) * M3(m,1,0); + + M3(dst,2,0) = M3(m,1,0) * M3(m,2,1) - M3(m,1,1) * M3(m,2,0); + M3(dst,2,1) = -M3(m,0,0) * M3(m,2,1) + M3(m,0,1) * M3(m,2,0); + M3(dst,2,2) = M3(m,0,0) * M3(m,1,1) - M3(m,0,1) * M3(m,1,0); + + for (i = 0; i < 9; i++) + dst[i] *= det; +} + +fz_matrix +fz_concat(fz_matrix one, fz_matrix two) +{ + fz_matrix dst; + dst.a = one.a * two.a + one.b * two.c; + dst.b = one.a * two.b + one.b * two.d; + dst.c = one.c * two.a + one.d * two.c; + dst.d = one.c * two.b + one.d * two.d; + dst.e = one.e * two.a + one.f * two.c + two.e; + dst.f = one.e * two.b + one.f * two.d + two.f; + return dst; +} + +fz_matrix +fz_identity(void) +{ + fz_matrix m; + m.a = 1; m.b = 0; + m.c = 0; m.d = 1; + m.e = 0; m.f = 0; + return m; +} + +fz_matrix +fz_scale(float sx, float sy) +{ + fz_matrix m; + m.a = sx; m.b = 0; + m.c = 0; m.d = sy; + m.e = 0; m.f = 0; + return m; +} + +fz_matrix +fz_rotate(float theta) +{ + fz_matrix m; + float s; + float c; + + while (theta < 0.0f) + theta += 360.0f; + while (theta >= 360.0f) + theta -= 360.0f; + + if (fabs(0.0f - theta) < FLT_EPSILON) + { + s = 0.0f; + c = 1.0f; + } + else if (fabs(90.0f - theta) < FLT_EPSILON) + { + s = 1.0f; + c = 0.0f; + } + else if (fabs(180.0f - theta) < FLT_EPSILON) + { + s = 0.0f; + c = -1.0f; + } + else if (fabs(270.0f - theta) < FLT_EPSILON) + { + s = -1.0f; + c = 0.0f; + } + else + { + s = sin(theta * M_PI / 180.0); + c = cos(theta * M_PI / 180.0); + } + + m.a = c; m.b = s; + m.c = -s; m.d = c; + m.e = 0; m.f = 0; + return m; +} + +fz_matrix +fz_translate(float tx, float ty) +{ + fz_matrix m; + m.a = 1; m.b = 0; + m.c = 0; m.d = 1; + m.e = tx; m.f = ty; + return m; +} + +fz_matrix +fz_invertmatrix(fz_matrix src) +{ + fz_matrix dst; + float rdet = 1.0 / (src.a * src.d - src.b * src.c); + dst.a = src.d * rdet; + dst.b = -src.b * rdet; + dst.c = -src.c * rdet; + dst.d = src.a * rdet; + dst.e = -src.e * dst.a - src.f * dst.c; + dst.f = -src.e * dst.b - src.f * dst.d; + return dst; +} + +int +fz_isrectilinear(fz_matrix m) +{ + return (fabs(m.b) < FLT_EPSILON && fabs(m.c) < FLT_EPSILON) || + (fabs(m.a) < FLT_EPSILON && fabs(m.d) < FLT_EPSILON); +} + +float +fz_matrixexpansion(fz_matrix m) +{ + return sqrt(fabs(m.a * m.d - m.b * m.c)); +} + +fz_point +fz_transformpoint(fz_matrix m, fz_point p) +{ + fz_point t; + t.x = p.x * m.a + p.y * m.c + m.e; + t.y = p.x * m.b + p.y * m.d + m.f; + return t; +} + +fz_rect +fz_transformaabb(fz_matrix m, fz_rect r) +{ + fz_point s, t, u, v; + + if (fz_isinfiniterect(r)) + 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; + s = fz_transformpoint(m, s); + t = fz_transformpoint(m, t); + u = fz_transformpoint(m, u); + v = fz_transformpoint(m, v); + 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; +} + diff --git a/fitz/base_memory.c b/fitz/base_memory.c new file mode 100644 index 00000000..8c2c0249 --- /dev/null +++ b/fitz/base_memory.c @@ -0,0 +1,79 @@ +#include "fitz-base.h" + +/* Make this thread local storage if you wish. */ + +static void *stdmalloc(fz_memorycontext *mem, int n) +{ + return malloc(n); +} + +static void *stdrealloc(fz_memorycontext *mem, void *p, int n) +{ + return realloc(p, n); +} + +static void stdfree(fz_memorycontext *mem, void *p) +{ + free(p); +} + +static fz_memorycontext defmem = { stdmalloc, stdrealloc, stdfree }; +static fz_memorycontext *curmem = &defmem; + +fz_error fz_koutofmem = { + {"out of memory"}, + {""}, + {""}, + 0, + nil +}; + +fz_memorycontext * +fz_currentmemorycontext() +{ + return curmem; +} + +void +fz_setmemorycontext(fz_memorycontext *mem) +{ + curmem = mem; +} + +void * +fz_malloc(int n) +{ + fz_memorycontext *mem = fz_currentmemorycontext(); + void *p = mem->malloc(mem, n); + if (!p) + fz_warn("cannot malloc %d bytes", n); + return p; +} + +void * +fz_realloc(void *p, int n) +{ + fz_memorycontext *mem = fz_currentmemorycontext(); + void *np = mem->realloc(mem, p, n); + if (np == nil) + fz_warn("cannot realloc %d bytes", n); + return np; +} + +void +fz_free(void *p) +{ + fz_memorycontext *mem = fz_currentmemorycontext(); + mem->free(mem, p); +} + +char * +fz_strdup(char *s) +{ + int len = strlen(s); + char *ns = fz_malloc(len + 1); + if (ns) + strcpy(ns, s); + return ns; +} + diff --git a/fitz/base_rect.c b/fitz/base_rect.c new file mode 100644 index 00000000..3c00cb94 --- /dev/null +++ b/fitz/base_rect.c @@ -0,0 +1,75 @@ +#include "fitz-base.h" + +fz_rect fz_infiniterect = { 1, 1, -1, -1 }; +fz_rect fz_emptyrect = { 0, 0, 0, 0 }; + +static fz_irect infinite = { 1, 1, -1, -1 }; +static fz_irect empty = { 0, 0, 0, 0 }; + +fz_irect +fz_roundrect(fz_rect f) +{ + fz_irect i; + i.x0 = fz_floor(f.x0); + i.y0 = fz_floor(f.y0); + i.x1 = fz_ceil(f.x1); + i.y1 = fz_ceil(f.y1); + return i; +} + +fz_rect +fz_intersectrects(fz_rect a, fz_rect b) +{ + fz_rect r; + if (fz_isinfiniterect(a)) return b; + if (fz_isinfiniterect(b)) return a; + r.x0 = MAX(a.x0, b.x0); + r.y0 = MAX(a.y0, b.y0); + r.x1 = MIN(a.x1, b.x1); + r.y1 = MIN(a.y1, b.y1); + return (r.x1 < r.x0 || r.y1 < r.y0) ? fz_emptyrect : r; +} + +fz_rect +fz_mergerects(fz_rect a, fz_rect b) +{ + fz_rect r; + if (fz_isinfiniterect(a) || fz_isinfiniterect(b)) + return fz_infiniterect; + if (fz_isemptyrect(a)) return b; + if (fz_isemptyrect(b)) return a; + r.x0 = MIN(a.x0, b.x0); + r.y0 = MIN(a.y0, b.y0); + r.x1 = MAX(a.x1, b.x1); + r.y1 = MAX(a.y1, b.y1); + return r; +} + +fz_irect +fz_intersectirects(fz_irect a, fz_irect b) +{ + fz_irect r; + if (fz_isinfiniterect(a)) return b; + if (fz_isinfiniterect(b)) return a; + r.x0 = MAX(a.x0, b.x0); + r.y0 = MAX(a.y0, b.y0); + r.x1 = MIN(a.x1, b.x1); + r.y1 = MIN(a.y1, b.y1); + return (r.x1 < r.x0 || r.y1 < r.y0) ? empty : r; +} + +fz_irect +fz_mergeirects(fz_irect a, fz_irect b) +{ + fz_irect r; + if (fz_isinfiniterect(a) || fz_isinfiniterect(b)) + return infinite; + if (fz_isemptyrect(a)) return b; + if (fz_isemptyrect(b)) return a; + r.x0 = MIN(a.x0, b.x0); + r.y0 = MIN(a.y0, b.y0); + r.x1 = MAX(a.x1, b.x1); + r.y1 = MAX(a.y1, b.y1); + return r; +} + diff --git a/fitz/base_rune.c b/fitz/base_rune.c new file mode 100644 index 00000000..32168792 --- /dev/null +++ b/fitz/base_rune.c @@ -0,0 +1,174 @@ +enum +{ + UTFmax = 3, /* maximum bytes per rune */ + Runesync = 0x80, /* cannot represent part of a UTF sequence (<) */ + Runeself = 0x80, /* rune and UTF sequences are the same (<) */ + Runeerror = 0x80 /* decoding error in UTF */ +}; + +enum +{ + Bit1 = 7, + Bitx = 6, + Bit2 = 5, + Bit3 = 4, + Bit4 = 3, + + 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 */ + + 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 */ + + Maskx = (1< T1 + */ + c = *(unsigned char*)str; + if (c < Tx) + { + *rune = c; + return 1; + } + + /* + * two character sequence + * 0080-07FF => T2 Tx + */ + c1 = *(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 = *(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; + } + + /* + * bad decoding + */ +bad: + *rune = Bad; + return 1; +} + +int +runetochar(char *str, int *rune) +{ + int c; + + /* + * one character sequence + * 00000-0007F => 00-7F + */ + c = *rune; + 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; + } + + /* + * three character sequence + * 0800-FFFF => T3 Tx Tx + */ + str[0] = T3 | (c >> 2*Bitx); + str[1] = Tx | ((c >> 1*Bitx) & Maskx); + str[2] = Tx | (c & Maskx); + return 3; +} + +int +runelen(int c) +{ + int rune; + char str[10]; + + rune = c; + return runetochar(str, &rune); +} + +int +runenlen(int *r, int nrune) +{ + int nb, c; + + nb = 0; + while (nrune--) + { + c = *r++; + if (c <= Rune1) + nb++; + else if (c <= Rune2) + nb += 2; + else + nb += 3; + } + return nb; +} + +int +fullrune(char *str, int n) +{ + int c; + + if (n > 0) + { + c = *(unsigned char*)str; + if (c < Tx) + return 1; + if (n > 1) + if (c < T3 || n > 2) + return 1; + } + return 0; +} + diff --git a/fitz/crypt_arc4.c b/fitz/crypt_arc4.c new file mode 100644 index 00000000..fc4d487c --- /dev/null +++ b/fitz/crypt_arc4.c @@ -0,0 +1,100 @@ +/* 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 "fitz-base.h" +#include "fitz-stream.h" + +void +fz_arc4init(fz_arc4 *arc4, const unsigned char *key, const 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; + } + } +} + +unsigned char +fz_arc4next(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_arc4encrypt(fz_arc4 *arc4, unsigned char *dest, const unsigned char *src, const unsigned len) +{ + unsigned int i; + for (i = 0; i < len; i++) + { + unsigned char x; + x = fz_arc4next(arc4); + dest[i] = src[i] ^ x; + } +} + diff --git a/fitz/crypt_crc32.c b/fitz/crypt_crc32.c new file mode 100644 index 00000000..dded733e --- /dev/null +++ b/fitz/crypt_crc32.c @@ -0,0 +1,86 @@ +/* + * Compute the CRC-32 of a data buffer + */ + +#include "fitz-base.h" +#include "fitz-stream.h" + +static const unsigned long crctab[256] = +{ + 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, + 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, + 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, + 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, + 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, + 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, + 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, + 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, + 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, + 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, + 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, + 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, + 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, + 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, + 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, + 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, + 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, + 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, + 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, + 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, + 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, + 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, + 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, + 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, + 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, + 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, + 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, + 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, + 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, + 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, + 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, + 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, + 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, + 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, + 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, + 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, + 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, + 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, + 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, + 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, + 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, + 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, + 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, + 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, + 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, + 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, + 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, + 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, + 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, + 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, + 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, + 0x2d02ef8dL +}; + +#define DO1(buf) crc = crctab[((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8); +#define DO2(buf) DO1(buf); DO1(buf); +#define DO4(buf) DO2(buf); DO2(buf); +#define DO8(buf) DO4(buf); DO4(buf); + +unsigned long +fz_crc32(unsigned long crc, unsigned char *buf, int len) +{ + if (buf == nil) + return 0L; + crc = crc ^ 0xffffffffL; + while (len >= 8) + { + DO8(buf); + len -= 8; + } + if (len) + { + do { DO1(buf); } while (--len); + } + return crc ^ 0xffffffffL; +} + diff --git a/fitz/crypt_md5.c b/fitz/crypt_md5.c new file mode 100644 index 00000000..8f665329 --- /dev/null +++ b/fitz/crypt_md5.c @@ -0,0 +1,274 @@ +/* +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 "fitz-base.h" +#include "fitz-stream.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 long *, const unsigned); +static void decode(unsigned long *, const unsigned char *, const unsigned); +static void transform(unsigned long 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 long)(ac); \ + (a) = ROTATE ((a), (s)); \ + (a) += (b); \ + } +#define GG(a, b, c, d, x, s, ac) { \ + (a) += G ((b), (c), (d)) + (x) + (unsigned long)(ac); \ + (a) = ROTATE ((a), (s)); \ + (a) += (b); \ + } +#define HH(a, b, c, d, x, s, ac) { \ + (a) += H ((b), (c), (d)) + (x) + (unsigned long)(ac); \ + (a) = ROTATE ((a), (s)); \ + (a) += (b); \ + } +#define II(a, b, c, d, x, s, ac) { \ + (a) += I ((b), (c), (d)) + (x) + (unsigned long)(ac); \ + (a) = ROTATE ((a), (s)); \ + (a) += (b); \ + } + +static void encode(unsigned char *output, const unsigned long *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 long *output, const unsigned char *input, const unsigned len) +{ + unsigned i, j; + + for (i = 0, j = 0; j < len; i++, j += 4) + { + output[i] = ((unsigned long)input[j]) | + (((unsigned long)input[j+1]) << 8) | + (((unsigned long)input[j+2]) << 16) | + (((unsigned long)input[j+3]) << 24); + } +} + +static void transform(unsigned long state[4], const unsigned char block[64]) +{ + unsigned long a = state[0]; + unsigned long b = state[1]; + unsigned long c = state[2]; + unsigned long d = state[3]; + unsigned long 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, 0x2441453); /* 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, 0x4881d05); /* 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_md5init(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_md5update(fz_md5 *context, const unsigned char *input, const 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 long) inlen << 3; + if (context->count[0] < (unsigned long) inlen << 3) + context->count[1] ++; + context->count[1] += (unsigned long) 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_md5final(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_md5update(context, padding, padlen); + + /* Append length (before padding) */ + fz_md5update(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/filt_a85d.c b/fitz/filt_a85d.c new file mode 100644 index 00000000..19ba9e9a --- /dev/null +++ b/fitz/filt_a85d.c @@ -0,0 +1,128 @@ +#include "fitz-base.h" +#include "fitz-stream.h" + +typedef struct fz_a85d_s fz_a85d; + +struct fz_a85d_s +{ + fz_filter super; + unsigned long word; + int count; +}; + +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; +} + +fz_error * +fz_newa85d(fz_filter **fp, fz_obj *params) +{ + FZ_NEWFILTER(fz_a85d, f, a85d); + f->word = 0; + f->count = 0; + return fz_okay; +} + +void +fz_dropa85d(fz_filter *f) +{ +} + +fz_error * +fz_processa85d(fz_filter *filter, fz_buffer *in, fz_buffer *out) +{ + fz_a85d *f = (fz_a85d*)filter; + int c; + + while (1) + { + if (in->rp == in->wp) + return fz_ioneedin; + + c = *in->rp++; + + if (c >= '!' && c <= 'u') { + if (f->count == 4) { + if (out->wp + 4 > out->ep) { + in->rp --; + return fz_ioneedout; + } + + f->word = f->word * 85 + (c - '!'); + + *out->wp++ = (f->word >> 24) & 0xff; + *out->wp++ = (f->word >> 16) & 0xff; + *out->wp++ = (f->word >> 8) & 0xff; + *out->wp++ = (f->word) & 0xff; + + f->word = 0; + f->count = 0; + } + else { + f->word = f->word * 85 + (c - '!'); + f->count ++; + } + } + + else if (c == 'z' && f->count == 0) { + if (out->wp + 4 > out->ep) { + in->rp --; + return fz_ioneedout; + } + *out->wp++ = 0; + *out->wp++ = 0; + *out->wp++ = 0; + *out->wp++ = 0; + } + + else if (c == '~') { + if (in->rp == in->wp) { + in->rp --; + return fz_ioneedin; + } + + c = *in->rp++; + + if (c != '>') { + return fz_throw("bad eod marker in a85d"); + } + + if (out->wp + f->count - 1 > out->ep) { + in->rp -= 2; + return fz_ioneedout; + } + + switch (f->count) { + case 0: + break; + case 1: + return fz_throw("partial final byte in a85d"); + case 2: + f->word = f->word * (85L * 85 * 85) + 0xffffffL; + goto o1; + case 3: + f->word = f->word * (85L * 85) + 0xffffL; + goto o2; + case 4: + f->word = f->word * 85 + 0xffL; + *(out->wp+2) = f->word >> 8; +o2: *(out->wp+1) = f->word >> 16; +o1: *(out->wp+0) = f->word >> 24; + out->wp += f->count - 1; + break; + } + return fz_iodone; + } + + else if (!iswhite(c)) { + return fz_throw("bad data in a85d: '%c'", c); + } + } +} + diff --git a/fitz/filt_a85e.c b/fitz/filt_a85e.c new file mode 100644 index 00000000..386d8bb3 --- /dev/null +++ b/fitz/filt_a85e.c @@ -0,0 +1,126 @@ +#include "fitz-base.h" +#include "fitz-stream.h" + +typedef struct fz_a85e_s fz_a85e; + +struct fz_a85e_s +{ + fz_filter super; + int c; +}; + +fz_error * +fz_newa85e(fz_filter **fp, fz_obj *params) +{ + FZ_NEWFILTER(fz_a85e, f, a85e); + f->c = 0; + return fz_okay; +} + +void +fz_dropa85e(fz_filter *f) +{ +} + +fz_error * +fz_processa85e(fz_filter *filter, fz_buffer *in, fz_buffer *out) +{ + fz_a85e *f = (fz_a85e*)filter; + unsigned long word; + int count; + int n; + + n = 0; + + while (1) + { + if (f->c >= 70) { + if (out->wp + 1 > out->ep) + return fz_ioneedout; + *out->wp++ = '\n'; + f->c = 0; + n ++; + } + + if (in->rp + 4 <= in->wp) + { + word = (in->rp[0] << 24) | + (in->rp[1] << 16) | + (in->rp[2] << 8) | + (in->rp[3]); + if (word == 0) { + if (out->wp + 1 > out->ep) + return fz_ioneedout; + *out->wp++ = 'z'; + f->c ++; + n ++; + } + else { + unsigned long v1, v2, v3, v4; + + if (out->wp + 5 > out->ep) + return fz_ioneedout; + + v4 = word / 85; + v3 = v4 / 85; + v2 = v3 / 85; + v1 = v2 / 85; + + *out->wp++ = (v1 % 85) + '!'; + *out->wp++ = (v2 % 85) + '!'; + *out->wp++ = (v3 % 85) + '!'; + *out->wp++ = (v4 % 85) + '!'; + *out->wp++ = (word % 85) + '!'; + f->c += 5; + n += 5; + } + in->rp += 4; + } + + else if (in->eof) + { + unsigned long divisor; + + if (in->rp == in->wp) + goto needinput; /* handle clean eof here */ + + count = in->wp - in->rp; + + if (out->wp + count + 3 > out->ep) + return fz_ioneedout; + + word = 0; + switch (count) { + case 3: word |= in->rp[2] << 8; + case 2: word |= in->rp[1] << 16; + case 1: word |= in->rp[0] << 24; + } + in->rp += count; + + divisor = 85L * 85 * 85 * 85; + while (count-- >= 0) { + *out->wp++ = ((word / divisor) % 85) + '!'; + divisor /= 85; + } + + *out->wp++ = '~'; + *out->wp++ = '>'; + return fz_iodone; + } + + else { + goto needinput; + } + } + +needinput: + if (in->eof) { + if (out->wp + 2 > out->ep) + return fz_ioneedout; + *out->wp++ = '~'; + *out->wp++ = '>'; + return fz_iodone; + } + return fz_ioneedin; +} + diff --git a/fitz/filt_ahxd.c b/fitz/filt_ahxd.c new file mode 100644 index 00000000..0feb10c2 --- /dev/null +++ b/fitz/filt_ahxd.c @@ -0,0 +1,112 @@ +#include "fitz-base.h" +#include "fitz-stream.h" + +typedef struct fz_ahxd_s fz_ahxd; + +struct fz_ahxd_s +{ + fz_filter super; + int odd; + int a; +}; + +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 fromhex(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; +} + +fz_error * +fz_newahxd(fz_filter **fp, fz_obj *params) +{ + FZ_NEWFILTER(fz_ahxd, f, ahxd); + f->odd = 0; + f->a = 0; + return fz_okay; +} + +void +fz_dropahxd(fz_filter *f) +{ +} + +fz_error * +fz_processahxd(fz_filter *filter, fz_buffer *in, fz_buffer *out) +{ + fz_ahxd *f = (fz_ahxd*)filter; + int b, c; + + while (1) + { + if (in->rp == in->wp) + return fz_ioneedin; + + if (out->wp == out->ep) + return fz_ioneedout; + + c = *in->rp++; + + if (ishex(c)) { + if (!f->odd) { + f->a = fromhex(c); + f->odd = 1; + } + else { + b = fromhex(c); + *out->wp++ = (f->a << 4) | b; + f->odd = 0; + } + } + + else if (c == '>') { + if (f->odd) + *out->wp++ = (f->a << 4); + return fz_iodone; + } + + else if (!iswhite(c)) { + return fz_throw("bad data in ahxd: '%c'", c); + } + } +} + +void +fz_pushbackahxd(fz_filter *filter, fz_buffer *in, fz_buffer *out, int n) +{ + int k; + + assert(filter->process == fz_processahxd); + assert(out->wp - n >= out->rp); + + k = 0; + while (k < n * 2) { + in->rp --; + if (ishex(*in->rp)) + k ++; + } + + out->wp -= n; +} + diff --git a/fitz/filt_ahxe.c b/fitz/filt_ahxe.c new file mode 100644 index 00000000..0fc727c3 --- /dev/null +++ b/fitz/filt_ahxe.c @@ -0,0 +1,64 @@ +#include "fitz-base.h" +#include "fitz-stream.h" + +typedef struct fz_ahxe_s fz_ahxe; + +struct fz_ahxe_s +{ + fz_filter super; + int c; +}; + +static const char tohex[16] = "0123456789ABCDEF"; + +fz_error * +fz_newahxe(fz_filter **fp, fz_obj *params) +{ + FZ_NEWFILTER(fz_ahxe, f, ahxe); + f->c = 0; + return fz_okay; +} + +void +fz_dropahxe(fz_filter *f) +{ +} + +fz_error * +fz_processahxe(fz_filter *filter, fz_buffer *in, fz_buffer *out) +{ + fz_ahxe *f = (fz_ahxe*)filter; + int a, b, c; + + while (1) + { + if (in->rp == in->wp) + goto needinput; + + if (out->wp + 2 >= out->ep) /* can write 3 bytes from 1 */ + return fz_ioneedout; + + c = *in->rp++; + a = tohex[(c >> 4) & 0x0f]; + b = tohex[c & 0x0f]; + + *out->wp++ = a; + *out->wp++ = b; + + f->c += 2; + if (f->c == 60) { + *out->wp++ = '\n'; + f->c = 0; + } + } + +needinput: + if (in->eof) { + if (out->wp == out->ep) + return fz_ioneedout; + *out->wp++ = '>'; + return fz_iodone; + } + return fz_ioneedin; +} + diff --git a/fitz/filt_arc4.c b/fitz/filt_arc4.c new file mode 100644 index 00000000..af038599 --- /dev/null +++ b/fitz/filt_arc4.c @@ -0,0 +1,47 @@ +#include "fitz-base.h" +#include "fitz-stream.h" + +typedef struct fz_arc4c_s fz_arc4c; + +struct fz_arc4c_s +{ + fz_filter super; + fz_arc4 arc4; +}; + +fz_error * +fz_newarc4filter(fz_filter **fp, unsigned char *key, unsigned keylen) +{ + FZ_NEWFILTER(fz_arc4c, f, arc4filter); + fz_arc4init(&f->arc4, key, keylen); + return fz_okay; +} + +void +fz_droparc4filter(fz_filter *f) +{ +} + +fz_error * +fz_processarc4filter(fz_filter *filter, fz_buffer *in, fz_buffer *out) +{ + fz_arc4c *f = (fz_arc4c*)filter; + int n; + + while (1) + { + if (in->rp + 1 > in->wp) { + if (in->eof) + return fz_iodone; + return fz_ioneedin; + } + if (out->wp + 1 > out->ep) + return fz_ioneedout; + + n = MIN(in->wp - in->rp, out->ep - out->wp); + fz_arc4encrypt(&f->arc4, out->wp, in->rp, n); + in->rp += n; + out->wp += n; + } +} + diff --git a/fitz/filt_dctc.h b/fitz/filt_dctc.h new file mode 100644 index 00000000..72f61ef2 --- /dev/null +++ b/fitz/filt_dctc.h @@ -0,0 +1,39 @@ +/* + * Extend libjpegs error handler to use setjmp/longjmp + */ + +#include + +#include + +struct myerrmgr +{ + struct jpeg_error_mgr super; + jmp_buf jb; + char msg[JMSG_LENGTH_MAX]; +}; + +static void myerrexit(j_common_ptr cinfo) +{ + struct myerrmgr *err = (struct myerrmgr *)cinfo->err; + char msgbuf[JMSG_LENGTH_MAX]; + err->super.format_message(cinfo, msgbuf); + strlcpy(err->msg, msgbuf, sizeof err->msg); + longjmp(err->jb, 1); +} + +static void myoutmess(j_common_ptr cinfo) +{ + struct myerrmgr *err = (struct myerrmgr *)cinfo->err; + char msgbuf[JMSG_LENGTH_MAX]; + err->super.format_message(cinfo, msgbuf); + fz_warn("jpeg error: %s", msgbuf); +} + +static void myiniterr(struct myerrmgr *err) +{ + jpeg_std_error(&err->super); + err->super.error_exit = myerrexit; + err->super.output_message = myoutmess; +} + diff --git a/fitz/filt_dctd.c b/fitz/filt_dctd.c new file mode 100644 index 00000000..3425b8e5 --- /dev/null +++ b/fitz/filt_dctd.c @@ -0,0 +1,232 @@ +#include "fitz-base.h" +#include "fitz-stream.h" + +#include "filt_dctc.h" + +typedef struct fz_dctd_s fz_dctd; + +struct mysrcmgr +{ + struct jpeg_source_mgr super; + fz_buffer *buf; + int skip; +}; + +struct fz_dctd_s +{ + fz_filter super; + struct jpeg_decompress_struct cinfo; + struct mysrcmgr src; + struct myerrmgr err; + int colortransform; + int stage; +}; + +static void myinitsource(j_decompress_ptr cinfo) { /* empty */ } +static boolean myfillinput(j_decompress_ptr cinfo) { return FALSE; } +static void mytermsource(j_decompress_ptr cinfo) { /* empty */ } + +static void myskipinput(j_decompress_ptr cinfo, long n) +{ + struct mysrcmgr *src = (struct mysrcmgr *)cinfo->src; + fz_buffer *in = src->buf; + + assert(src->skip == 0); + + in->rp = in->wp - src->super.bytes_in_buffer; + + if (in->rp + n > in->wp) { + src->skip = (in->rp + n) - in->wp; + in->rp = in->wp; + } + else { + src->skip = 0; + in->rp += n; + } + + src->super.bytes_in_buffer = in->wp - in->rp; + src->super.next_input_byte = in->rp; +} + +fz_error * +fz_newdctd(fz_filter **fp, fz_obj *params) +{ + fz_error *err; + fz_obj *obj; + int colortransform; + + FZ_NEWFILTER(fz_dctd, d, dctd); + + colortransform = -1; /* "unset" */ + + if (params) + { + obj = fz_dictgets(params, "ColorTransform"); + if (obj) + colortransform = fz_toint(obj); + } + + d->colortransform = colortransform; + d->stage = 0; + + /* setup error callback first thing */ + myiniterr(&d->err); + d->cinfo.err = (struct jpeg_error_mgr*) &d->err; + + if (setjmp(d->err.jb)) { + err = fz_throw("cannot decode jpeg: %s", d->err.msg); + fz_free(d); + return err; + } + + /* create decompression object. this zeroes cinfo except for err. */ + jpeg_create_decompress(&d->cinfo); + + /* prepare source manager */ + d->cinfo.src = (struct jpeg_source_mgr *)&d->src; + d->src.super.init_source = myinitsource; + d->src.super.fill_input_buffer = myfillinput; + d->src.super.skip_input_data = myskipinput; + d->src.super.resync_to_restart = jpeg_resync_to_restart; + d->src.super.term_source = mytermsource; + + d->src.super.bytes_in_buffer = 0; + d->src.super.next_input_byte = nil; + d->src.skip = 0; + + /* speed up jpeg decoding a bit */ + d->cinfo.dct_method = JDCT_FASTEST; + d->cinfo.do_fancy_upsampling = FALSE; + + return fz_okay; +} + +void +fz_dropdctd(fz_filter *filter) +{ + fz_dctd *d = (fz_dctd*)filter; + if (setjmp(d->err.jb)) { + fz_warn("jpeg error: jpeg_destroy_decompress: %s", d->err.msg); + return; + } + jpeg_destroy_decompress(&d->cinfo); +} + +fz_error * +fz_processdctd(fz_filter *filter, fz_buffer *in, fz_buffer *out) +{ + fz_dctd *d = (fz_dctd*)filter; + boolean b; + int i; + int stride; + JSAMPROW scanlines[1]; + + d->src.buf = in; + + /* skip any bytes left over from myskipinput() */ + if (d->src.skip > 0) { + if (in->rp + d->src.skip > in->wp) { + d->src.skip = (in->rp + d->src.skip) - in->wp; + in->rp = in->wp; + goto needinput; + } + else { + in->rp += d->src.skip; + d->src.skip = 0; + } + } + + d->src.super.bytes_in_buffer = in->wp - in->rp; + d->src.super.next_input_byte = in->rp; + + if (setjmp(d->err.jb)) + { + return fz_throw("cannot decode jpeg: %s", d->err.msg); + } + + switch (d->stage) + { + case 0: + i = jpeg_read_header(&d->cinfo, TRUE); + if (i == JPEG_SUSPENDED) + goto needinput; + + /* default value if ColorTransform is not set */ + if (d->colortransform == -1) + { + if (d->cinfo.num_components == 3) + d->colortransform = 1; + else + d->colortransform = 0; + } + + if (d->cinfo.saw_Adobe_marker) + d->colortransform = d->cinfo.Adobe_transform; + + /* Guess the input colorspace, and set output colorspace accordingly */ + switch (d->cinfo.num_components) + { + case 3: + if (d->colortransform) + d->cinfo.jpeg_color_space = JCS_YCbCr; + else + d->cinfo.jpeg_color_space = JCS_RGB; + break; + case 4: + if (d->colortransform) + d->cinfo.jpeg_color_space = JCS_YCCK; + else + d->cinfo.jpeg_color_space = JCS_CMYK; + break; + } + + /* fall through */ + d->stage = 1; + + case 1: + b = jpeg_start_decompress(&d->cinfo); + if (b == FALSE) + goto needinput; + + /* fall through */ + d->stage = 2; + + case 2: + stride = d->cinfo.output_width * d->cinfo.output_components; + + while (d->cinfo.output_scanline < d->cinfo.output_height) + { + if (out->wp + stride > out->ep) + goto needoutput; + + scanlines[0] = out->wp; + + i = jpeg_read_scanlines(&d->cinfo, scanlines, 1); + + if (i == 0) + goto needinput; + + out->wp += stride; + } + + /* fall through */ + d->stage = 3; + + case 3: + b = jpeg_finish_decompress(&d->cinfo); + if (b == FALSE) + goto needinput; + d->stage = 4; + in->rp = in->wp - d->src.super.bytes_in_buffer; + return fz_iodone; + } + +needinput: + in->rp = in->wp - d->src.super.bytes_in_buffer; + return fz_ioneedin; + +needoutput: + in->rp = in->wp - d->src.super.bytes_in_buffer; + return fz_ioneedout; +} + diff --git a/fitz/filt_dcte.c b/fitz/filt_dcte.c new file mode 100644 index 00000000..5380c6b1 --- /dev/null +++ b/fitz/filt_dcte.c @@ -0,0 +1,254 @@ +#include "fitz-base.h" +#include "fitz-stream.h" + +#include "filt_dctc.h" + +typedef struct fz_dcte_s fz_dcte; + +struct mydstmgr +{ + struct jpeg_destination_mgr super; + fz_buffer *buf; +}; + +struct fz_dcte_s +{ + fz_filter super; + + struct jpeg_compress_struct cinfo; + struct mydstmgr dst; + struct myerrmgr err; + int stage; + + int columns; + int rows; + int colors; +}; + +static void myinitdest(j_compress_ptr cinfo) { /* empty */ } +static boolean myemptybuf(j_compress_ptr cinfo) { return FALSE; } +static void mytermdest(j_compress_ptr cinfo) { /* empty */ } + +fz_error * +fz_newdcte(fz_filter **fp, fz_obj *params) +{ + fz_error *err; + fz_obj *obj; + int i; + + FZ_NEWFILTER(fz_dcte, e, dcte); + + e->stage = 0; + + obj = fz_dictgets(params, "Columns"); + if (!obj) { fz_free(e); return fz_throw("missing Columns parameter"); } + e->columns = fz_toint(obj); + + obj = fz_dictgets(params, "Rows"); + if (!obj) { fz_free(e); return fz_throw("missing Rows parameter"); } + e->rows = fz_toint(obj); + + obj = fz_dictgets(params, "Colors"); + if (!obj) { fz_free(e); return fz_throw("missing Colors parameter"); } + e->colors = fz_toint(obj); + + /* setup error callback first thing */ + myiniterr(&e->err); + e->cinfo.err = (struct jpeg_error_mgr*) &e->err; + + if (setjmp(e->err.jb)) + { + err = fz_throw("cannot encode jpeg: %s", e->err.msg); + fz_free(e); + return err; + } + + jpeg_create_compress(&e->cinfo); + + /* prepare destination manager */ + e->cinfo.dest = (struct jpeg_destination_mgr *) &e->dst; + e->dst.super.init_destination = myinitdest; + e->dst.super.empty_output_buffer = myemptybuf; + e->dst.super.term_destination = mytermdest; + + e->dst.super.next_output_byte = nil; + e->dst.super.free_in_buffer = 0; + + /* prepare required encoding options */ + e->cinfo.image_width = e->columns; + e->cinfo.image_height = e->rows; + e->cinfo.input_components = e->colors; + + switch (e->colors) { + case 1: e->cinfo.in_color_space = JCS_GRAYSCALE; break; + case 3: e->cinfo.in_color_space = JCS_RGB; break; + case 4: e->cinfo.in_color_space = JCS_CMYK; break; + default: e->cinfo.in_color_space = JCS_UNKNOWN; break; + } + + jpeg_set_defaults(&e->cinfo); + + /* FIXME check this */ + obj = fz_dictgets(params, "ColorTransform"); + if (obj) { + int colortransform = fz_toint(obj); + if (e->colors == 3 && !colortransform) + jpeg_set_colorspace(&e->cinfo, JCS_RGB); + if (e->colors == 4 && colortransform) + jpeg_set_colorspace(&e->cinfo, JCS_YCCK); + if (e->colors == 4 && !colortransform) + jpeg_set_colorspace(&e->cinfo, JCS_CMYK); + } + + obj = fz_dictgets(params, "HSamples"); + if (obj && fz_isarray(obj)) { + fz_obj *o; + for (i = 0; i < e->colors; i++) { + o = fz_arrayget(obj, i); + e->cinfo.comp_info[i].h_samp_factor = fz_toint(o); + } + } + + obj = fz_dictgets(params, "VSamples"); + if (obj && fz_isarray(obj)) { + fz_obj *o; + for (i = 0; i < e->colors; i++) { + o = fz_arrayget(obj, i); + e->cinfo.comp_info[i].v_samp_factor = fz_toint(o); + } + } + + /* TODO: quant-tables and huffman-tables */ + + return fz_okay; +} + +void +fz_dropdcte(fz_filter *filter) +{ + fz_dcte *e = (fz_dcte*)filter; + + if (setjmp(e->err.jb)) { + fz_warn("jpeg error: jpeg_destroy_compress: %s", e->err.msg); + return; + } + + jpeg_destroy_compress(&e->cinfo); +} + +/* Adobe says zigzag order. IJG > v6a says natural order. */ +#if JPEG_LIB_VERSION >= 61 +#define unzigzag(x) unzigzagorder[x] +/* zigzag array position of n'th element of natural array order */ +static const unsigned char unzigzagorder[] = +{ + 0, 1, 5, 6, 14, 15, 27, 28, + 2, 4, 7, 13, 16, 26, 29, 42, + 3, 8, 12, 17, 25, 30, 41, 43, + 9, 11, 18, 24, 31, 40, 44, 53, + 10, 19, 23, 32, 39, 45, 52, 54, + 20, 22, 33, 38, 46, 51, 55, 60, + 21, 34, 37, 47, 50, 56, 59, 61, + 35, 36, 48, 49, 57, 58, 62, 63 +}; +#else +#define unzigzag(x) (x) +#endif + +fz_error * +fz_setquanttables(fz_dcte *e, unsigned int **qtables, int qfactor) +{ + int i, j; + unsigned int table[64]; + + if (setjmp(e->err.jb)) { + return fz_throw("jpeg error: jpeg_add_quant_table: %s", e->err.msg); + } + + /* TODO: check for duplicate tables */ + + for (i = 0; i < e->colors; i++) { + for (j = 0; j < 64; j++) { + table[j] = unzigzag(qtables[i][j]); + } + jpeg_add_quant_table(&e->cinfo, i, table, qfactor, TRUE); + e->cinfo.comp_info[i].quant_tbl_no = i; + } + + return fz_okay; +} + +fz_error * +fz_processdcte(fz_filter *filter, fz_buffer *in, fz_buffer *out) +{ + fz_dcte *e = (fz_dcte*)filter; + JSAMPROW scanline[1]; + int stride; + int i; + + e->dst.buf = out; + e->dst.super.free_in_buffer = out->ep - out->wp; + e->dst.super.next_output_byte = out->wp; + + if (setjmp(e->err.jb)) + { + return fz_throw("cannot encode jpeg: %s", e->err.msg); + } + + switch (e->stage) + { + case 0: + /* must have enough space for markers, typically 600 bytes or so */ + if (out->wp + 1024 > out->ep) + goto needoutput; + + jpeg_start_compress(&e->cinfo, TRUE); + + /* TODO: write Adobe ColorTransform marker */ + + /* fall through */ + e->stage = 1; + + case 1: + stride = e->columns * e->colors; + + while (e->cinfo.next_scanline < e->cinfo.image_height) + { + if (in->rp + stride > in->wp) + goto needinput; + + scanline[0] = in->rp; + + i = jpeg_write_scanlines(&e->cinfo, scanline, 1); + + if (i == 0) + goto needoutput; + + in->rp += stride; + } + + /* fall through */ + e->stage = 2; + + case 2: + /* must have enough space for end markers */ + if (out->wp + 100 > out->ep) + goto needoutput; + + /* finish compress cannot suspend! */ + jpeg_finish_compress(&e->cinfo); + + e->stage = 3; + out->wp = out->ep - e->dst.super.free_in_buffer; + return fz_iodone; + } + +needinput: + out->wp = out->ep - e->dst.super.free_in_buffer; + return fz_ioneedin; + +needoutput: + out->wp = out->ep - e->dst.super.free_in_buffer; + return fz_ioneedout; +} + diff --git a/fitz/filt_faxc.h b/fitz/filt_faxc.h new file mode 100644 index 00000000..f11334be --- /dev/null +++ b/fitz/filt_faxc.h @@ -0,0 +1,125 @@ +/* common bit magic */ + +static inline void +printbits(FILE *f, int code, int nbits) +{ + int n, b; + for (n = nbits - 1; n >= 0; n--) + { + b = (code >> n) & 1; + fprintf(f, "%c", b ? '1' : '0'); + } +} + +static inline int +getbit(const unsigned char *buf, int x) +{ + return ( buf[x >> 3] >> ( 7 - (x & 7) ) ) & 1; +} + +static inline void +printline(FILE *f, unsigned char *line, int w) +{ + int i; + for (i = 0; i < w; i++) + fprintf(f, "%c", getbit(line, i) ? '#' : '.'); + fprintf(f, "\n"); +} + +static inline int +getrun(const unsigned char *line, int x, int w, int c) +{ + int z; + int b; + + if (x < 0) + x = 0; + + z = x; + while (z < w) + { + b = getbit(line, z); + if (c != b) + break; + z ++; + } + + return z - x; +} + +static inline int +findchanging(const unsigned char *line, int x, int w) +{ + int a, b; + + if (line == 0) + return w; + + if (x == -1) + { + a = 0; + x = 0; + } + else + { + a = getbit(line, x); + x++; + } + + while (x < w) + { + b = getbit(line, x); + if (a != b) + break; + x++; + } + + return x; +} + +static inline int +findchangingcolor(const unsigned char *line, int x, int w, int color) +{ + if (line == 0) + return w; + + x = findchanging(line, x, w); + + if (x < w && getbit(line, x) != color) + x = findchanging(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; + + 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]; + } +} + diff --git a/fitz/filt_faxd.c b/fitz/filt_faxd.c new file mode 100644 index 00000000..3eaf5f3b --- /dev/null +++ b/fitz/filt_faxd.c @@ -0,0 +1,470 @@ +#include "fitz-base.h" +#include "fitz-stream.h" + +#include "filt_faxd.h" +#include "filt_faxc.h" + +typedef enum fax_stage_e +{ + SNORMAL, /* neutral state, waiting for any code */ + SMAKEUP, /* got a 1d makeup code, waiting for terminating code */ + SEOL, /* at eol, needs output buffer space */ + SH1, SH2 /* in H part 1 and 2 (both makeup and terminating codes) */ +} fax_stage_e; + +/* TODO: uncompressed */ + +typedef struct fz_faxd_s fz_faxd; + +struct fz_faxd_s +{ + fz_filter super; + + int k; + int endofline; + int encodedbytealign; + int columns; + int rows; + int endofblock; + int blackis1; + + int stride; + int ridx; + + int bidx; + unsigned int word; + + fax_stage_e stage; + + int a, c, dim, eolc; + unsigned char *ref; + unsigned char *dst; +}; + +fz_error * +fz_newfaxd(fz_filter **fp, fz_obj *params) +{ + fz_obj *obj; + + FZ_NEWFILTER(fz_faxd, fax, faxd); + + fax->ref = nil; + fax->dst = nil; + + fax->k = 0; + fax->endofline = 0; + fax->encodedbytealign = 0; + fax->columns = 1728; + fax->rows = 0; + fax->endofblock = 1; + fax->blackis1 = 0; + + obj = fz_dictgets(params, "K"); + if (obj) fax->k = fz_toint(obj); + + obj = fz_dictgets(params, "EndOfLine"); + if (obj) fax->endofline = fz_tobool(obj); + + obj = fz_dictgets(params, "EncodedByteAlign"); + if (obj) fax->encodedbytealign = fz_tobool(obj); + + obj = fz_dictgets(params, "Columns"); + if (obj) fax->columns = fz_toint(obj); + + obj = fz_dictgets(params, "Rows"); + if (obj) fax->rows = fz_toint(obj); + + obj = fz_dictgets(params, "EndOfBlock"); + if (obj) fax->endofblock = fz_tobool(obj); + + obj = fz_dictgets(params, "BlackIs1"); + if (obj) fax->blackis1 = fz_tobool(obj); + + fax->stride = ((fax->columns - 1) >> 3) + 1; + fax->ridx = 0; + fax->bidx = 32; + fax->word = 0; + + fax->stage = SNORMAL; + fax->a = -1; + fax->c = 0; + fax->dim = fax->k < 0 ? 2 : 1; + fax->eolc = 0; + + fax->ref = fz_malloc(fax->stride); + if (!fax->ref) + { + fz_free(fax); + return fz_throw("outofmem: scanline buffer one"); + } + + fax->dst = fz_malloc(fax->stride); + if (!fax->dst) + { + fz_free(fax); + fz_free(fax->ref); + return fz_throw("outofmem: scanline buffer two"); + } + + memset(fax->ref, 0, fax->stride); + memset(fax->dst, 0, fax->stride); + + return fz_okay; +} + +void +fz_dropfaxd(fz_filter *p) +{ + fz_faxd *fax = (fz_faxd*) p; + fz_free(fax->ref); + fz_free(fax->dst); +} + +static inline void eatbits(fz_faxd *fax, int nbits) +{ + fax->word <<= nbits; + fax->bidx += nbits; +} + +static inline fz_error * fillbits(fz_faxd *fax, fz_buffer *in) +{ + while (fax->bidx >= 8) + { + if (in->rp + 1 > in->wp) + return fz_ioneedin; + fax->bidx -= 8; + fax->word |= *in->rp << fax->bidx; + in->rp ++; + } + return fz_okay; +} + +static int +getcode(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; + } + + eatbits(fax, nbits); + + return val; +} + +/* decode one 1d code */ +static fz_error * +dec1d(fz_faxd *fax) +{ + int code; + + if (fax->a == -1) + fax->a = 0; + + if (fax->c) + code = getcode(fax, cf_black_decode, cfd_black_initial_bits); + else + code = getcode(fax, cf_white_decode, cfd_white_initial_bits); + + if (code == UNCOMPRESSED) + return fz_throw("uncompressed data in faxd"); + + if (code < 0) + return fz_throw("negative code in 1d faxd"); + + if (fax->a + code > fax->columns) + return fz_throw("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 = SNORMAL; + } + else + fax->stage = SMAKEUP; + + return fz_okay; +} + +/* decode one 2d code */ +static fz_error * +dec2d(fz_faxd *fax) +{ + int code, b1, b2; + + if (fax->stage == SH1 || fax->stage == SH2) + { + if (fax->a == -1) + fax->a = 0; + + if (fax->c) + code = getcode(fax, cf_black_decode, cfd_black_initial_bits); + else + code = getcode(fax, cf_white_decode, cfd_white_initial_bits); + + if (code == UNCOMPRESSED) + return fz_throw("uncompressed data in faxd"); + + if (code < 0) + return fz_throw("negative code in 2d faxd"); + + if (fax->a + code > fax->columns) + return fz_throw("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 == SH1) + fax->stage = SH2; + else if (fax->stage == SH2) + fax->stage = SNORMAL; + } + + return fz_okay; + } + + code = getcode(fax, cf_2d_decode, cfd_2d_initial_bits); + + switch (code) + { + case H: + fax->stage = SH1; + break; + + case P: + b1 = findchangingcolor(fax->ref, fax->a, fax->columns, !fax->c); + b2 = findchanging(fax->ref, b1, fax->columns); + if (fax->c) setbits(fax->dst, fax->a, b2); + fax->a = b2; + break; + + case V0: + b1 = findchangingcolor(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 = findchangingcolor(fax->ref, fax->a, fax->columns, !fax->c); + if (fax->c) setbits(fax->dst, fax->a, b1 + 1); + fax->a = b1 + 1; + fax->c = !fax->c; + break; + + case VR2: + b1 = findchangingcolor(fax->ref, fax->a, fax->columns, !fax->c); + if (fax->c) setbits(fax->dst, fax->a, b1 + 2); + fax->a = b1 + 2; + fax->c = !fax->c; + break; + + case VR3: + b1 = findchangingcolor(fax->ref, fax->a, fax->columns, !fax->c); + if (fax->c) setbits(fax->dst, fax->a, b1 + 3); + fax->a = b1 + 3; + fax->c = !fax->c; + break; + + case VL1: + b1 = findchangingcolor(fax->ref, fax->a, fax->columns, !fax->c); + if (fax->c) setbits(fax->dst, fax->a, b1 - 1); + fax->a = b1 - 1; + fax->c = !fax->c; + break; + + case VL2: + b1 = findchangingcolor(fax->ref, fax->a, fax->columns, !fax->c); + if (fax->c) setbits(fax->dst, fax->a, b1 - 2); + fax->a = b1 - 2; + fax->c = !fax->c; + break; + + case VL3: + b1 = findchangingcolor(fax->ref, fax->a, fax->columns, !fax->c); + if (fax->c) setbits(fax->dst, fax->a, b1 - 3); + fax->a = b1 - 3; + fax->c = !fax->c; + break; + + case UNCOMPRESSED: + return fz_throw("uncompressed data in faxd"); + + case ERROR: + return fz_throw("invalid code in 2d faxd"); + + default: + return fz_throw("invalid code in 2d faxd (%d)", code); + } + + return 0; +} + +fz_error * +fz_processfaxd(fz_filter *f, fz_buffer *in, fz_buffer *out) +{ + fz_faxd *fax = (fz_faxd*)f; + fz_error *error; + int i; + unsigned char *tmp; + + if (fax->stage == SEOL) + goto eol; + +loop: + + if (fillbits(fax, in)) + { + if (in->eof) + { + if (fax->bidx > 31) + { + if (fax->a > 0) + goto eol; + goto rtc; + } + } + else + { + return fz_ioneedin; + } + } + + if ((fax->word >> (32 - 12)) == 0) + { + eatbits(fax, 1); + goto loop; + } + + if ((fax->word >> (32 - 12)) == 1) + { + eatbits(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; + eatbits(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; + eatbits(fax, 1); + } + else if (fax->dim == 1) + { + fax->eolc = 0; + error = dec1d(fax); + if (error) return error; /* can be fz_io* or real error */ + + } + else if (fax->dim == 2) + { + fax->eolc = 0; + error = dec2d(fax); + if (error) return error; /* can be fz_io* or real error */ + } + + /* no eol check after makeup codes nor in the middle of an H code */ + if (fax->stage == SMAKEUP || fax->stage == SH1 || fax->stage == SH2) + 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 = SEOL; + if (out->wp + fax->stride > out->ep) + return fz_ioneedout; + + if (fax->blackis1) + memcpy(out->wp, fax->dst, fax->stride); + else { + unsigned char * restrict d = out->wp; + unsigned char * restrict s = fax->dst; + unsigned w = fax->stride; + for (i = 0; i < w; i++) + *d++ = *s++ ^ 0xff; + } + + tmp = fax->ref; + fax->ref = fax->dst; + fax->dst = tmp; + memset(fax->dst, 0, fax->stride); + out->wp += fax->stride; + + fax->stage = SNORMAL; + fax->c = 0; + fax->a = -1; + fax->ridx ++; + + if (!fax->endofblock && 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 endofline & encodedbytealign, EOLs are *not* optional */ + if (fax->encodedbytealign) + { + if (fax->endofline) + eatbits(fax, (12 - fax->bidx) & 7); + else + eatbits(fax, (8 - fax->bidx) & 7); + } + + goto loop; + +rtc: + i = (32 - fax->bidx) / 8; + while (i-- && in->rp > in->bp) + in->rp --; + + return fz_iodone; +} + diff --git a/fitz/filt_faxd.h b/fitz/filt_faxd.h new file mode 100644 index 00000000..9f3fb470 --- /dev/null +++ b/fitz/filt_faxd.h @@ -0,0 +1,61 @@ +/* Fax G3/G4 tables */ + +/* + 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 +}; + +/* Decoding tables */ + +extern const cfd_node cf_white_decode[]; +extern const cfd_node cf_black_decode[]; +extern const cfd_node cf_2d_decode[]; +extern const cfd_node cf_uncompressed_decode[]; + diff --git a/fitz/filt_faxdtab.c b/fitz/filt_faxdtab.c new file mode 100644 index 00000000..6efcf053 --- /dev/null +++ b/fitz/filt_faxdtab.c @@ -0,0 +1,931 @@ +/* Tables for CCITTFaxDecode filter. */ + +/* This file was generated automatically. It is governed by the same terms */ +/* as the files scfetab.c and scfdgen.c from which it was derived. */ +/* Consult those files for the licensing terms and conditions. */ + +#include "filt_faxd.h" + +/* White decoding table. */ +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. */ +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. */ +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 } +}; + +/* Uncompresssed decoding table. */ +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 } +}; + +/* Dummy executable code to pacify compilers. */ +void scfdtab_dummy(void) { } + diff --git a/fitz/filt_faxe.c b/fitz/filt_faxe.c new file mode 100644 index 00000000..7551fb80 --- /dev/null +++ b/fitz/filt_faxe.c @@ -0,0 +1,407 @@ +#include "fitz-base.h" +#include "fitz-stream.h" + +#include "filt_faxe.h" +#include "filt_faxc.h" + +/* TODO: honor Rows param */ + +typedef struct fz_faxe_s fz_faxe; + +struct fz_faxe_s +{ + fz_filter super; + + int k; + int endofline; + int encodedbytealign; + int columns; + int endofblock; + int blackis1; + + int stride; + int ridx; /* how many rows in total */ + int bidx; /* how many bits are already used in out->wp */ + unsigned char bsave; /* partial byte saved between process() calls */ + + int stage; + int a0, c; /* mid-line coding state */ + + unsigned char *ref; + unsigned char *src; +}; + +fz_error * +fz_newfaxe(fz_filter **fp, fz_obj *params) +{ + fz_obj *obj; + + FZ_NEWFILTER(fz_faxe, fax, faxe); + + fax->ref = nil; + fax->src = nil; + + fax->k = 0; + fax->endofline = 0; + fax->encodedbytealign = 0; + fax->columns = 1728; + fax->endofblock = 1; + fax->blackis1 = 0; + + obj = fz_dictgets(params, "K"); + if (obj) fax->k = fz_toint(obj); + + obj = fz_dictgets(params, "EndOfLine"); + if (obj) fax->endofline = fz_tobool(obj); + + obj = fz_dictgets(params, "EncodedByteAlign"); + if (obj) fax->encodedbytealign = fz_tobool(obj); + + obj = fz_dictgets(params, "Columns"); + if (obj) fax->columns = fz_toint(obj); + + obj = fz_dictgets(params, "EndOfBlock"); + if (obj) fax->endofblock = fz_tobool(obj); + + obj = fz_dictgets(params, "BlackIs1"); + if (obj) fax->blackis1 = fz_tobool(obj); + + fax->stride = ((fax->columns - 1) >> 3) + 1; + fax->bidx = 0; + fax->ridx = 0; + + fax->stage = 0; + fax->a0 = -1; + fax->c = 0; + + fax->ref = fz_malloc(fax->stride); + if (!fax->ref) + { + fz_free(fax); + return fz_throw("outofmemory: scanline buffer one"); + } + + fax->src = fz_malloc(fax->stride); + if (!fax->src) + { + fz_free(fax); + fz_free(fax->ref); + return fz_throw("outofmemory: scanline buffer two"); + } + + memset(fax->ref, 0, fax->stride); + memset(fax->src, 0, fax->stride); + + return fz_okay; +} + +void +fz_dropfaxe(fz_filter *p) +{ + fz_faxe *fax = (fz_faxe*) p; + fz_free(fax->src); + fz_free(fax->ref); +} + +enum { codebytes = 2 }; + +static inline int runbytes(int run) +{ + int m = (run / 64) / 40 + 1; /* number of makeup codes */ + return codebytes * (m + 1); /* bytes for makeup + term codes */ +} + +static void +putbits(fz_faxe *fax, fz_buffer *out, int code, int nbits) +{ + while (nbits > 0) + { + if (fax->bidx == 0) + *out->wp = 0; + + /* code does not fit: shift right */ + if (nbits > (8 - fax->bidx)) + { + *out->wp |= code >> (nbits - (8 - fax->bidx)); + nbits = nbits - (8 - fax->bidx); + fax->bidx = 0; + out->wp ++; + } + + /* shift left */ + else + { + *out->wp |= code << ((8 - fax->bidx) - nbits); + fax->bidx += nbits; + if (fax->bidx == 8) + { + fax->bidx = 0; + out->wp ++; + } + nbits = 0; + } + } +} + +static inline void +putcode(fz_faxe *fax, fz_buffer *out, const cfe_code *run) +{ + putbits(fax, out, run->code, run->nbits); +} + +static void +putrun(fz_faxe *fax, fz_buffer *out, int run, int c) +{ + int m; + + const cf_runs *codetable = c ? &cf_black_runs : &cf_white_runs; + + if (run > 63) + { + m = run / 64; + while (m > 40) + { + putcode(fax, out, &codetable->makeup[40]); + m -= 40; + } + if (m > 0) + { + putcode(fax, out, &codetable->makeup[m]); + } + putcode(fax, out, &codetable->termination[run % 64]); + } + else + { + putcode(fax, out, &codetable->termination[run]); + } +} + +static fz_error * +enc1d(fz_faxe *fax, unsigned char *line, fz_buffer *out) +{ + int run; + + if (fax->a0 < 0) + fax->a0 = 0; + + while (fax->a0 < fax->columns) + { + run = getrun(line, fax->a0, fax->columns, fax->c); + + if (out->wp + 1 + runbytes(run) > out->ep) + return fz_ioneedout; + + putrun(fax, out, run, fax->c); + + fax->a0 += run; + fax->c = !fax->c; + } + + return fz_okay; +} + +static fz_error * +enc2d(fz_faxe *fax, unsigned char *ref, unsigned char *src, fz_buffer *out) +{ + int a1, a2, b1, b2; + int run1, run2, n; + + while (fax->a0 < fax->columns) + { + a1 = findchanging(src, fax->a0, fax->columns); + b1 = findchangingcolor(ref, fax->a0, fax->columns, !fax->c); + b2 = findchanging(ref, b1, fax->columns); + + /* pass */ + if (b2 < a1) + { + if (out->wp + 1 + codebytes > out->ep) + return fz_ioneedout; + + putcode(fax, out, &cf2_run_pass); + + fax->a0 = b2; + } + + /* vertical */ + else if (ABS(b1 - a1) <= 3) + { + if (out->wp + 1 + codebytes > out->ep) + return fz_ioneedout; + + putcode(fax, out, &cf2_run_vertical[b1 - a1 + 3]); + + fax->a0 = a1; + fax->c = !fax->c; + } + + /* horizontal */ + else + { + a2 = findchanging(src, a1, fax->columns); + run1 = a1 - fax->a0; + run2 = a2 - a1; + n = codebytes + runbytes(run1) + runbytes(run2); + + if (out->wp + 1 + n > out->ep) + return fz_ioneedout; + + putcode(fax, out, &cf2_run_horizontal); + putrun(fax, out, run1, fax->c); + putrun(fax, out, run2, !fax->c); + + fax->a0 = a2; + } + } + + return fz_okay; +} + +static fz_error * +process(fz_faxe *fax, fz_buffer *in, fz_buffer *out) +{ + fz_error *error; + int i, n; + + while (1) + { + if (in->rp == in->wp && in->eof) + goto rtc; + + switch (fax->stage) + { + case 0: + if (fax->encodedbytealign) + { + if (fax->endofline) + { + if (out->wp + 1 + 1 > out->ep) + return fz_ioneedout; + + /* make sure that EOL ends on a byte border */ + putbits(fax, out, 0, (12 - fax->bidx) & 7); + } + else + { + if (fax->bidx) + { + if (out->wp + 1 > out->ep) + return fz_ioneedout; + fax->bidx = 0; + out->wp ++; + } + } + } + + fax->stage ++; + + case 1: + if (fax->endofline) + { + if (out->wp + 1 + codebytes + 1 > out->ep) + return fz_ioneedout; + + if (fax->k > 0) + { + if (fax->ridx % fax->k == 0) + putcode(fax, out, &cf2_run_eol_1d); + else + putcode(fax, out, &cf2_run_eol_2d); + } + else + { + putcode(fax, out, &cf_run_eol); + } + } + + fax->stage ++; + + case 2: + if (in->rp + fax->stride > in->wp) + { + if (in->eof) /* XXX barf here? */ + goto rtc; + return fz_ioneedin; + } + + memcpy(fax->ref, fax->src, fax->stride); + memcpy(fax->src, in->rp, fax->stride); + + if (!fax->blackis1) + { + for (i = 0; i < fax->stride; i++) + fax->src[i] = ~fax->src[i]; + } + + in->rp += fax->stride; + + fax->c = 0; + fax->a0 = -1; + + fax->stage ++; + + case 3: + error = 0; /* to silence compiler */ + + if (fax->k < 0) + error = enc2d(fax, fax->ref, fax->src, out); + + else if (fax->k == 0) + error = enc1d(fax, fax->src, out); + + else if (fax->k > 0) + { + if (fax->ridx % fax->k == 0) + error = enc1d(fax, fax->src, out); + else + error = enc2d(fax, fax->ref, fax->src, out); + } + + if (error) + return error; /* one of fz_io* */ + + fax->ridx ++; + + fax->stage = 0; + } + } + +rtc: + if (fax->endofblock) + { + n = fax->k < 0 ? 2 : 6; + + if (out->wp + 1 + codebytes * n > out->ep) + return fz_ioneedout; + + for (i = 0; i < n; i++) + { + putcode(fax, out, &cf_run_eol); + if (fax->k > 0) + putbits(fax, out, 1, 1); + } + } + + if (fax->bidx) + out->wp ++; + + return fz_iodone; +} + +fz_error * +fz_processfaxe(fz_filter *p, fz_buffer *in, fz_buffer *out) +{ + fz_faxe *fax = (fz_faxe*) p; + fz_error *error; + + /* restore partial bits */ + *out->wp = fax->bsave; + + error = process(fax, in, out); + + /* save partial bits */ + fax->bsave = *out->wp; + + return error; +} + diff --git a/fitz/filt_faxe.h b/fitz/filt_faxe.h new file mode 100644 index 00000000..dd3fc121 --- /dev/null +++ b/fitz/filt_faxe.h @@ -0,0 +1,37 @@ +/* Fax G3/G4 tables */ + +typedef struct cfe_code_s cfe_code; + +struct cfe_code_s +{ + unsigned short code; + unsigned short nbits; +}; + +typedef struct cf_runs_s { + cfe_code termination[64]; + cfe_code makeup[41]; +} cf_runs; + +/* Encoding tables */ + +/* Codes common to 1-D and 2-D encoding. */ +extern const cfe_code cf_run_eol; +extern const cf_runs cf_white_runs, cf_black_runs; +extern const cfe_code cf_uncompressed[6]; +extern const cfe_code cf_uncompressed_exit[10]; /* indexed by 2 x length of */ + +/* 1-D encoding. */ +extern const cfe_code cf1_run_uncompressed; + +/* 2-D encoding. */ +enum { cf2_run_vertical_offset = 3 }; +extern const cfe_code cf2_run_pass; +extern const cfe_code cf2_run_vertical[7]; /* indexed by b1 - a1 + offset */ +extern const cfe_code cf2_run_horizontal; +extern const cfe_code cf2_run_uncompressed; + +/* 2-D Group 3 encoding. */ +extern const cfe_code cf2_run_eol_1d; +extern const cfe_code cf2_run_eol_2d; + diff --git a/fitz/filt_faxetab.c b/fitz/filt_faxetab.c new file mode 100644 index 00000000..34914c2d --- /dev/null +++ b/fitz/filt_faxetab.c @@ -0,0 +1,131 @@ +/* Tables for CCITTFaxEncode filter */ + +#include "filt_faxe.h" + +/* Define the end-of-line code. */ +const cfe_code cf_run_eol = {1, 12}; + +/* Define the 1-D code that signals uncompressed data. */ +const cfe_code cf1_run_uncompressed = {0xf, 12}; + +/* Define the 2-D run codes. */ +const cfe_code cf2_run_pass = {0x1, 4}; +const cfe_code cf2_run_vertical[7] = +{ + {0x3, 7}, + {0x3, 6}, + {0x3, 3}, + {0x1, 1}, + {0x2, 3}, + {0x2, 6}, + {0x2, 7} +}; +const cfe_code cf2_run_horizontal = {1, 3}; +const cfe_code cf2_run_uncompressed = {0xf, 10}; + +/* EOL codes for Group 3 2-D. */ +const cfe_code cf2_run_eol_1d = { (1 << 1) + 1, 12 + 1}; +const cfe_code cf2_run_eol_2d = { (1 << 1) + 0, 12 + 1}; + +/* White run codes. */ +const cf_runs cf_white_runs = +{ + /* Termination codes */ + { + {0x35, 8}, {0x7, 6}, {0x7, 4}, {0x8, 4}, + {0xb, 4}, {0xc, 4}, {0xe, 4}, {0xf, 4}, + {0x13, 5}, {0x14, 5}, {0x7, 5}, {0x8, 5}, + {0x8, 6}, {0x3, 6}, {0x34, 6}, {0x35, 6}, + {0x2a, 6}, {0x2b, 6}, {0x27, 7}, {0xc, 7}, + {0x8, 7}, {0x17, 7}, {0x3, 7}, {0x4, 7}, + {0x28, 7}, {0x2b, 7}, {0x13, 7}, {0x24, 7}, + {0x18, 7}, {0x2, 8}, {0x3, 8}, {0x1a, 8}, + {0x1b, 8}, {0x12, 8}, {0x13, 8}, {0x14, 8}, + {0x15, 8}, {0x16, 8}, {0x17, 8}, {0x28, 8}, + {0x29, 8}, {0x2a, 8}, {0x2b, 8}, {0x2c, 8}, + {0x2d, 8}, {0x4, 8}, {0x5, 8}, {0xa, 8}, + {0xb, 8}, {0x52, 8}, {0x53, 8}, {0x54, 8}, + {0x55, 8}, {0x24, 8}, {0x25, 8}, {0x58, 8}, + {0x59, 8}, {0x5a, 8}, {0x5b, 8}, {0x4a, 8}, + {0x4b, 8}, {0x32, 8}, {0x33, 8}, {0x34, 8} + }, + + /* Make-up codes */ + { + {0, 0} /* dummy */ , {0x1b, 5}, {0x12, 5}, {0x17, 6}, + {0x37, 7}, {0x36, 8}, {0x37, 8}, {0x64, 8}, + {0x65, 8}, {0x68, 8}, {0x67, 8}, {0xcc, 9}, + {0xcd, 9}, {0xd2, 9}, {0xd3, 9}, {0xd4, 9}, + {0xd5, 9}, {0xd6, 9}, {0xd7, 9}, {0xd8, 9}, + {0xd9, 9}, {0xda, 9}, {0xdb, 9}, {0x98, 9}, + {0x99, 9}, {0x9a, 9}, {0x18, 6}, {0x9b, 9}, + {0x8, 11}, {0xc, 11}, {0xd, 11}, {0x12, 12}, + {0x13, 12}, {0x14, 12}, {0x15, 12}, {0x16, 12}, + {0x17, 12}, {0x1c, 12}, {0x1d, 12}, {0x1e, 12}, + {0x1f, 12} + } +}; + +/* Black run codes. */ +const cf_runs cf_black_runs = +{ + /* Termination codes */ + { + {0x37, 10}, {0x2, 3}, {0x3, 2}, {0x2, 2}, + {0x3, 3}, {0x3, 4}, {0x2, 4}, {0x3, 5}, + {0x5, 6}, {0x4, 6}, {0x4, 7}, {0x5, 7}, + {0x7, 7}, {0x4, 8}, {0x7, 8}, {0x18, 9}, + {0x17, 10}, {0x18, 10}, {0x8, 10}, {0x67, 11}, + {0x68, 11}, {0x6c, 11}, {0x37, 11}, {0x28, 11}, + {0x17, 11}, {0x18, 11}, {0xca, 12}, {0xcb, 12}, + {0xcc, 12}, {0xcd, 12}, {0x68, 12}, {0x69, 12}, + {0x6a, 12}, {0x6b, 12}, {0xd2, 12}, {0xd3, 12}, + {0xd4, 12}, {0xd5, 12}, {0xd6, 12}, {0xd7, 12}, + {0x6c, 12}, {0x6d, 12}, {0xda, 12}, {0xdb, 12}, + {0x54, 12}, {0x55, 12}, {0x56, 12}, {0x57, 12}, + {0x64, 12}, {0x65, 12}, {0x52, 12}, {0x53, 12}, + {0x24, 12}, {0x37, 12}, {0x38, 12}, {0x27, 12}, + {0x28, 12}, {0x58, 12}, {0x59, 12}, {0x2b, 12}, + {0x2c, 12}, {0x5a, 12}, {0x66, 12}, {0x67, 12} + }, + + /* Make-up codes. */ + { + {0, 0} /* dummy */ , {0xf, 10}, {0xc8, 12}, {0xc9, 12}, + {0x5b, 12}, {0x33, 12}, {0x34, 12}, {0x35, 12}, + {0x6c, 13}, {0x6d, 13}, {0x4a, 13}, {0x4b, 13}, + {0x4c, 13}, {0x4d, 13}, {0x72, 13}, {0x73, 13}, + {0x74, 13}, {0x75, 13}, {0x76, 13}, {0x77, 13}, + {0x52, 13}, {0x53, 13}, {0x54, 13}, {0x55, 13}, + {0x5a, 13}, {0x5b, 13}, {0x64, 13}, {0x65, 13}, + {0x8, 11}, {0xc, 11}, {0xd, 11}, {0x12, 12}, + {0x13, 12}, {0x14, 12}, {0x15, 12}, {0x16, 12}, + {0x17, 12}, {0x1c, 12}, {0x1d, 12}, {0x1e, 12}, + {0x1f, 12} + } +}; + +/* Uncompressed codes. */ +const cfe_code cf_uncompressed[6] = +{ + {1, 1}, + {1, 2}, + {1, 3}, + {1, 4}, + {1, 5}, + {1, 6} +}; + +/* Uncompressed exit codes. */ +const cfe_code cf_uncompressed_exit[10] = +{ + {2, 8}, {3, 8}, + {2, 9}, {3, 9}, + {2, 10}, {3, 10}, + {2, 11}, {3, 11}, + {2, 12}, {3, 12} +}; + +/* Some C compilers insist on having executable code in every file.... */ +void scfetab_dummy(void) { } + diff --git a/fitz/filt_flate.c b/fitz/filt_flate.c new file mode 100644 index 00000000..6a86da3a --- /dev/null +++ b/fitz/filt_flate.c @@ -0,0 +1,208 @@ +#include "fitz-base.h" +#include "fitz-stream.h" + +#include + +typedef struct fz_flate_s fz_flate; + +struct fz_flate_s +{ + fz_filter super; + z_stream z; +}; + +static void * +zmalloc(void *opaque, unsigned int items, unsigned int size) +{ + return fz_malloc(items * size); +} + +fz_error * +fz_newflated(fz_filter **fp, fz_obj *params) +{ + fz_error *eo; + fz_obj *obj; + int zipfmt; + int ei; + + FZ_NEWFILTER(fz_flate, f, flated); + + f->z.zalloc = zmalloc; + f->z.zfree = (void(*)(void*,void*))fz_currentmemorycontext()->free; + f->z.opaque = fz_currentmemorycontext(); + f->z.next_in = nil; + f->z.avail_in = 0; + + zipfmt = 0; + + if (params) + { + obj = fz_dictgets(params, "ZIP"); + if (obj) zipfmt = fz_tobool(obj); + } + + if (zipfmt) + { + /* if windowbits is negative the zlib header is skipped */ + ei = inflateInit2(&f->z, -15); + } + else + ei = inflateInit(&f->z); + + if (ei != Z_OK) + { + eo = fz_throw("zlib error: inflateInit: %s", f->z.msg); + fz_free(f); + return eo; + } + + return fz_okay; +} + +void +fz_dropflated(fz_filter *f) +{ + z_streamp zp = &((fz_flate*)f)->z; + int err; + + err = inflateEnd(zp); + if (err != Z_OK) + fprintf(stderr, "inflateEnd: %s", zp->msg); +} + +fz_error * +fz_processflated(fz_filter *f, fz_buffer *in, fz_buffer *out) +{ + z_streamp zp = &((fz_flate*)f)->z; + int err; + + if (in->rp == in->wp && !in->eof) + return fz_ioneedin; + if (out->wp == out->ep) + return fz_ioneedout; + + zp->next_in = in->rp; + zp->avail_in = in->wp - in->rp; + + zp->next_out = out->wp; + zp->avail_out = out->ep - out->wp; + + err = inflate(zp, Z_NO_FLUSH); + + in->rp = in->wp - zp->avail_in; + out->wp = out->ep - zp->avail_out; + + if (err == Z_STREAM_END || err == Z_BUF_ERROR) + { + return fz_iodone; + } + else if (err == Z_OK) + { + if (in->rp == in->wp && !in->eof) + return fz_ioneedin; + if (out->wp == out->ep) + return fz_ioneedout; + return fz_ioneedin; /* hmm, what's going on here? */ + } + else + { + return fz_throw("zlib error: inflate: %s", zp->msg); + } +} + +fz_error * +fz_newflatee(fz_filter **fp, fz_obj *params) +{ + fz_obj *obj; + fz_error *eo; + int effort; + int zipfmt; + int ei; + + FZ_NEWFILTER(fz_flate, f, flatee); + + effort = -1; + zipfmt = 0; + + if (params) + { + obj = fz_dictgets(params, "Effort"); + if (obj) effort = fz_toint(obj); + obj = fz_dictgets(params, "ZIP"); + if (obj) zipfmt = fz_tobool(obj); + } + + f->z.zalloc = zmalloc; + f->z.zfree = (void(*)(void*,void*))fz_currentmemorycontext()->free; + f->z.opaque = fz_currentmemorycontext(); + f->z.next_in = nil; + f->z.avail_in = 0; + + if (zipfmt) + ei = deflateInit2(&f->z, effort, Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY); + else + ei = deflateInit(&f->z, effort); + + if (ei != Z_OK) + { + eo = fz_throw("zlib error: deflateInit: %s", f->z.msg); + fz_free(f); + return eo; + } + + return fz_okay; +} + +void +fz_dropflatee(fz_filter *f) +{ + z_streamp zp = &((fz_flate*)f)->z; + int err; + + err = deflateEnd(zp); + if (err != Z_OK) + fprintf(stderr, "deflateEnd: %s", zp->msg); + + fz_free(f); +} + +fz_error * +fz_processflatee(fz_filter *f, fz_buffer *in, fz_buffer *out) +{ + z_streamp zp = &((fz_flate*)f)->z; + int err; + + if (in->rp == in->wp && !in->eof) + return fz_ioneedin; + if (out->wp == out->ep) + return fz_ioneedout; + + zp->next_in = in->rp; + zp->avail_in = in->wp - in->rp; + + zp->next_out = out->wp; + zp->avail_out = out->ep - out->wp; + + err = deflate(zp, in->eof ? Z_FINISH : Z_NO_FLUSH); + + in->rp = in->wp - zp->avail_in; + out->wp = out->ep - zp->avail_out; + + if (err == Z_STREAM_END) + { + return fz_iodone; + } + else if (err == Z_OK) + { + if (in->rp == in->wp && !in->eof) + return fz_ioneedin; + if (out->wp == out->ep) + return fz_ioneedout; + return fz_ioneedin; /* hmm? */ + } + else + { + return fz_throw("zlib error: deflate: %s", zp->msg); + } +} + diff --git a/fitz/filt_jbig2d.c b/fitz/filt_jbig2d.c new file mode 100644 index 00000000..3569d3eb --- /dev/null +++ b/fitz/filt_jbig2d.c @@ -0,0 +1,119 @@ +#include "fitz-base.h" +#include "fitz-stream.h" + +/* TODO: complete rewrite with error checking and use fitz memctx */ + +/* + so to use a global_ctx, you run your global data through a normal ctx + then call jbig2_make_global_ctx with the normal context + that does the (currently null) conversion + make_global_ctx after i fed it all the global stream data? + maskros: yes + and you pass the new global ctx object to jbig2_ctx_new() when you ++create the per-page ctx +*/ + +#ifdef WIN32 /* Microsoft Visual C++ */ + +typedef signed char int8_t; +typedef short int int16_t; +typedef int int32_t; +typedef __int64 int64_t; + +typedef unsigned char uint8_t; +typedef unsigned short int uint16_t; +typedef unsigned int uint32_t; + +#else +#include +#endif + +#include + +typedef struct fz_jbig2d_s fz_jbig2d; + +struct fz_jbig2d_s +{ + fz_filter super; + Jbig2Ctx *ctx; + Jbig2GlobalCtx *gctx; + Jbig2Image *page; + int idx; +}; + +fz_error * +fz_newjbig2d(fz_filter **fp, fz_obj *params) +{ + FZ_NEWFILTER(fz_jbig2d, d, jbig2d); + d->ctx = jbig2_ctx_new(nil, JBIG2_OPTIONS_EMBEDDED, nil, nil, nil); + d->page = nil; + d->idx = 0; + return fz_okay; +} + +void +fz_dropjbig2d(fz_filter *filter) +{ + fz_jbig2d *d = (fz_jbig2d*)filter; + jbig2_ctx_free(d->ctx); +} + +fz_error * +fz_setjbig2dglobalstream(fz_filter *filter, unsigned char *buf, int len) +{ + fz_jbig2d *d = (fz_jbig2d*)filter; + jbig2_data_in(d->ctx, buf, len); + d->gctx = jbig2_make_global_ctx(d->ctx); + d->ctx = jbig2_ctx_new(nil, JBIG2_OPTIONS_EMBEDDED, d->gctx, nil, nil); + return fz_okay; +} + +fz_error * +fz_processjbig2d(fz_filter *filter, fz_buffer *in, fz_buffer *out) +{ + fz_jbig2d *d = (fz_jbig2d*)filter; + int len; + int i; + + while (1) + { + if (in->rp == in->wp) { + if (!in->eof) + return fz_ioneedin; + + if (!d->page) { + jbig2_complete_page(d->ctx); + d->page = jbig2_page_out(d->ctx); + } + + if (out->wp == out->ep) + return fz_ioneedout; + + len = out->ep - out->wp; + if (d->idx + len > d->page->height * d->page->stride) + len = d->page->height * d->page->stride - d->idx; + + /* XXX memcpy(out->wp, d->page->data + d->idx, len); */ + { + unsigned char * restrict in = &d->page->data[d->idx]; + unsigned char * restrict o = out->wp; + for (i = 0; i < len; i++) + *o++ = 0xff ^ *in++; + } + + out->wp += len; + d->idx += len; + + if (d->idx == d->page->height * d->page->stride) { + jbig2_release_page(d->ctx, d->page); + return fz_iodone; + } + } + else { + len = in->wp - in->rp; + jbig2_data_in(d->ctx, in->rp, len); + in->rp += len; + } + } +} + diff --git a/fitz/filt_jpxd.c b/fitz/filt_jpxd.c new file mode 100644 index 00000000..28dc87de --- /dev/null +++ b/fitz/filt_jpxd.c @@ -0,0 +1,146 @@ +#include "fitz-base.h" +#include "fitz-stream.h" + +/* TODO: bpc */ + +/* + * We use the Jasper JPEG2000 coder for now. + */ + +#include + +static char *colorspacename(jas_clrspc_t clrspc) +{ + switch (jas_clrspc_fam(clrspc)) + { + case JAS_CLRSPC_FAM_UNKNOWN: return "Unknown"; + case JAS_CLRSPC_FAM_XYZ: return "XYZ"; + case JAS_CLRSPC_FAM_LAB: return "Lab"; + case JAS_CLRSPC_FAM_GRAY: return "Gray"; + case JAS_CLRSPC_FAM_RGB: return "RGB"; + case JAS_CLRSPC_FAM_YCBCR: return "YCbCr"; + } + return "Unknown"; +} + +typedef struct fz_jpxd_s fz_jpxd; + +struct fz_jpxd_s +{ + fz_filter super; + jas_stream_t *stream; + jas_image_t *image; + int offset; + int stage; +}; + +fz_error * +fz_newjpxd(fz_filter **fp, fz_obj *params) +{ + int err; + + FZ_NEWFILTER(fz_jpxd, d, jpxd); + + err = jas_init(); + if (err) + { + fz_free(d); + return fz_throw("jasper error: jas_init()"); + } + + d->stream = jas_stream_memopen(nil, 0); + if (!d->stream) + { + fz_free(d); + return fz_throw("jasper error: jas_stream_memopen()"); + } + + d->image = nil; + d->offset = 0; + d->stage = 0; + + return fz_okay; +} + +void +fz_dropjpxd(fz_filter *filter) +{ + fz_jpxd *d = (fz_jpxd*)filter; + if (d->stream) jas_stream_close(d->stream); + if (d->image) jas_image_destroy(d->image); +} + +fz_error * +fz_processjpxd(fz_filter *filter, fz_buffer *in, fz_buffer *out) +{ + fz_jpxd *d = (fz_jpxd*)filter; + int n, bpc, w, h; + int i, x, y; + + switch (d->stage) + { + case 0: goto input; + case 1: goto decode; + case 2: goto output; + } + +input: + while (in->rp < in->wp) + { + n = jas_stream_write(d->stream, in->rp, in->wp - in->rp); + in->rp += n; + } + + if (!in->eof) + return fz_ioneedin; + + d->stage = 1; + +decode: + jas_stream_seek(d->stream, 0, 0); + + d->image = jas_image_decode(d->stream, -1, 0); + if (!d->image) + return fz_throw("jasper error: jas_image_decode()"); + + fprintf(stderr, "P%c\n# JPX %d x %d n=%d bpc=%d colorspace=%04x %s\n%d %d\n%d\n", + jas_image_numcmpts(d->image) == 1 ? '5' : '6', + + jas_image_width(d->image), + jas_image_height(d->image), + jas_image_numcmpts(d->image), + jas_image_cmptprec(d->image, 0), + jas_image_clrspc(d->image), + colorspacename(jas_image_clrspc(d->image)), + + jas_image_width(d->image), + jas_image_height(d->image), + (1 << jas_image_cmptprec(d->image, 0)) - 1); + + d->stage = 2; + +output: + w = jas_image_width(d->image); + h = jas_image_height(d->image); + n = jas_image_numcmpts(d->image); + bpc = jas_image_cmptprec(d->image, 0); /* use precision of first component for all... */ + + while (d->offset < w * h) + { + y = d->offset / w; + x = d->offset - y * w; + + /* FIXME bpc != 8 */ + + if (out->wp + n >= out->ep) + return fz_ioneedout; + + for (i = 0; i < n; i++) + *out->wp++ = jas_image_readcmptsample(d->image, i, x, y); + + d->offset ++; + } + + return fz_iodone; +} + diff --git a/fitz/filt_lzwd.c b/fitz/filt_lzwd.c new file mode 100644 index 00000000..c4aed45b --- /dev/null +++ b/fitz/filt_lzwd.c @@ -0,0 +1,254 @@ +#include "fitz-base.h" +#include "fitz-stream.h" + +/* TODO: error checking */ + +enum +{ + MINBITS = 9, + MAXBITS = 12, + NUMCODES = (1 << MAXBITS), + LZW_CLEAR = 256, + LZW_EOD = 257, + LZW_FIRST = 258 +}; + +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 firstchar; /* first token of string */ +}; + +typedef struct fz_lzwd_s fz_lzwd; + +struct fz_lzwd_s +{ + fz_filter super; + + int earlychange; + + unsigned int word; /* bits loaded from data */ + int bidx; + + int resume; /* resume output of code from needout */ + int codebits; /* num bits/code */ + int code; /* current code */ + int oldcode; /* previously recognized code */ + int nextcode; /* next free entry */ + lzw_code table[NUMCODES]; +}; + +fz_error * +fz_newlzwd(fz_filter **fp, fz_obj *params) +{ + int i; + + FZ_NEWFILTER(fz_lzwd, lzw, lzwd); + + lzw->earlychange = 0; + + if (params) + { + fz_obj *obj; + obj = fz_dictgets(params, "EarlyChange"); + if (obj) lzw->earlychange = fz_toint(obj) != 0; + } + + lzw->bidx = 32; + lzw->word = 0; + + for (i = 0; i < 256; i++) + { + lzw->table[i].value = i; + lzw->table[i].firstchar = i; + lzw->table[i].length = 1; + lzw->table[i].prev = -1; + } + + for (i = 256; i < NUMCODES; i++) + { + lzw->table[i].value = 0; + lzw->table[i].firstchar = 0; + lzw->table[i].length = 0; + lzw->table[i].prev = -1; + } + + lzw->codebits = MINBITS; + lzw->code = -1; + lzw->nextcode = LZW_FIRST; + lzw->oldcode = -1; + lzw->resume = 0; + + return fz_okay; +} + +void +fz_droplzwd(fz_filter *filter) +{ +} + +static inline void eatbits(fz_lzwd *lzw, int nbits) +{ + lzw->word <<= nbits; + lzw->bidx += nbits; +} + +static inline fz_error * fillbits(fz_lzwd *lzw, fz_buffer *in) +{ + while (lzw->bidx >= 8) + { + if (in->rp + 1 > in->wp) + return fz_ioneedin; + lzw->bidx -= 8; + lzw->word |= *in->rp << lzw->bidx; + in->rp ++; + } + return fz_okay; +} + +static inline void unstuff(fz_lzwd *lzw, fz_buffer *in) +{ + int i = (32 - lzw->bidx) / 8; + while (i-- && in->rp > in->bp) + in->rp --; +} + +fz_error * +fz_processlzwd(fz_filter *filter, fz_buffer *in, fz_buffer *out) +{ + fz_lzwd *lzw = (fz_lzwd*)filter; + unsigned char *s; + int len; + + if (lzw->resume) + { + lzw->resume = 0; + goto output; + } + + while (1) + { + if (fillbits(lzw, in)) + { + if (in->eof) + { + if (lzw->bidx > 32 - lzw->codebits) + { + unstuff(lzw, in); + return fz_iodone; + } + } + else + { + return fz_ioneedin; + } + } + + lzw->code = lzw->word >> (32 - lzw->codebits); + + if (lzw->code == LZW_EOD) + { + eatbits(lzw, lzw->codebits); + unstuff(lzw, in); + return fz_iodone; + } + + if (lzw->code == LZW_CLEAR) + { + int oldcodebits = lzw->codebits; + + lzw->codebits = MINBITS; + lzw->nextcode = LZW_FIRST; + + lzw->code = lzw->word >> (32 - oldcodebits - MINBITS) & ((1 << MINBITS) - 1); + + if (lzw->code == LZW_EOD) + { + eatbits(lzw, oldcodebits + MINBITS); + unstuff(lzw, in); + return fz_iodone; + } + + eatbits(lzw, oldcodebits + MINBITS); + + lzw->oldcode = lzw->code; + + if (out->wp + 1 > out->ep) + { + lzw->resume = 1; + return fz_ioneedout; + } + + *out->wp++ = lzw->code; + + continue; + } + + eatbits(lzw, lzw->codebits); + + /* if stream starts without a clear code, oldcode is undefined... */ + if (lzw->oldcode == -1) + { + lzw->oldcode = lzw->code; + goto output; + } + + /* add new entry to the code table */ + lzw->table[lzw->nextcode].prev = lzw->oldcode; + lzw->table[lzw->nextcode].firstchar = lzw->table[lzw->oldcode].firstchar; + lzw->table[lzw->nextcode].length = lzw->table[lzw->oldcode].length + 1; + if (lzw->code < lzw->nextcode) + lzw->table[lzw->nextcode].value = lzw->table[lzw->code].firstchar; + else + lzw->table[lzw->nextcode].value = lzw->table[lzw->nextcode].firstchar; + + lzw->nextcode ++; + + if (lzw->nextcode >= (1 << lzw->codebits) - lzw->earlychange - 1) + { + lzw->codebits ++; + if (lzw->codebits > MAXBITS) + lzw->codebits = MAXBITS; /* FIXME */ + } + + lzw->oldcode = lzw->code; + +output: + /* code maps to a string, copy to output (in reverse...) */ + if (lzw->code > 255) + { + if (out->wp + lzw->table[lzw->code].length > out->ep) + { + lzw->resume = 1; + return fz_ioneedout; + } + + len = lzw->table[lzw->code].length; + s = out->wp + len; + + do + { + *(--s) = lzw->table[lzw->code].value; + lzw->code = lzw->table[lzw->code].prev; + } while (lzw->code >= 0 && s > out->wp); + out->wp += len; + } + + /* ... or just a single character */ + else + { + if (out->wp + 1 > out->ep) + { + lzw->resume = 1; + return fz_ioneedout; + } + + *out->wp++ = lzw->code; + } + } +} + diff --git a/fitz/filt_lzwe.c b/fitz/filt_lzwe.c new file mode 100644 index 00000000..5a221f9f --- /dev/null +++ b/fitz/filt_lzwe.c @@ -0,0 +1,261 @@ +#include "fitz-base.h" +#include "fitz-stream.h" + +#define noDEBUG 1 + +enum +{ + MINBITS = 9, + MAXBITS = 12, + MAXBYTES = 2, + NUMCODES = (1 << MAXBITS), + LZW_CLEAR = 256, + LZW_EOD = 257, + LZW_FIRST = 258, + HSIZE = 9001, /* 91% occupancy (???) */ + HSHIFT = (13 - 8) +}; + +typedef struct lzw_hash_s lzw_hash; + +struct lzw_hash_s +{ + int hash; + int code; +}; + +typedef struct fz_lzwe_s fz_lzwe; + +struct fz_lzwe_s +{ + fz_filter super; + + int earlychange; + + int bidx; /* partial bits used in out->wp */ + unsigned char bsave; /* partial byte saved between process() calls */ + + int resume; + int code; + int fcode; + int hcode; + + int codebits; + int oldcode; + int nextcode; + + lzw_hash table[HSIZE]; +}; + +static void +clearhash(fz_lzwe *lzw) +{ + int i; + for (i = 0; i < HSIZE; i++) + lzw->table[i].hash = -1; +} + +fz_error * +fz_newlzwe(fz_filter **fp, fz_obj *params) +{ + FZ_NEWFILTER(fz_lzwe, lzw, lzwe); + + lzw->earlychange = 0; + + if (params) + { + fz_obj *obj; + obj = fz_dictgets(params, "EarlyChange"); + if (obj) lzw->earlychange = fz_toint(obj) != 0; + } + + lzw->bidx = 0; + lzw->bsave = 0; + + lzw->resume = 0; + lzw->code = -1; + lzw->hcode = -1; + lzw->fcode = -1; + + lzw->codebits = MINBITS; + lzw->nextcode = LZW_FIRST; + lzw->oldcode = -1; /* generates LZW_CLEAR */ + + clearhash(lzw); + + return fz_okay; +} + +void +fz_droplzwe(fz_filter *filter) +{ +} + +static void +putcode(fz_lzwe *lzw, fz_buffer *out, int code) +{ + int nbits = lzw->codebits; + + while (nbits > 0) + { + if (lzw->bidx == 0) + { + *out->wp = 0; + } + + /* code does not fit: shift right */ + if (nbits > (8 - lzw->bidx)) + { + *out->wp |= code >> (nbits - (8 - lzw->bidx)); + nbits = nbits - (8 - lzw->bidx); + lzw->bidx = 0; + out->wp ++; + } + + /* shift left */ + else + { + *out->wp |= code << ((8 - lzw->bidx) - nbits); + lzw->bidx += nbits; + if (lzw->bidx == 8) + { + lzw->bidx = 0; + out->wp ++; + } + nbits = 0; + } + } +} + + +static fz_error * +compress(fz_lzwe *lzw, fz_buffer *in, fz_buffer *out) +{ + if (lzw->resume) + { + lzw->resume = 0; + goto resume; + } + + /* at start of data, output a clear code */ + if (lzw->oldcode == -1) + { + if (out->wp + 3 > out->ep) + return fz_ioneedout; + + if (in->rp + 1 > in->wp) + { + if (in->eof) + goto eof; + return fz_ioneedin; + } + + putcode(lzw, out, LZW_CLEAR); + + lzw->oldcode = *in->rp++; + } + +begin: + while (1) + { + if (in->rp + 1 > in->wp) + { + if (in->eof) + goto eof; + return fz_ioneedin; + } + + /* read character */ + lzw->code = *in->rp++; + + /* hash string + character */ + lzw->fcode = (lzw->code << MAXBITS) + lzw->oldcode; + lzw->hcode = (lzw->code << HSHIFT) ^ lzw->oldcode; + + /* primary hash */ + if (lzw->table[lzw->hcode].hash == lzw->fcode) + { + lzw->oldcode = lzw->table[lzw->hcode].code; + continue; + } + + /* secondary hash */ + if (lzw->table[lzw->hcode].hash != -1) + { + int disp = HSIZE - lzw->hcode; + if (lzw->hcode == 0) + disp = 1; + do + { + lzw->hcode = lzw->hcode - disp; + if (lzw->hcode < 0) + lzw->hcode += HSIZE; + if (lzw->table[lzw->hcode].hash == lzw->fcode) + { + lzw->oldcode = lzw->table[lzw->hcode].code; + goto begin; + } + } while (lzw->table[lzw->hcode].hash != -1); + } + +resume: + /* new entry: emit code and add to table */ + + /* reserve space for this code and an eventual CLEAR code */ + if (out->wp + 5 > out->ep) + { + lzw->resume = 1; + return fz_ioneedout; + } + + putcode(lzw, out, lzw->oldcode); + + lzw->oldcode = lzw->code; + lzw->table[lzw->hcode].code = lzw->nextcode; + lzw->table[lzw->hcode].hash = lzw->fcode; + + lzw->nextcode ++; + + /* table is full: emit clear code and reset */ + if (lzw->nextcode == NUMCODES - 1) + { + putcode(lzw, out, LZW_CLEAR); + clearhash(lzw); + lzw->nextcode = LZW_FIRST; + lzw->codebits = MINBITS; + } + + /* check if next entry will be too big for the code size */ + else if (lzw->nextcode >= (1 << lzw->codebits) - lzw->earlychange) + { + lzw->codebits ++; + } + } + +eof: + if (out->wp + 5 > out->ep) + return fz_ioneedout; + + putcode(lzw, out, lzw->oldcode); + putcode(lzw, out, LZW_EOD); + + return fz_iodone; +} + +fz_error * +fz_processlzwe(fz_filter *filter, fz_buffer *in, fz_buffer *out) +{ + fz_lzwe *lzw = (fz_lzwe*)filter; + fz_error *error; + + /* restore partial bits */ + *out->wp = lzw->bsave; + + error = compress(lzw, in, out); + + /* save partial bits */ + lzw->bsave = *out->wp; + + return error; +} + diff --git a/fitz/filt_null.c b/fitz/filt_null.c new file mode 100644 index 00000000..601ed815 --- /dev/null +++ b/fitz/filt_null.c @@ -0,0 +1,54 @@ +#include "fitz-base.h" +#include "fitz-stream.h" + +typedef struct fz_nullfilter_s fz_nullfilter; + +struct fz_nullfilter_s +{ + fz_filter super; + int len; + int cur; +}; + +fz_error * +fz_newnullfilter(fz_filter **fp, int len) +{ + FZ_NEWFILTER(fz_nullfilter, f, nullfilter); + f->len = len; + f->cur = 0; + return fz_okay; +} + +void +fz_dropnullfilter(fz_filter *f) +{ +} + +fz_error * +fz_processnullfilter(fz_filter *filter, fz_buffer *in, fz_buffer *out) +{ + fz_nullfilter *f = (fz_nullfilter*)filter; + int n; + + n = MIN(in->wp - in->rp, out->ep - out->wp); + if (f->len >= 0) + n = MIN(n, f->len - f->cur); + + if (n) + { + memcpy(out->wp, in->rp, n); + in->rp += n; + out->wp += n; + f->cur += n; + } + + if (f->cur == f->len) + return fz_iodone; + if (in->rp == in->wp) + return fz_ioneedin; + if (out->wp == out->ep) + return fz_ioneedout; + + return fz_throw("braindead programmer trapped in nullfilter"); +} + diff --git a/fitz/filt_pipeline.c b/fitz/filt_pipeline.c new file mode 100644 index 00000000..ea0b9885 --- /dev/null +++ b/fitz/filt_pipeline.c @@ -0,0 +1,139 @@ +#include "fitz-base.h" +#include "fitz-stream.h" + +#define noDEBUG 1 + +typedef struct fz_pipeline_s fz_pipeline; + +fz_error * fz_processpipeline(fz_filter *filter, fz_buffer *in, fz_buffer *out); + +struct fz_pipeline_s +{ + fz_filter super; + fz_filter *head; + fz_buffer *buffer; + fz_filter *tail; + int tailneedsin; +}; + +fz_error * +fz_chainpipeline(fz_filter **fp, fz_filter *head, fz_filter *tail, fz_buffer *buf) +{ + FZ_NEWFILTER(fz_pipeline, p, pipeline); + p->head = fz_keepfilter(head); + p->tail = fz_keepfilter(tail); + p->tailneedsin = 1; + p->buffer = fz_keepbuffer(buf); + return fz_okay; +} + +void +fz_unchainpipeline(fz_filter *filter, fz_filter **oldfp, fz_buffer **oldbp) +{ + fz_pipeline *p = (fz_pipeline*)filter; + + *oldfp = fz_keepfilter(p->head); + *oldbp = fz_keepbuffer(p->buffer); + + fz_dropfilter(filter); +} + +fz_error * +fz_newpipeline(fz_filter **fp, fz_filter *head, fz_filter *tail) +{ + fz_error *error; + + FZ_NEWFILTER(fz_pipeline, p, pipeline); + p->head = fz_keepfilter(head); + p->tail = fz_keepfilter(tail); + p->tailneedsin = 1; + + error = fz_newbuffer(&p->buffer, FZ_BUFSIZE); + if (error) + { + fz_free(p); + return fz_rethrow(error, "cannot create buffer"); + } + + return fz_okay; +} + +void +fz_droppipeline(fz_filter *filter) +{ + fz_pipeline *p = (fz_pipeline*)filter; + fz_dropfilter(p->head); + fz_dropfilter(p->tail); + fz_dropbuffer(p->buffer); +} + +fz_error * +fz_processpipeline(fz_filter *filter, fz_buffer *in, fz_buffer *out) +{ + fz_pipeline *p = (fz_pipeline*)filter; + fz_error *e; + + if (p->buffer->eof) + goto tail; + + if (p->tailneedsin && p->head->produced) + goto tail; + +head: + e = fz_process(p->head, in, p->buffer); + + if (e == fz_ioneedin) + return fz_ioneedin; + + else if (e == fz_ioneedout) + { + if (p->tailneedsin && !p->head->produced) + { + fz_error *be = nil; + if (p->buffer->rp > p->buffer->bp) + be = fz_rewindbuffer(p->buffer); + else + be = fz_growbuffer(p->buffer); + if (be) + return be; + goto head; + } + goto tail; + } + + else if (e == fz_iodone) + goto tail; + + else if (e) + return fz_rethrow(e, "cannot process head filter"); + + else + return fz_okay; + +tail: + e = fz_process(p->tail, p->buffer, out); + + if (e == fz_ioneedin) + { + if (p->buffer->eof) + return fz_throw("ioerror: premature eof in pipeline"); + p->tailneedsin = 1; + goto head; + } + + else if (e == fz_ioneedout) + { + p->tailneedsin = 0; + return fz_ioneedout; + } + + else if (e == fz_iodone) + return fz_iodone; + + else if (e) + return fz_rethrow(e, "cannot process tail filter"); + + else + return fz_okay; +} + diff --git a/fitz/filt_predict.c b/fitz/filt_predict.c new file mode 100644 index 00000000..4654e792 --- /dev/null +++ b/fitz/filt_predict.c @@ -0,0 +1,254 @@ +#include "fitz-base.h" +#include "fitz-stream.h" + +/* TODO: check if this works with 16bpp images */ + +enum { MAXC = 32 }; + +typedef struct fz_predict_s fz_predict; + +struct fz_predict_s +{ + fz_filter super; + + int predictor; + int columns; + int colors; + int bpc; + + int stride; + int bpp; + unsigned char *ref; + + int encode; +}; + +fz_error * +fz_newpredict(fz_filter **fp, fz_obj *params, int encode) +{ + fz_obj *obj; + + FZ_NEWFILTER(fz_predict, p, predict); + + p->encode = encode; + + p->predictor = 1; + p->columns = 1; + p->colors = 1; + p->bpc = 8; + + obj = fz_dictgets(params, "Predictor"); + if (obj) p->predictor = fz_toint(obj); + + obj = fz_dictgets(params, "Columns"); + if (obj) p->columns = fz_toint(obj); + + obj = fz_dictgets(params, "Colors"); + if (obj) p->colors = fz_toint(obj); + + obj = fz_dictgets(params, "BitsPerComponent"); + if (obj) p->bpc = fz_toint(obj); + + p->stride = (p->bpc * p->colors * p->columns + 7) / 8; + p->bpp = (p->bpc * p->colors + 7) / 8; + + if (p->predictor >= 10) + { + p->ref = fz_malloc(p->stride); + if (!p->ref) + { + fz_free(p); + return fz_throw("outofmem: scanline buffer"); + } + memset(p->ref, 0, p->stride); + } + else + { + p->ref = nil; + } + + return fz_okay; +} + +void +fz_droppredict(fz_filter *filter) +{ + fz_predict *p = (fz_predict*)filter; + fz_free(p->ref); +} + +static inline int +getcomponent(unsigned char *buf, int x, int bpc) +{ + switch (bpc) + { + case 1: return buf[x / 8] >> (7 - (x % 8)) & 0x01; + case 2: return buf[x / 4] >> ((3 - (x % 4)) * 2) & 0x03; + case 4: return buf[x / 2] >> ((1 - (x % 2)) * 4) & 0x0f; + case 8: return buf[x]; + } + return 0; +} + +static inline void +putcomponent(unsigned char *buf, int x, int bpc, int value) +{ + switch (bpc) + { + case 1: buf[x / 8] |= value << (7 - (x % 8)); break; + case 2: buf[x / 4] |= value << ((3 - (x % 4)) * 2); break; + case 4: buf[x / 2] |= value << ((1 - (x % 2)) * 4); break; + case 8: buf[x] = 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 = (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 inline void +none(fz_predict *p, unsigned char *in, unsigned char *out) +{ + memcpy(out, in, p->stride); +} + +static void +tiff(fz_predict *p, unsigned char *in, unsigned char *out) +{ + int left[MAXC]; + int i, k; + + for (k = 0; k < p->colors; k++) + left[k] = 0; + + for (i = 0; i < p->columns; i++) + { + for (k = 0; k < p->colors; k++) + { + int a = getcomponent(in, i * p->colors + k, p->bpc); + int b = p->encode ? a - left[k] : a + left[k]; + int c = b % (1 << p->bpc); + putcomponent(out, i * p->colors + k, p->bpc, c); + left[k] = p->encode ? a : c; + } + } +} + +static void +png(fz_predict *p, unsigned char *in, unsigned char *out, int predictor) +{ + int upleft[MAXC], left[MAXC], i, k; + + for (k = 0; k < p->bpp; k++) + { + left[k] = 0; + upleft[k] = 0; + } + + if (p->encode) + { + for (k = 0, i = 0; i < p->stride; k = (k + 1) % p->bpp, i ++) + { + switch (predictor) + { + case 0: out[i] = in[i]; break; + case 1: out[i] = in[i] - left[k]; break; + case 2: out[i] = in[i] - p->ref[i]; break; + case 3: out[i] = in[i] - (left[k] + p->ref[i]) / 2; break; + case 4: out[i] = in[i] - paeth(left[k], p->ref[i], upleft[k]); break; + } + left[k] = in[i]; + upleft[k] = p->ref[i]; + } + } + + else + { + for (k = 0, i = 0; i < p->stride; k = (k + 1) % p->bpp, i ++) + { + switch (predictor) + { + case 0: out[i] = in[i]; break; + case 1: out[i] = in[i] + left[k]; break; + case 2: out[i] = in[i] + p->ref[i]; break; + case 3: out[i] = in[i] + (left[k] + p->ref[i]) / 2; break; + case 4: out[i] = in[i] + paeth(left[k], p->ref[i], upleft[k]); break; + } + left[k] = out[i]; + upleft[k] = p->ref[i]; + } + } +} + +fz_error * +fz_processpredict(fz_filter *filter, fz_buffer *in, fz_buffer *out) +{ + fz_predict *dec = (fz_predict*)filter; + int ispng = dec->predictor >= 10; + int predictor; + + while (1) + { + if (in->rp + dec->stride + (!dec->encode && ispng) > in->wp) + { + if (in->eof) + return fz_iodone; + return fz_ioneedin; + } + + if (out->wp + dec->stride + (dec->encode && ispng) > out->ep) + return fz_ioneedout; + + if (dec->predictor == 1) + { + none(dec, in->rp, out->wp); + } + else if (dec->predictor == 2) + { + if (dec->bpc != 8) + memset(out->wp, 0, dec->stride); + tiff(dec, in->rp, out->wp); + } + else + { + if (dec->encode) + { + predictor = dec->predictor - 10; + if (predictor < 0 || predictor > 4) + predictor = 1; + *out->wp ++ = predictor; + } + else + { + predictor = *in->rp++; + } + png(dec, in->rp, out->wp, predictor); + } + + if (dec->ref) + memcpy(dec->ref, out->wp, dec->stride); + + in->rp += dec->stride; + out->wp += dec->stride; + } +} + +fz_error * +fz_newpredictd(fz_filter **fp, fz_obj *params) +{ + return fz_newpredict(fp, params, 0); +} + +fz_error * +fz_newpredicte(fz_filter **fp, fz_obj *params) +{ + return fz_newpredict(fp, params, 1); +} + diff --git a/fitz/filt_rld.c b/fitz/filt_rld.c new file mode 100644 index 00000000..9b0ed75f --- /dev/null +++ b/fitz/filt_rld.c @@ -0,0 +1,73 @@ +#include "fitz-base.h" +#include "fitz-stream.h" + +fz_error * +fz_newrld(fz_filter **fp, fz_obj *params) +{ + FZ_NEWFILTER(fz_filter, f, rld); + return fz_okay; +} + +void +fz_droprld(fz_filter *rld) +{ +} + +fz_error * +fz_processrld(fz_filter *filter, fz_buffer *in, fz_buffer *out) +{ + int run, i; + unsigned char c; + + while (1) + { + if (in->rp == in->wp) + { + if (in->eof) + { + return fz_iodone; + } + return fz_ioneedin; + } + + if (out->wp == out->ep) + return fz_ioneedout; + + run = *in->rp++; + + if (run == 128) + { + return fz_iodone; + } + + else if (run < 128) { + run = run + 1; + if (in->rp + run > in->wp) { + in->rp --; + return fz_ioneedin; + } + if (out->wp + run > out->ep) { + in->rp --; + return fz_ioneedout; + } + for (i = 0; i < run; i++) + *out->wp++ = *in->rp++; + } + + else if (run > 128) { + run = 257 - run; + if (in->rp + 1 > in->wp) { + in->rp --; + return fz_ioneedin; + } + if (out->wp + run > out->ep) { + in->rp --; + return fz_ioneedout; + } + c = *in->rp++; + for (i = 0; i < run; i++) + *out->wp++ = c; + } + } +} + diff --git a/fitz/filt_rle.c b/fitz/filt_rle.c new file mode 100644 index 00000000..65c2a7a4 --- /dev/null +++ b/fitz/filt_rle.c @@ -0,0 +1,238 @@ +#include "fitz-base.h" +#include "fitz-stream.h" + +/* TODO: rewrite! + * make it non-optimal or something, + * just not this horrid mess... + */ + +#define noDEBUG + +typedef struct fz_rle_s fz_rle; + +struct fz_rle_s +{ + fz_filter super; + int reclen; + int curlen; + int state; + int run; + unsigned char buf[128]; +}; + +enum { + ZERO, + ONE, + DIFF, + SAME, + END +}; + +fz_error * +fz_newrle(fz_filter **fp, fz_obj *params) +{ + FZ_NEWFILTER(fz_rle, enc, rle); + + if (params) + enc->reclen = fz_toint(params); + else + enc->reclen = 0; + + enc->curlen = 0; + enc->state = ZERO; + enc->run = 0; + + return fz_okay; +} + +void +fz_droprle(fz_filter *enc) +{ +} + +static fz_error * +putone(fz_rle *enc, fz_buffer *in, fz_buffer *out) +{ + if (out->wp + 2 >= out->ep) + return fz_ioneedout; + +#ifdef DEBUG +fprintf(stderr, "one '%c'\n", enc->buf[0]); +#endif + + *out->wp++ = 0; + *out->wp++ = enc->buf[0]; + + return fz_okay; +} + +static fz_error * +putsame(fz_rle *enc, fz_buffer *in, fz_buffer *out) +{ + if (out->wp + enc->run >= out->ep) + return fz_ioneedout; + +#ifdef DEBUG +fprintf(stderr, "same %d x '%c'\n", enc->run, enc->buf[0]); +#endif + + *out->wp++ = 257 - enc->run; + *out->wp++ = enc->buf[0]; + return fz_okay; +} + +static fz_error * +putdiff(fz_rle *enc, fz_buffer *in, fz_buffer *out) +{ + int i; + if (out->wp + enc->run >= out->ep) + return fz_ioneedout; + +#ifdef DEBUG +fprintf(stderr, "diff %d\n", enc->run); +#endif + + *out->wp++ = enc->run - 1; + for (i = 0; i < enc->run; i++) + *out->wp++ = enc->buf[i]; + return fz_okay; +} + +static fz_error * +puteod(fz_rle *enc, fz_buffer *in, fz_buffer *out) +{ + if (out->wp + 1 >= out->ep) + return fz_ioneedout; + +#ifdef DEBUG +fprintf(stderr, "eod\n"); +#endif + + *out->wp++ = 128; + return fz_okay; +} + +static fz_error * +savebuf(fz_rle *enc, fz_buffer *in, fz_buffer *out) +{ + switch (enc->state) + { + case ZERO: return fz_okay; + case ONE: return putone(enc, in, out); + case SAME: return putsame(enc, in, out); + case DIFF: return putdiff(enc, in, out); + case END: return puteod(enc, in, out); + default: assert(!"invalid state in rle"); return fz_okay; + } +} + +fz_error * +fz_processrle(fz_filter *filter, fz_buffer *in, fz_buffer *out) +{ + fz_rle *enc = (fz_rle*)filter; + fz_error *error; + unsigned char c; + + while (1) + { + + if (enc->reclen && enc->curlen == enc->reclen) { + error = savebuf(enc, in, out); + if (error) return error; +#ifdef DEBUG +fprintf(stderr, "--record--\n"); +#endif + enc->state = ZERO; + enc->curlen = 0; + } + + if (in->rp == in->wp) { + if (in->eof) { + if (enc->state != END) { + error = savebuf(enc, in, out); + if (error) return error; + } + enc->state = END; + } + else + return fz_ioneedin; + } + + c = *in->rp; + + switch (enc->state) + { + case ZERO: + enc->state = ONE; + enc->run = 1; + enc->buf[0] = c; + break; + + case ONE: + enc->state = DIFF; + enc->run = 2; + enc->buf[1] = c; + break; + + case DIFF: + /* out of space */ + if (enc->run == 128) { + error = putdiff(enc, in, out); + if (error) return error; + + enc->state = ONE; + enc->run = 1; + enc->buf[0] = c; + } + + /* run of three that are the same */ + else if ((enc->run > 1) && + (c == enc->buf[enc->run - 1]) && + (c == enc->buf[enc->run - 2])) + { + if (enc->run >= 3) { + enc->run -= 2; /* skip prev two for diff run */ + error = putdiff(enc, in, out); + if (error) return error; + } + + enc->state = SAME; + enc->run = 3; + enc->buf[0] = c; + } + + /* keep on collecting */ + else { + enc->buf[enc->run++] = c; + } + break; + + case SAME: + if (enc->run == 128 || c != enc->buf[0]) { + error = putsame(enc, in, out); + if (error) return error; + + enc->state = ONE; + enc->run = 1; + enc->buf[0] = c; + } + else { + enc->run ++; + } + break; + + case END: + error = puteod(enc, in, out); + if (error) + return error; + + return fz_iodone; + } + + in->rp ++; + + enc->curlen ++; + + } +} + diff --git a/fitz/node_misc1.c b/fitz/node_misc1.c new file mode 100644 index 00000000..fc8407d5 --- /dev/null +++ b/fitz/node_misc1.c @@ -0,0 +1,155 @@ +#include "fitz-base.h" +#include "fitz-world.h" + +void fz_droplinknode(fz_linknode* node); +void fz_droppathnode(fz_pathnode* node); +void fz_droptextnode(fz_textnode* node); +void fz_dropimagenode(fz_imagenode* node); +void fz_dropshadenode(fz_shadenode* node); + +fz_rect fz_boundtransformnode(fz_transformnode* node, fz_matrix ctm); +fz_rect fz_boundovernode(fz_overnode* node, fz_matrix ctm); +fz_rect fz_boundmasknode(fz_masknode* node, fz_matrix ctm); +fz_rect fz_boundblendnode(fz_blendnode* node, fz_matrix ctm); +fz_rect fz_boundsolidnode(fz_solidnode* node, fz_matrix ctm); +fz_rect fz_boundpathnode(fz_pathnode* node, fz_matrix ctm); +fz_rect fz_boundtextnode(fz_textnode* node, fz_matrix ctm); +fz_rect fz_boundimagenode(fz_imagenode* node, fz_matrix ctm); +fz_rect fz_boundshadenode(fz_shadenode* node, fz_matrix ctm); +fz_rect fz_boundlinknode(fz_linknode* node, fz_matrix ctm); + +void +fz_initnode(fz_node *node, fz_nodekind kind) +{ + node->kind = kind; + node->parent = nil; + node->first = nil; + node->last = nil; + node->next = nil; +} + +void +fz_dropnode(fz_node *node) +{ + if (node->first) + fz_dropnode(node->first); + if (node->next) + fz_dropnode(node->next); + + switch (node->kind) + { + case FZ_NTRANSFORM: + case FZ_NOVER: + case FZ_NMASK: + case FZ_NBLEND: + case FZ_NCOLOR: + break; + case FZ_NPATH: + fz_droppathnode((fz_pathnode *) node); + break; + case FZ_NTEXT: + fz_droptextnode((fz_textnode *) node); + break; + case FZ_NIMAGE: + fz_dropimagenode((fz_imagenode *) node); + break; + case FZ_NSHADE: + fz_dropshadenode((fz_shadenode *) node); + break; + case FZ_NLINK: + fz_droplinknode((fz_linknode *) node); + break; + } + + fz_free(node); +} + +fz_rect +fz_boundnode(fz_node *node, fz_matrix ctm) +{ + switch (node->kind) + { + case FZ_NTRANSFORM: + return fz_boundtransformnode((fz_transformnode *) node, ctm); + case FZ_NOVER: + return fz_boundovernode((fz_overnode *) node, ctm); + case FZ_NMASK: + return fz_boundmasknode((fz_masknode *) node, ctm); + case FZ_NBLEND: + return fz_boundblendnode((fz_blendnode *) node, ctm); + case FZ_NCOLOR: + return fz_boundsolidnode((fz_solidnode *) node, ctm); + case FZ_NPATH: + return fz_boundpathnode((fz_pathnode *) node, ctm); + case FZ_NTEXT: + return fz_boundtextnode((fz_textnode *) node, ctm); + case FZ_NIMAGE: + return fz_boundimagenode((fz_imagenode *) node, ctm); + case FZ_NSHADE: + return fz_boundshadenode((fz_shadenode *) node, ctm); + case FZ_NLINK: + return fz_boundlinknode((fz_linknode *) node, ctm); + } + return fz_emptyrect; +} + +int +fz_istransformnode(fz_node *node) +{ + return node ? node->kind == FZ_NTRANSFORM : 0; +} + +int +fz_isovernode(fz_node *node) +{ + return node ? node->kind == FZ_NOVER : 0; +} + +int +fz_ismasknode(fz_node *node) +{ + return node ? node->kind == FZ_NMASK : 0; +} + +int +fz_isblendnode(fz_node *node) +{ + return node ? node->kind == FZ_NBLEND : 0; +} + +int +fz_issolidnode(fz_node *node) +{ + return node ? node->kind == FZ_NCOLOR : 0; +} + +int +fz_ispathnode(fz_node *node) +{ + return node ? node->kind == FZ_NPATH : 0; +} + +int +fz_istextnode(fz_node *node) +{ + return node ? node->kind == FZ_NTEXT : 0; +} + +int +fz_isimagenode(fz_node *node) +{ + return node ? node->kind == FZ_NIMAGE : 0; +} + +int +fz_isshadenode(fz_node *node) +{ + return node ? node->kind == FZ_NSHADE : 0; +} + +int +fz_islinknode(fz_node *node) +{ + return node ? node->kind == FZ_NLINK : 0; +} + diff --git a/fitz/node_misc2.c b/fitz/node_misc2.c new file mode 100644 index 00000000..b83678d1 --- /dev/null +++ b/fitz/node_misc2.c @@ -0,0 +1,296 @@ +#include "fitz-base.h" +#include "fitz-world.h" + +/* + * Over + */ + +fz_error * +fz_newovernode(fz_node **nodep) +{ + fz_node *node; + + node = *nodep = fz_malloc(sizeof (fz_overnode)); + if (!node) + return fz_outofmem; + + fz_initnode(node, FZ_NOVER); + + return fz_okay; +} + +fz_rect +fz_boundovernode(fz_overnode *node, fz_matrix ctm) +{ + fz_node *child; + fz_rect bbox; + fz_rect temp; + + child = node->super.first; + if (!child) + return fz_emptyrect; + + bbox = fz_boundnode(child, ctm); + + child = child->next; + while (child) + { + temp = fz_boundnode(child, ctm); + bbox = fz_mergerects(temp, bbox); + child = child->next; + } + + return bbox; +} + +/* + * Mask + */ + +fz_error * +fz_newmasknode(fz_node **nodep) +{ + fz_node *node; + + node = *nodep = fz_malloc(sizeof (fz_masknode)); + if (!node) + return fz_outofmem; + + fz_initnode(node, FZ_NMASK); + + return fz_okay; +} + +fz_rect +fz_boundmasknode(fz_masknode *node, fz_matrix ctm) +{ + fz_node *shape; + fz_node *color; + fz_rect one, two; + + shape = node->super.first; + color = shape->next; + + one = fz_boundnode(shape, ctm); + two = fz_boundnode(color, ctm); + return fz_intersectrects(one, two); +} + +/* + * Blend + */ + +fz_error * +fz_newblendnode(fz_node **nodep, fz_blendkind b, int k, int i) +{ + fz_blendnode *node; + + node = fz_malloc(sizeof (fz_blendnode)); + if (!node) + return fz_outofmem; + *nodep = (fz_node*)node; + + fz_initnode((fz_node*)node, FZ_NBLEND); + node->mode = b; + node->knockout = k; + node->isolated = i; + + return fz_okay; +} + +fz_rect +fz_boundblendnode(fz_blendnode *node, fz_matrix ctm) +{ + fz_node *child; + fz_rect bbox; + fz_rect temp; + + child = node->super.first; + if (!child) + return fz_emptyrect; + + bbox = fz_boundnode(child, ctm); + + child = child->next; + while (child) + { + temp = fz_boundnode(child, ctm); + bbox = fz_mergerects(temp, bbox); + child = child->next; + } + + return bbox; +} + +void +fz_dropblendnode(fz_blendnode *node) +{ + fz_dropcolorspace(node->cs); +} + +/* + * Transform + */ + +fz_error * +fz_newtransformnode(fz_node **nodep, fz_matrix m) +{ + fz_transformnode *node; + + node = fz_malloc(sizeof (fz_transformnode)); + if (!node) + return fz_outofmem; + *nodep = (fz_node*)node; + + fz_initnode((fz_node*)node, FZ_NTRANSFORM); + node->m = m; + + return fz_okay; +} + +fz_rect +fz_boundtransformnode(fz_transformnode *node, fz_matrix ctm) +{ + if (!node->super.first) + return fz_emptyrect; + return fz_boundnode(node->super.first, fz_concat(node->m, ctm)); +} + +/* + * Link to tree + */ + +fz_error * +fz_newlinknode(fz_node **nodep, fz_tree *subtree) +{ + fz_linknode *node; + + node = fz_malloc(sizeof (fz_linknode)); + if (!node) + return fz_outofmem; + *nodep = (fz_node*)node; + + fz_initnode((fz_node*)node, FZ_NLINK); + node->tree = fz_keeptree(subtree); + + return fz_okay; +} + +void +fz_droplinknode(fz_linknode *node) +{ + fz_droptree(node->tree); +} + +fz_rect +fz_boundlinknode(fz_linknode *node, fz_matrix ctm) +{ + return fz_boundtree(node->tree, ctm); +} + +/* + * Solid color + */ + +fz_error * +fz_newsolidnode(fz_node **nodep, float a, fz_colorspace *cs, int n, float *v) +{ + fz_solidnode *node; + int i; + + node = fz_malloc(sizeof(fz_solidnode) + sizeof(float) * n); + if (!node) + return fz_outofmem; + *nodep = (fz_node*)node; + + fz_initnode((fz_node*)node, FZ_NCOLOR); + node->a = a; + node->cs = fz_keepcolorspace(cs); + node->n = n; + for (i = 0; i < n; i++) + node->samples[i] = v[i]; + + return fz_okay; +} + +fz_rect +fz_boundsolidnode(fz_solidnode *node, fz_matrix ctm) +{ + return fz_infiniterect; +} + +void +fz_dropsolidnode(fz_solidnode *node) +{ + fz_dropcolorspace(node->cs); +} + +/* + * Image node + */ + +fz_error * +fz_newimagenode(fz_node **nodep, fz_image *image) +{ + fz_imagenode *node; + + node = fz_malloc(sizeof (fz_imagenode)); + if (!node) + return fz_outofmem; + *nodep = (fz_node*)node; + + fz_initnode((fz_node*)node, FZ_NIMAGE); + node->image = fz_keepimage(image); + + return fz_okay; +} + +void +fz_dropimagenode(fz_imagenode *node) +{ + fz_dropimage(node->image); +} + +fz_rect +fz_boundimagenode(fz_imagenode *node, fz_matrix ctm) +{ + fz_rect bbox; + bbox.x0 = 0; + bbox.y0 = 0; + bbox.x1 = 1; + bbox.y1 = 1; + return fz_transformaabb(ctm, bbox); +} + +/* + * Shade node + */ + +fz_error * +fz_newshadenode(fz_node **nodep, fz_shade *shade) +{ + fz_shadenode *node; + + node = fz_malloc(sizeof (fz_shadenode)); + if (!node) + return fz_outofmem; + *nodep = (fz_node*)node; + + fz_initnode((fz_node*)node, FZ_NSHADE); + node->shade = fz_keepshade(shade); + + return fz_okay; +} + +void +fz_dropshadenode(fz_shadenode *node) +{ + fz_dropshade(node->shade); +} + +fz_rect +fz_boundshadenode(fz_shadenode *node, fz_matrix ctm) +{ + return fz_boundshade(node->shade, ctm); +} + diff --git a/fitz/node_optimize.c b/fitz/node_optimize.c new file mode 100644 index 00000000..cb3918e1 --- /dev/null +++ b/fitz/node_optimize.c @@ -0,0 +1,235 @@ +#include "fitz-base.h" +#include "fitz-world.h" + +/* + * Remove (mask ... white) until we get something not white + */ + +static int iswhitenode(fz_solidnode *node) +{ + if (!strcmp(node->cs->name, "DeviceGray")) + return fabs(node->samples[0] - 1.0) < FLT_EPSILON; + if (!strcmp(node->cs->name, "DeviceRGB")) + return fabs(node->samples[0] - 1.0) < FLT_EPSILON && + fabs(node->samples[1] - 1.0) < FLT_EPSILON && + fabs(node->samples[2] - 1.0) < FLT_EPSILON; + if (!strcmp(node->cs->name, "DeviceCMYK")) + return fabs(node->samples[0]) < FLT_EPSILON && + fabs(node->samples[1]) < FLT_EPSILON && + fabs(node->samples[2]) < FLT_EPSILON && + fabs(node->samples[3]) < FLT_EPSILON; + return 0; +} + +static int cleanwhite(fz_node *node) +{ + fz_node *current; + fz_node *next; + fz_node *shape; + fz_node *color; + + for (current = node->first; current; current = next) + { + next = current->next; + + if (fz_islinknode(current)) + return 1; + else if (fz_isimagenode(current)) + return 1; + else if (fz_isshadenode(current)) + return 1; + else if (fz_issolidnode(current)) + { + if (!iswhitenode((fz_solidnode*)current)) + return 1; + } + + else if (fz_ismasknode(current)) + { + shape = current->first; + color = shape->next; + if (fz_issolidnode(color)) + { + if (iswhitenode((fz_solidnode*)color)) + fz_removenode(current); + else + return 1; + } + else + { + if (cleanwhite(current)) + return 1; + } + } + + else + { + if (cleanwhite(current)) + return 1; + } + } + + return 0; +} + +/* + * Remove useless overs that only have one child. + */ + +static void cleanovers(fz_node *node) +{ + fz_node *prev; + fz_node *next; + fz_node *current; + fz_node *child; + + prev = nil; + for (current = node->first; current; current = next) + { + next = current->next; + + if (fz_isovernode(current)) + { + if (current->first == current->last) + { + child = current->first; + fz_removenode(current); + if (child) + { + if (prev) + fz_insertnodeafter(prev, child); + else + fz_insertnodefirst(node, child); + } + current = child; + } + } + + if (current) + prev = current; + } + + for (current = node->first; current; current = current->next) + cleanovers(current); +} + +/* + * Remove rectangular clip-masks whose contents fit... + */ + +static int getrect(fz_pathnode *path, fz_rect *bboxp) +{ + float x, y, w, h; + + /* move x y, line x+w y, line x+w y+h, line x y+h, close */ + + if (path->len != 13) + return 0; + + if (path->els[0].k != FZ_MOVETO) return 0; + x = path->els[1].v; + y = path->els[2].v; + + if (path->els[3].k != FZ_LINETO) return 0; + w = path->els[4].v - x; + if (path->els[5].v != y) return 0; + + if (path->els[6].k != FZ_LINETO) return 0; + if (path->els[7].v != x + w) return 0; + h = path->els[8].v - y; + + if (path->els[9].k != FZ_LINETO) return 0; + if (path->els[10].v != x) return 0; + if (path->els[11].v != y + h) return 0; + + if (path->els[12].k != FZ_CLOSEPATH) return 0; + + bboxp->x0 = MIN(x, x + w); + bboxp->y0 = MIN(y, y + h); + bboxp->x1 = MAX(x, x + w); + bboxp->y1 = MAX(y, y + h); + + return 1; +} + +static int fitsinside(fz_node *node, fz_rect clip) +{ + fz_rect bbox; + bbox = fz_boundnode(node, fz_identity()); + if (fz_isinfiniterect(bbox)) return 0; + if (fz_isemptyrect(bbox)) return 1; + if (bbox.x0 < clip.x0) return 0; + if (bbox.x1 > clip.x1) return 0; + if (bbox.y0 < clip.y0) return 0; + if (bbox.y1 > clip.y1) return 0; + return 1; +} + +static void cleanmasks(fz_node *node) +{ + fz_node *prev; + fz_node *current; + fz_node *shape; + fz_node *color; + fz_rect bbox; + + for (current = node->first; current; current = current->next) + cleanmasks(current); + + prev = nil; + for (current = node->first; current; current = current->next) + { +retry: + if (!current) + break; + + if (fz_ismasknode(current)) + { + shape = current->first; + color = shape->next; + + if (color == nil) + { + fz_removenode(current); + prev = nil; + current = node->first; + goto retry; + } + + if (fz_ispathnode(shape)) + { + if (getrect((fz_pathnode*)shape, &bbox)) + { + if (fitsinside(color, bbox)) + { + fz_removenode(current); + if (prev) + fz_insertnodeafter(prev, color); + else + fz_insertnodefirst(node, color); + current = color; + goto retry; + } + } + } + } + + prev = current; + } +} + +/* + * + */ + +fz_error * +fz_optimizetree(fz_tree *tree) +{ + if (getenv("DONTOPT")) + return fz_okay; + cleanwhite(tree->root); + cleanovers(tree->root); + cleanmasks(tree->root); + return fz_okay; +} + diff --git a/fitz/node_path.c b/fitz/node_path.c new file mode 100644 index 00000000..b5aea542 --- /dev/null +++ b/fitz/node_path.c @@ -0,0 +1,347 @@ +#include "fitz-base.h" +#include "fitz-world.h" + +fz_error * +fz_newpathnode(fz_pathnode **pathp) +{ + fz_pathnode *path; + + path = *pathp = fz_malloc(sizeof(fz_pathnode)); + if (!path) + return fz_outofmem; + + fz_initnode((fz_node*)path, FZ_NPATH); + + path->paint = FZ_FILL; + path->linecap = 0; + path->linejoin = 0; + path->linewidth = 1.0; + path->miterlimit = 10.0; + path->dash = nil; + path->len = 0; + path->cap = 0; + path->els = nil; + + return fz_okay; +} + +fz_error * +fz_clonepathnode(fz_pathnode **pathp, fz_pathnode *oldpath) +{ + fz_pathnode *path; + + path = *pathp = fz_malloc(sizeof(fz_pathnode)); + if (!path) + return fz_outofmem; + + fz_initnode((fz_node*)path, FZ_NPATH); + + path->paint = FZ_FILL; + path->linecap = 0; + path->linejoin = 0; + path->linewidth = 1.0; + path->miterlimit = 10.0; + path->dash = nil; + path->len = oldpath->len; + path->cap = oldpath->len; + + path->els = fz_malloc(sizeof (fz_pathel) * path->len); + if (!path->els) { + fz_free(path); + return fz_outofmem; + } + memcpy(path->els, oldpath->els, sizeof(fz_pathel) * path->len); + + return fz_okay; +} + +void +fz_droppathnode(fz_pathnode *node) +{ + fz_free(node->dash); + fz_free(node->els); +} + +static fz_error * +growpath(fz_pathnode *path, int n) +{ + int newcap; + fz_pathel *newels; + + while (path->len + n > path->cap) + { + newcap = path->cap + 36; + newels = fz_realloc(path->els, sizeof (fz_pathel) * newcap); + if (!newels) + return fz_outofmem; + path->cap = newcap; + path->els = newels; + } + + return fz_okay; +} + +fz_error * +fz_moveto(fz_pathnode *path, float x, float y) +{ + if (growpath(path, 3) != nil) + return fz_outofmem; + path->els[path->len++].k = FZ_MOVETO; + path->els[path->len++].v = x; + path->els[path->len++].v = y; + return fz_okay; +} + +fz_error * +fz_lineto(fz_pathnode *path, float x, float y) +{ + if (growpath(path, 3) != nil) + return fz_outofmem; + path->els[path->len++].k = FZ_LINETO; + path->els[path->len++].v = x; + path->els[path->len++].v = y; + return fz_okay; +} + +fz_error * +fz_curveto(fz_pathnode *path, + float x1, float y1, + float x2, float y2, + float x3, float y3) +{ + if (growpath(path, 7) != nil) + return fz_outofmem; + path->els[path->len++].k = FZ_CURVETO; + path->els[path->len++].v = x1; + path->els[path->len++].v = y1; + path->els[path->len++].v = x2; + path->els[path->len++].v = y2; + path->els[path->len++].v = x3; + path->els[path->len++].v = y3; + return fz_okay; +} + +fz_error * +fz_curvetov(fz_pathnode *path, float x2, float y2, float x3, float y3) +{ + float x1 = path->els[path->len-2].v; + float y1 = path->els[path->len-1].v; + return fz_curveto(path, x1, y1, x2, y2, x3, y3); +} + +fz_error * +fz_curvetoy(fz_pathnode *path, float x1, float y1, float x3, float y3) +{ + return fz_curveto(path, x1, y1, x3, y3, x3, y3); +} + +fz_error * +fz_closepath(fz_pathnode *path) +{ + if (growpath(path, 1) != nil) + return fz_outofmem; + path->els[path->len++].k = FZ_CLOSEPATH; + return fz_okay; +} + +fz_error * +fz_endpath(fz_pathnode *path, fz_pathkind paint, fz_stroke *stroke, fz_dash *dash) +{ + if (path->len == 0) + fz_warn("creating an empty path"); + + path->paint = paint; + path->dash = dash; + if (stroke) + { + path->linecap = stroke->linecap; + path->linejoin = stroke->linejoin; + path->linewidth = stroke->linewidth; + path->miterlimit = stroke->miterlimit; + } + + if (path->linewidth < 0.01) + path->linewidth = 0.01; + + return fz_okay; +} + +static inline fz_rect boundexpand(fz_rect r, 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_boundpathnode(fz_pathnode *path, fz_matrix ctm) +{ + fz_point p; + fz_rect r = fz_emptyrect; + int i = 0; + + if (path->len) + { + p.x = path->els[1].v; + p.y = path->els[2].v; + p = fz_transformpoint(ctm, p); + r.x0 = r.x1 = p.x; + r.y0 = r.y1 = p.y; + } + + while (i < path->len) + { + switch (path->els[i++].k) + { + case FZ_CURVETO: + p.x = path->els[i++].v; + p.y = path->els[i++].v; + r = boundexpand(r, fz_transformpoint(ctm, p)); + p.x = path->els[i++].v; + p.y = path->els[i++].v; + r = boundexpand(r, fz_transformpoint(ctm, p)); + case FZ_MOVETO: + case FZ_LINETO: + p.x = path->els[i++].v; + p.y = path->els[i++].v; + r = boundexpand(r, fz_transformpoint(ctm, p)); + break; + case FZ_CLOSEPATH: + break; + } + } + + if (path->paint == FZ_STROKE) + { + float miterlength = sin(path->miterlimit / 2.0); + float linewidth = path->linewidth; + float expand = MAX(miterlength, linewidth) / 2.0; + r.x0 -= expand; + r.y0 -= expand; + r.x1 += expand; + r.y1 += expand; + } + + return r; +} + +void +fz_printpathnode(fz_pathnode *path, int indent) +{ + float x, y; + int i = 0; + int n; + while (i < path->len) + { + for (n = 0; n < indent; n++) + putchar(' '); + switch (path->els[i++].k) + { + case FZ_MOVETO: + x = path->els[i++].v; + y = path->els[i++].v; + printf("%g %g m\n", x, y); + break; + case FZ_LINETO: + x = path->els[i++].v; + y = path->els[i++].v; + printf("%g %g l\n", x, y); + break; + case FZ_CURVETO: + x = path->els[i++].v; + y = path->els[i++].v; + printf("%g %g ", x, y); + x = path->els[i++].v; + y = path->els[i++].v; + printf("%g %g ", x, y); + x = path->els[i++].v; + y = path->els[i++].v; + printf("%g %g c\n", x, y); + break; + case FZ_CLOSEPATH: + printf("h\n"); + } + } + + for (n = 0; n < indent; n++) + putchar(' '); + + switch (path->paint) + { + case FZ_STROKE: + printf("S\n"); + break; + case FZ_FILL: + printf("f\n"); + break; + case FZ_EOFILL: + printf("f*\n"); + break; + } +} + +void +fz_debugpathnode(fz_pathnode *path, int indent) +{ + float x, y; + int i = 0; + int n; + while (i < path->len) + { + for (n = 0; n < indent; n++) + putchar(' '); + switch (path->els[i++].k) + { + case FZ_MOVETO: + x = path->els[i++].v; + y = path->els[i++].v; + printf("\n", x, y); + break; + case FZ_LINETO: + x = path->els[i++].v; + y = path->els[i++].v; + printf("\n", x, y); + break; + case FZ_CURVETO: + x = path->els[i++].v; + y = path->els[i++].v; + printf("els[i++].v; + y = path->els[i++].v; + printf("x2=\"%g\" y2=\"%g\" ", x, y); + x = path->els[i++].v; + y = path->els[i++].v; + printf("x3=\"%g\" y3=\"%g\" />\n", x, y); + break; + case FZ_CLOSEPATH: + printf("\n"); + } + } +} + +fz_error * +fz_newdash(fz_dash **dashp, float phase, int len, float *array) +{ + fz_dash *dash; + int i; + + dash = *dashp = fz_malloc(sizeof(fz_dash) + sizeof(float) * len); + if (!dash) + return fz_outofmem; + + dash->len = len; + dash->phase = phase; + for (i = 0; i < len; i++) + dash->array[i] = array[i]; + + return fz_okay; +} + +void +fz_dropdash(fz_dash *dash) +{ + fz_free(dash); +} + diff --git a/fitz/node_text.c b/fitz/node_text.c new file mode 100644 index 00000000..86a523df --- /dev/null +++ b/fitz/node_text.c @@ -0,0 +1,143 @@ +#include "fitz-base.h" +#include "fitz-world.h" + +fz_error * +fz_newtextnode(fz_textnode **textp, fz_font *font) +{ + fz_textnode *text; + + text = fz_malloc(sizeof(fz_textnode)); + if (!text) + return fz_outofmem; + + fz_initnode((fz_node*)text, FZ_NTEXT); + + text->font = fz_keepfont(font); + text->trm = fz_identity(); + text->len = 0; + text->cap = 0; + text->els = nil; + + *textp = text; + return fz_okay; +} + +fz_error * +fz_clonetextnode(fz_textnode **textp, fz_textnode *oldtext) +{ + fz_textnode *text; + + text = *textp = fz_malloc(sizeof(fz_textnode)); + if (!text) + return fz_outofmem; + + fz_initnode((fz_node*)text, FZ_NTEXT); + + text->font = fz_keepfont(oldtext->font); + text->trm = oldtext->trm; + text->len = oldtext->len; + text->cap = oldtext->len; + text->els = nil; + + text->els = fz_malloc(sizeof(fz_textel) * text->len); + if (!text->els) + { + fz_dropfont(text->font); + fz_free(text); + return fz_outofmem; + } + + memcpy(text->els, oldtext->els, sizeof(fz_textel) * text->len); + + *textp = text; + return fz_okay; +} + +void +fz_droptextnode(fz_textnode *text) +{ + fz_dropfont(text->font); + fz_free(text->els); +} + +fz_rect +fz_boundtextnode(fz_textnode *text, fz_matrix ctm) +{ + fz_matrix trm; + fz_rect bbox; + fz_rect fbox; + int i; + + if (text->len == 0) + return fz_emptyrect; + + /* find bbox of glyph origins in ctm space */ + + bbox.x0 = bbox.x1 = text->els[0].x; + bbox.y0 = bbox.y1 = text->els[0].y; + + for (i = 1; i < text->len; i++) + { + bbox.x0 = MIN(bbox.x0, text->els[i].x); + bbox.y0 = MIN(bbox.y0, text->els[i].y); + bbox.x1 = MAX(bbox.x1, text->els[i].x); + bbox.y1 = MAX(bbox.y1, text->els[i].y); + } + + bbox = fz_transformaabb(ctm, bbox); + + /* find bbox of font in trm * ctm space */ + + trm = fz_concat(text->trm, ctm); + trm.e = 0; + trm.f = 0; + + fbox.x0 = text->font->bbox.x0 * 0.001; + fbox.y0 = text->font->bbox.y0 * 0.001; + fbox.x1 = text->font->bbox.x1 * 0.001; + fbox.y1 = text->font->bbox.y1 * 0.001; + + fbox = fz_transformaabb(trm, fbox); + + /* expand glyph origin bbox by font bbox */ + + bbox.x0 += fbox.x0; + bbox.y0 += fbox.y0; + bbox.x1 += fbox.x1; + bbox.y1 += fbox.y1; + + return bbox; +} + +static fz_error * +growtext(fz_textnode *text, int n) +{ + int newcap; + fz_textel *newels; + + while (text->len + n > text->cap) + { + newcap = text->cap + 36; + newels = fz_realloc(text->els, sizeof (fz_textel) * newcap); + if (!newels) + return fz_outofmem; + text->cap = newcap; + text->els = newels; + } + + return fz_okay; +} + +fz_error * +fz_addtext(fz_textnode *text, int gid, int ucs, float x, float y) +{ + if (growtext(text, 1) != nil) + return fz_outofmem; + text->els[text->len].ucs = ucs; + text->els[text->len].gid = gid; + text->els[text->len].x = x; + text->els[text->len].y = y; + text->len++; + return fz_okay; +} + diff --git a/fitz/node_toxml.c b/fitz/node_toxml.c new file mode 100644 index 00000000..cc87c997 --- /dev/null +++ b/fitz/node_toxml.c @@ -0,0 +1,185 @@ +#include "fitz-base.h" +#include "fitz-world.h" + +static void indent(int level) +{ + while (level--) + putchar(' '); +} + +static void xmlnode(fz_node *node, int level); + +static void xmlover(fz_overnode *node, int level) +{ + fz_node *child; + indent(level); + printf("\n"); + for (child = node->super.first; child; child = child->next) + xmlnode(child, level + 1); + indent(level); + printf("\n"); +} + +static void xmlmask(fz_masknode *node, int level) +{ + fz_node *child; + indent(level); + printf("\n"); + for (child = node->super.first; child; child = child->next) + xmlnode(child, level + 1); + indent(level); + printf("\n"); +} + +static void xmlblend(fz_blendnode *node, int level) +{ + fz_node *child; + indent(level); + printf("\n", node->mode); + for (child = node->super.first; child; child = child->next) + xmlnode(child, level + 1); + indent(level); + printf("\n"); +} + +static void xmltransform(fz_transformnode *node, int level) +{ + indent(level); + printf("\n", + node->m.a, node->m.b, + node->m.c, node->m.d, + node->m.e, node->m.f); + xmlnode(node->super.first, level + 1); + indent(level); + printf("\n"); +} + +static void xmlsolid(fz_solidnode *node, int level) +{ + int i; + indent(level); + printf("cs->name, node->a); + for (i = 0; i < node->n; i++) + { + printf("%g", node->samples[i]); + if (i < node->n - 1) + putchar(' '); + } + printf("\" />\n"); +} + +static void xmllink(fz_linknode *node, int level) +{ + indent(level); + printf("\n", node->tree); +} + +static void xmlpath(fz_pathnode *node, int level) +{ + int i; + + indent(level); + + if (node->paint == FZ_STROKE) + { + printf("linecap, + node->linejoin, + node->linewidth, + node->miterlimit); + if (node->dash) + { + printf(" phase=\"%g\" array=\"", node->dash->phase); + for (i = 0; i < node->dash->len; i++) + printf("%g ", node->dash->array[i]); + printf("\""); + } + printf(">\n"); + } + else + { + printf("\n", + node->paint == FZ_FILL ? "nonzero" : "evenodd"); + } + + fz_debugpathnode(node, level + 2); + + indent(level); + printf("\n"); +} + +static void xmltext(fz_textnode *node, int level) +{ + int i; + + indent(level); + printf("\n", node->font->name, + node->trm.a, node->trm.b, node->trm.c, node->trm.d); + + for (i = 0; i < node->len; i++) + { + indent(level + 1); + if (node->els[i].ucs >= 32 && node->els[i].ucs < 128) + printf("\n", + node->els[i].ucs, node->els[i].gid, node->els[i].x, node->els[i].y); + else + printf("\n", + node->els[i].ucs, node->els[i].gid, node->els[i].x, node->els[i].y); + } + + indent(level); + printf("\n"); +} + +static void xmlimage(fz_imagenode *node, int level) +{ + fz_image *image = node->image; + indent(level); + printf("\n", + image->w, image->h, image->n, image->a); +} + +static void xmlshade(fz_shadenode *node, int level) +{ + indent(level); + printf("\n"); +} + +static void xmlnode(fz_node *node, int level) +{ + if (!node) + { + indent(level); + printf("\n"); + return; + } + + switch (node->kind) + { + case FZ_NOVER: xmlover((fz_overnode*)node, level); break; + case FZ_NMASK: xmlmask((fz_masknode*)node, level); break; + case FZ_NBLEND: xmlblend((fz_blendnode*)node, level); break; + case FZ_NTRANSFORM: xmltransform((fz_transformnode*)node, level); break; + case FZ_NCOLOR: xmlsolid((fz_solidnode*)node, level); break; + case FZ_NPATH: xmlpath((fz_pathnode*)node, level); break; + case FZ_NTEXT: xmltext((fz_textnode*)node, level); break; + case FZ_NIMAGE: xmlimage((fz_imagenode*)node, level); break; + case FZ_NSHADE: xmlshade((fz_shadenode*)node, level); break; + case FZ_NLINK: xmllink((fz_linknode*)node, level); break; + } +} + +void +fz_debugnode(fz_node *node) +{ + xmlnode(node, 0); +} + +void +fz_debugtree(fz_tree *tree) +{ + printf("\n"); + xmlnode(tree->root, 1); + printf("\n"); +} + diff --git a/fitz/node_tree.c b/fitz/node_tree.c new file mode 100644 index 00000000..f5698bc1 --- /dev/null +++ b/fitz/node_tree.c @@ -0,0 +1,108 @@ +#include "fitz-base.h" +#include "fitz-world.h" + +fz_error * +fz_newtree(fz_tree **treep) +{ + fz_tree *tree; + + tree = *treep = fz_malloc(sizeof (fz_tree)); + if (!tree) + return fz_outofmem; + + tree->refs = 1; + tree->root = nil; + tree->head = nil; + + return fz_okay; +} + +fz_tree * +fz_keeptree(fz_tree *tree) +{ + tree->refs ++; + return tree; +} + +void +fz_droptree(fz_tree *tree) +{ + if (--tree->refs == 0) + { + if (tree->root) + fz_dropnode(tree->root); + fz_free(tree); + } +} + +fz_rect +fz_boundtree(fz_tree *tree, fz_matrix ctm) +{ + if (tree->root) + return fz_boundnode(tree->root, ctm); + return fz_emptyrect; +} + +void +fz_insertnodefirst(fz_node *parent, fz_node *child) +{ + child->parent = parent; + child->next = parent->first; + parent->first = child; + if (!parent->last) + parent->last = child; +} + +void +fz_insertnodelast(fz_node *parent, fz_node *child) +{ + child->parent = parent; + if (!parent->first) + parent->first = child; + else + parent->last->next = child; + parent->last = child; +} + +void +fz_insertnodeafter(fz_node *prev, fz_node *child) +{ + fz_node *parent = prev->parent; + child->parent = parent; + if (parent->last == prev) + parent->last = child; + child->next = prev->next; + prev->next = child; +} + +void +fz_removenode(fz_node *child) +{ + fz_node *parent = child->parent; + fz_node *prev; + fz_node *node; + + if (parent->first == child) + { + parent->first = child->next; + if (parent->last == child) + parent->last = nil; + return; + } + + prev = parent->first; + node = prev->next; + + while (node) + { + if (node == child) + { + prev->next = child->next; + } + prev = node; + node = node->next; + } + + parent->last = prev; +} + diff --git a/fitz/obj_array.c b/fitz/obj_array.c new file mode 100644 index 00000000..3953470a --- /dev/null +++ b/fitz/obj_array.c @@ -0,0 +1,230 @@ +#include "fitz-base.h" +#include "fitz-stream.h" + +void fz_droparray(fz_obj *obj); + +fz_error * +fz_newarray(fz_obj **op, int initialcap) +{ + fz_obj *obj; + int i; + + obj = *op = fz_malloc(sizeof (fz_obj)); + if (!obj) + return fz_throw("outofmem: array struct"); + + obj->refs = 1; + obj->kind = FZ_ARRAY; + + obj->u.a.len = 0; + obj->u.a.cap = initialcap > 0 ? initialcap : 6; + + obj->u.a.items = fz_malloc(sizeof (fz_obj*) * obj->u.a.cap); + if (!obj->u.a.items) + { + fz_free(obj); + return fz_throw("outofmem: array item buffer"); + } + + for (i = 0; i < obj->u.a.cap; i++) + obj->u.a.items[i] = nil; + + return fz_okay; +} + +fz_error * +fz_copyarray(fz_obj **op, fz_obj *obj) +{ + fz_error *error; + fz_obj *new; + int i; + + if (!fz_isarray(obj)) + return fz_throw("assert: not an array (%s)", fz_objkindstr(obj)); + + error = fz_newarray(&new, fz_arraylen(obj)); + if (error) + return fz_rethrow(error, "cannot create new array"); + + for (i = 0; i < fz_arraylen(obj); i++) + { + error = fz_arraypush(new, fz_arrayget(obj, i)); + if (error) + { + fz_droparray(new); + return fz_rethrow(error, "cannot add item to array"); + } + } + + *op = new; + + return fz_okay; +} + +fz_error * +fz_deepcopyarray(fz_obj **op, fz_obj *obj) +{ + fz_error *error; + fz_obj *new; + fz_obj *val; + int i; + + if (!fz_isarray(obj)) + return fz_throw("assert: not an array (%s)", fz_objkindstr(obj)); + + error = fz_newarray(&new, fz_arraylen(obj)); + if (error) + return fz_rethrow(error, "cannot create new array"); + + for (i = 0; i < fz_arraylen(obj); i++) + { + val = fz_arrayget(obj, i); + + if (fz_isarray(val)) + { + error = fz_deepcopyarray(&val, val); + if (error) + { + fz_droparray(new); + return fz_rethrow(error, "cannot deep copy item"); + } + + error = fz_arraypush(new, val); + if (error) + { + fz_dropobj(val); + fz_droparray(new); + return fz_rethrow(error, "cannot add copied item to array"); + } + + fz_dropobj(val); + } + + else if (fz_isdict(val)) + { + error = fz_deepcopydict(&val, val); + if (error) + { + fz_droparray(new); + return fz_rethrow(error, "cannot deep copy item"); + } + + error = fz_arraypush(new, val); + if (error) + { + fz_dropobj(val); + fz_droparray(new); + return fz_rethrow(error, "cannot add copied item to array"); + } + fz_dropobj(val); + } + + else + { + error = fz_arraypush(new, val); + if (error) + { + fz_droparray(new); + return fz_rethrow(error, "cannot add copied item to array"); + } + } + } + + *op = new; + + return fz_okay; +} + +int +fz_arraylen(fz_obj *obj) +{ + if (!fz_isarray(obj)) + return 0; + return obj->u.a.len; +} + +fz_obj * +fz_arrayget(fz_obj *obj, int i) +{ + if (!fz_isarray(obj)) + return nil; + + if (i < 0 || i >= obj->u.a.len) + return nil; + + return obj->u.a.items[i]; +} + +fz_error * +fz_arrayput(fz_obj *obj, int i, fz_obj *item) +{ + if (!fz_isarray(obj)) + return fz_throw("assert: not an array (%s)", fz_objkindstr(obj)); + if (i < 0) + return fz_throw("assert: index %d < 0", i); + if (i >= obj->u.a.len) + return fz_throw("assert: index %d > length %d", i, obj->u.a.len); + + if (obj->u.a.items[i]) + fz_dropobj(obj->u.a.items[i]); + obj->u.a.items[i] = fz_keepobj(item); + + return fz_okay; +} + +static fz_error * +growarray(fz_obj *obj) +{ + fz_obj **newitems; + int newcap; + int i; + + newcap = obj->u.a.cap * 2; + newitems = fz_realloc(obj->u.a.items, sizeof (fz_obj*) * newcap); + if (!newitems) + return fz_throw("outofmem: resize item buffer"); + + obj->u.a.items = newitems; + for (i = obj->u.a.cap ; i < newcap; i++) + obj->u.a.items[i] = nil; + obj->u.a.cap = newcap; + + return fz_okay; +} + +fz_error * +fz_arraypush(fz_obj *obj, fz_obj *item) +{ + fz_error *error; + + if (!fz_isarray(obj)) + return fz_throw("assert: not an array (%s)", fz_objkindstr(obj)); + + if (obj->u.a.len + 1 > obj->u.a.cap) + { + error = growarray(obj); + if (error) + return fz_rethrow(error, "cannot grow item buffer"); + } + + obj->u.a.items[obj->u.a.len] = fz_keepobj(item); + obj->u.a.len++; + + return fz_okay; +} + +void +fz_droparray(fz_obj *obj) +{ + int i; + + assert(obj->kind == FZ_ARRAY); + + for (i = 0; i < obj->u.a.len; i++) + if (obj->u.a.items[i]) + fz_dropobj(obj->u.a.items[i]); + + fz_free(obj->u.a.items); + fz_free(obj); +} + diff --git a/fitz/obj_dict.c b/fitz/obj_dict.c new file mode 100644 index 00000000..236c8a1a --- /dev/null +++ b/fitz/obj_dict.c @@ -0,0 +1,399 @@ +#include "fitz-base.h" +#include "fitz-stream.h" + +/* keep either names or strings in the dict. don't mix & match. */ + +static int keyvalcmp(const void *ap, const void *bp) +{ + const fz_keyval *a = ap; + const fz_keyval *b = bp; + if (fz_isname(a->k)) + return strcmp(fz_toname(a->k), fz_toname(b->k)); + if (fz_isstring(a->k)) + return strcmp(fz_tostrbuf(a->k), fz_tostrbuf(b->k)); + return -1; +} + +static inline int keystrcmp(fz_obj *key, char *s) +{ + if (fz_isname(key)) + return strcmp(fz_toname(key), s); + if (fz_isstring(key)) + return strcmp(fz_tostrbuf(key), s); + return -1; +} + +fz_error * +fz_newdict(fz_obj **op, int initialcap) +{ + fz_obj *obj; + int i; + + obj = *op = fz_malloc(sizeof (fz_obj)); + if (!obj) + return fz_throw("outofmem: dict struct"); + + obj->refs = 1; + obj->kind = FZ_DICT; + + obj->u.d.sorted = 1; + obj->u.d.len = 0; + obj->u.d.cap = initialcap > 0 ? initialcap : 10; + + obj->u.d.items = fz_malloc(sizeof(fz_keyval) * obj->u.d.cap); + if (!obj->u.d.items) + { + fz_free(obj); + return fz_throw("outofmem: dict item buffer"); + } + + for (i = 0; i < obj->u.d.cap; i++) + { + obj->u.d.items[i].k = nil; + obj->u.d.items[i].v = nil; + } + + return fz_okay; +} + +fz_error * +fz_copydict(fz_obj **op, fz_obj *obj) +{ + fz_error *error; + fz_obj *new; + int i; + + if (!fz_isdict(obj)) + return fz_throw("assert: not a dict (%s)", fz_objkindstr(obj)); + + error = fz_newdict(&new, obj->u.d.cap); + if (error) + return fz_rethrow(error, "cannot create new dict"); + + for (i = 0; i < fz_dictlen(obj); i++) + { + error = fz_dictput(new, fz_dictgetkey(obj, i), fz_dictgetval(obj, i)); + if (error) + { + fz_dropobj(new); + return fz_rethrow(error, "cannot copy dict entry"); + } + } + + *op = new; + return fz_okay; +} + +fz_error * +fz_deepcopydict(fz_obj **op, fz_obj *obj) +{ + fz_error *error; + fz_obj *new; + fz_obj *val; + int i; + + if (!fz_isdict(obj)) + return fz_throw("assert: not a dict (%s)", fz_objkindstr(obj)); + + error = fz_newdict(&new, obj->u.d.cap); + if (error) + return fz_rethrow(error, "cannot create new dict"); + + for (i = 0; i < fz_dictlen(obj); i++) + { + val = fz_dictgetval(obj, i); + + if (fz_isarray(val)) + { + error = fz_deepcopyarray(&val, val); + if (error) + { + fz_dropobj(new); + return fz_rethrow(error, "cannot deep copy item"); + } + error = fz_dictput(new, fz_dictgetkey(obj, i), val); + if (error) + { + fz_dropobj(val); + fz_dropobj(new); + return fz_rethrow(error, "cannot add copied dict entry"); + } + fz_dropobj(val); + } + + else if (fz_isdict(val)) + { + error = fz_deepcopydict(&val, val); + if (error) + { + fz_dropobj(new); + return fz_rethrow(error, "cannot deep copy item"); + } + error = fz_dictput(new, fz_dictgetkey(obj, i), val); + if (error) + { + fz_dropobj(val); + fz_dropobj(new); + return fz_rethrow(error, "cannot add copied dict entry"); + } + fz_dropobj(val); + } + + else + { + error = fz_dictput(new, fz_dictgetkey(obj, i), val); + if (error) + { + fz_dropobj(new); + return fz_rethrow(error, "cannot copy dict entry"); + } + } + } + + *op = new; + return fz_okay; +} + +static fz_error * +growdict(fz_obj *obj) +{ + fz_keyval *newitems; + int newcap; + int i; + + newcap = obj->u.d.cap * 2; + + newitems = fz_realloc(obj->u.d.items, sizeof(fz_keyval) * newcap); + if (!newitems) + return fz_throw("outofmem: resize item buffer"); + + obj->u.d.items = newitems; + for (i = obj->u.d.cap; i < newcap; i++) + { + obj->u.d.items[i].k = nil; + obj->u.d.items[i].v = nil; + } + obj->u.d.cap = newcap; + + return fz_okay; +} + +int +fz_dictlen(fz_obj *obj) +{ + if (!fz_isdict(obj)) + return 0; + return obj->u.d.len; +} + +fz_obj * +fz_dictgetkey(fz_obj *obj, int i) +{ + if (!fz_isdict(obj)) + return nil; + + if (i < 0 || i >= obj->u.d.len) + return nil; + + return obj->u.d.items[i].k; +} + +fz_obj * +fz_dictgetval(fz_obj *obj, int i) +{ + if (!fz_isdict(obj)) + return nil; + + if (i < 0 || i >= obj->u.d.len) + return nil; + + return obj->u.d.items[i].v; +} + +static inline int dictfinds(fz_obj *obj, char *key) +{ + if (obj->u.d.sorted) + { + int l = 0; + int r = obj->u.d.len - 1; + while (l <= r) + { + int m = (l + r) >> 1; + int c = -keystrcmp(obj->u.d.items[m].k, key); + if (c < 0) + r = m - 1; + else if (c > 0) + l = m + 1; + else + return m; + } + } + + else + { + int i; + for (i = 0; i < obj->u.d.len; i++) + if (keystrcmp(obj->u.d.items[i].k, key) == 0) + return i; + } + + return -1; +} + +fz_obj * +fz_dictgets(fz_obj *obj, char *key) +{ + int i; + + if (!fz_isdict(obj)) + return nil; + + i = dictfinds(obj, key); + if (i >= 0) + return obj->u.d.items[i].v; + + return nil; +} + +fz_obj * +fz_dictget(fz_obj *obj, fz_obj *key) +{ + if (fz_isname(key)) + return fz_dictgets(obj, fz_toname(key)); + if (fz_isstring(key)) + return fz_dictgets(obj, fz_tostrbuf(key)); + return nil; +} + +fz_obj * +fz_dictgetsa(fz_obj *obj, char *key, char *abbrev) +{ + fz_obj *v; + v = fz_dictgets(obj, key); + if (v) + return v; + return fz_dictgets(obj, abbrev); +} + +fz_error * +fz_dictput(fz_obj *obj, fz_obj *key, fz_obj *val) +{ + fz_error *error; + char *s; + int i; + + if (!fz_isdict(obj)) + return fz_throw("assert: not a dict (%s)", fz_objkindstr(obj)); + + if (fz_isname(key)) + s = fz_toname(key); + else if (fz_isstring(key)) + s = fz_tostrbuf(key); + else + return fz_throw("assert: key is not string or name (%s)", fz_objkindstr(obj)); + + i = dictfinds(obj, s); + if (i >= 0) + { + fz_dropobj(obj->u.d.items[i].v); + obj->u.d.items[i].v = fz_keepobj(val); + return fz_okay; + } + + if (obj->u.d.len + 1 > obj->u.d.cap) + { + error = growdict(obj); + if (error) + return fz_rethrow(error, "cannot grow dict item buffer"); + } + + /* borked! */ + if (obj->u.d.len) + if (keystrcmp(obj->u.d.items[obj->u.d.len - 1].k, s) > 0) + obj->u.d.sorted = 0; + + obj->u.d.items[obj->u.d.len].k = fz_keepobj(key); + obj->u.d.items[obj->u.d.len].v = fz_keepobj(val); + obj->u.d.len ++; + + return fz_okay; +} + +fz_error * +fz_dictputs(fz_obj *obj, char *key, fz_obj *val) +{ + fz_error *error; + fz_obj *keyobj; + error = fz_newname(&keyobj, key); + if (error) + return fz_rethrow(error, "cannot create dict key"); + error = fz_dictput(obj, keyobj, val); + fz_dropobj(keyobj); + if (error) + return fz_rethrow(error, "cannot insert dict entry"); + return fz_okay; +} + +fz_error * +fz_dictdels(fz_obj *obj, char *key) +{ + int i; + + if (!fz_isdict(obj)) + return fz_throw("assert: not a dict (%s)", fz_objkindstr(obj)); + + i = dictfinds(obj, key); + if (i >= 0) + { + fz_dropobj(obj->u.d.items[i].k); + fz_dropobj(obj->u.d.items[i].v); + obj->u.d.sorted = 0; + obj->u.d.items[i] = obj->u.d.items[obj->u.d.len-1]; + obj->u.d.len --; + } + + return fz_okay; +} + +fz_error * +fz_dictdel(fz_obj *obj, fz_obj *key) +{ + if (fz_isname(key)) + return fz_dictdels(obj, fz_toname(key)); + else if (fz_isstring(key)) + return fz_dictdels(obj, fz_tostrbuf(key)); + else + return fz_throw("assert: key is not string or name (%s)", fz_objkindstr(obj)); +} + +void +fz_dropdict(fz_obj *obj) +{ + int i; + + if (!fz_isdict(obj)) + return; + + for (i = 0; i < obj->u.d.len; i++) { + if (obj->u.d.items[i].k) + fz_dropobj(obj->u.d.items[i].k); + if (obj->u.d.items[i].v) + fz_dropobj(obj->u.d.items[i].v); + } + + fz_free(obj->u.d.items); + fz_free(obj); +} + +void +fz_sortdict(fz_obj *obj) +{ + if (!fz_isdict(obj)) + return; + if (!obj->u.d.sorted) + { + qsort(obj->u.d.items, obj->u.d.len, sizeof(fz_keyval), keyvalcmp); + obj->u.d.sorted = 1; + } +} + diff --git a/fitz/obj_parse.c b/fitz/obj_parse.c new file mode 100644 index 00000000..48d59538 --- /dev/null +++ b/fitz/obj_parse.c @@ -0,0 +1,492 @@ +#include "fitz-base.h" +#include "fitz-stream.h" + +struct vap { va_list ap; }; + +static inline int iswhite(int ch) +{ + return + ch == '\000' || + ch == '\011' || + ch == '\012' || + ch == '\014' || + ch == '\015' || + ch == '\040'; +} + +static inline int isdelim(int ch) +{ + return + ch == '(' || ch == ')' || + ch == '<' || ch == '>' || + ch == '[' || ch == ']' || + ch == '{' || ch == '}' || + ch == '/' || + ch == '%'; +} + +static inline int isregular(int ch) +{ + return !isdelim(ch) && !iswhite(ch) && ch != EOF; +} + +static fz_error *parseobj(fz_obj **obj, char **sp, struct vap *v); + +static inline int fromhex(char ch) +{ + if (ch >= '0' && ch <= '9') + return ch - '0'; + else if (ch >= 'A' && ch <= 'F') + return ch - 'A' + 0xA; + else if (ch >= 'a' && ch <= 'f') + return ch - 'a' + 0xA; + return 0; +} + +static inline void skipwhite(char **sp) +{ + char *s = *sp; + while (iswhite(*s)) + s ++; + *sp = s; +} + +static void parsekeyword(char **sp, char *b, char *eb) +{ + char *s = *sp; + while (b < eb && isregular(*s)) + *b++ = *s++; + *b++ = 0; + *sp = s; +} + +static fz_error *parsename(fz_obj **obj, char **sp) +{ + fz_error *error; + char buf[64]; + char *s = *sp; + char *p = buf; + + s ++; /* skip '/' */ + while (p < buf + sizeof buf - 1 && isregular(*s)) + *p++ = *s++; + *p++ = 0; + *sp = s; + + error = fz_newname(obj, buf); + if (error) + return fz_rethrow(error, "cannot create name"); + return fz_okay; +} + +static fz_error *parsenumber(fz_obj **obj, char **sp) +{ + fz_error *error; + char buf[32]; + char *s = *sp; + char *p = buf; + + while (p < buf + sizeof buf - 1) + { + if (s[0] == '-' || s[0] == '.' || (s[0] >= '0' && s[0] <= '9')) + *p++ = *s++; + else + break; + } + *p++ = 0; + *sp = s; + + if (strchr(buf, '.')) + error = fz_newreal(obj, atof(buf)); + else + error = fz_newint(obj, atoi(buf)); + + if (error) + return fz_rethrow(error, "cannot parse number"); + return fz_okay; +} + +static fz_error *parsedict(fz_obj **obj, char **sp, struct vap *v) +{ + fz_error *error = fz_okay; + fz_obj *dict = nil; + fz_obj *key = nil; + fz_obj *val = nil; + char *s = *sp; + + error = fz_newdict(&dict, 8); + if (error) + return fz_rethrow(error, "cannot create dict"); + + s += 2; /* skip "<<" */ + + while (*s) + { + skipwhite(&s); + + /* end-of-dict marker >> */ + if (*s == '>') + { + s ++; + if (*s == '>') + { + s ++; + break; + } + error = fz_throw("malformed >> marker"); + goto cleanup; + } + + /* non-name as key, bail */ + if (*s != '/') + { + error = fz_throw("key is not a name"); + goto cleanup; + } + + error = parsename(&key, &s); + if (error) + { + error = fz_rethrow(error, "cannot parse key"); + goto cleanup; + } + + skipwhite(&s); + + error = parseobj(&val, &s, v); + if (error) + { + error = fz_rethrow(error, "cannot parse value"); + goto cleanup; + } + + error = fz_dictput(dict, key, val); + if (error) + { + error = fz_rethrow(error, "cannot insert dict entry"); + goto cleanup; + } + + fz_dropobj(val); val = nil; + fz_dropobj(key); key = nil; + } + + *obj = dict; + *sp = s; + return fz_okay; + +cleanup: + if (val) fz_dropobj(val); + if (key) fz_dropobj(key); + if (dict) fz_dropobj(dict); + *obj = nil; + *sp = s; + return error; /* already rethrown */ +} + +static fz_error *parsearray(fz_obj **obj, char **sp, struct vap *v) +{ + fz_error *error; + fz_obj *a; + fz_obj *o; + char *s = *sp; + + error = fz_newarray(&a, 8); + if (error) + return fz_rethrow(error, "cannot create array"); + + s ++; /* skip '[' */ + + while (*s) + { + skipwhite(&s); + + if (*s == ']') + { + s ++; + break; + } + + error = parseobj(&o, &s, v); + if (error) + { + fz_dropobj(a); + return fz_rethrow(error, "cannot parse item"); + } + + error = fz_arraypush(a, o); + if (error) + { + fz_dropobj(o); + fz_dropobj(a); + return fz_rethrow(error, "cannot add item to array"); + } + + fz_dropobj(o); + } + + *obj = a; + *sp = s; + return fz_okay; +} + +static fz_error *parsestring(fz_obj **obj, char **sp) +{ + fz_error *error; + char buf[512]; + char *s = *sp; + char *p = buf; + int balance = 1; + int oct; + + s ++; /* skip '(' */ + + while (*s && p < buf + sizeof buf) + { + if (*s == '(') + { + balance ++; + *p++ = *s++; + } + else if (*s == ')') + { + balance --; + *p++ = *s++; + } + else if (*s == '\\') + { + s ++; + if (*s >= '0' && *s <= '9') + { + oct = *s - '0'; + s ++; + if (*s >= '0' && *s <= '9') + { + oct = oct * 8 + (*s - '0'); + s ++; + if (*s >= '0' && *s <= '9') + { + oct = oct * 8 + (*s - '0'); + s ++; + } + } + *p++ = oct; + } + else switch (*s) + { + case 'n': *p++ = '\n'; s++; break; + case 'r': *p++ = '\r'; s++; break; + case 't': *p++ = '\t'; s++; break; + case 'b': *p++ = '\b'; s++; break; + case 'f': *p++ = '\f'; s++; break; + default: *p++ = *s++; break; + } + } + else + *p++ = *s++; + + if (balance == 0) + break; + } + + *sp = s; + + error = fz_newstring(obj, buf, p - buf - 1); + if (error) + return fz_rethrow(error, "cannot create string"); + return fz_okay; +} + +static fz_error *parsehexstring(fz_obj **obj, char **sp) +{ + fz_error *error; + char buf[512]; + char *s = *sp; + char *p = buf; + int a, b; + + s ++; /* skip '<' */ + + while (*s && p < buf + sizeof buf) + { + skipwhite(&s); + if (*s == '>') { + s ++; + break; + } + a = *s++; + + if (*s == '\0') + break; + + skipwhite(&s); + if (*s == '>') { + s ++; + break; + } + b = *s++; + + *p++ = fromhex(a) * 16 + fromhex(b); + } + + *sp = s; + error = fz_newstring(obj, buf, p - buf); + if (error) + return fz_rethrow(error, "cannot create string"); + return fz_okay; +} + +static fz_error *parseobj(fz_obj **obj, char **sp, struct vap *v) +{ + fz_error *error; + char buf[32]; + int oid, gid, len; + char *tmp; + char *s = *sp; + + if (*s == '\0') + return fz_throw("end of data"); + + skipwhite(&s); + + error = fz_okay; + + if (v != nil && *s == '%') + { + s ++; + + switch (*s) + { + case 'p': error = fz_newpointer(obj, va_arg(v->ap, void*)); break; + case 'o': *obj = fz_keepobj(va_arg(v->ap, fz_obj*)); break; + case 'b': error = fz_newbool(obj, va_arg(v->ap, int)); break; + case 'i': error = fz_newint(obj, va_arg(v->ap, int)); break; + case 'f': error = fz_newreal(obj, (float)va_arg(v->ap, double)); break; + case 'n': error = fz_newname(obj, va_arg(v->ap, char*)); break; + case 'r': + oid = va_arg(v->ap, int); + gid = va_arg(v->ap, int); + error = fz_newindirect(obj, oid, gid); + break; + case 's': + tmp = va_arg(v->ap, char*); + error = fz_newstring(obj, tmp, strlen(tmp)); + break; + case '#': + tmp = va_arg(v->ap, char*); + len = va_arg(v->ap, int); + error = fz_newstring(obj, tmp, len); + break; + default: + error = fz_throw("unknown format specifier in packobj: '%c'", *s); + break; + } + + if (error) + error = fz_rethrow(error, "cannot create object for %% format"); + + s ++; + } + + else if (*s == '/') + { + error = parsename(obj, &s); + if (error) + error = fz_rethrow(error, "cannot parse name"); + } + + else if (*s == '(') + { + error = parsestring(obj, &s); + if (error) + error = fz_rethrow(error, "cannot parse string"); + } + + else if (*s == '<') + { + if (s[1] == '<') + { + error = parsedict(obj, &s, v); + if (error) + error = fz_rethrow(error, "cannot parse dict"); + } + else + { + error = parsehexstring(obj, &s); + if (error) + error = fz_rethrow(error, "cannot parse hex string"); + } + } + + else if (*s == '[') + { + error = parsearray(obj, &s, v); + if (error) + error = fz_rethrow(error, "cannot parse array"); + } + + else if (*s == '-' || *s == '.' || (*s >= '0' && *s <= '9')) + { + error = parsenumber(obj, &s); + if (error) + error = fz_rethrow(error, "cannot parse number"); + } + + else if (isregular(*s)) + { + parsekeyword(&s, buf, buf + sizeof buf); + + if (strcmp("true", buf) == 0) + { + error = fz_newbool(obj, 1); + if (error) + error = fz_rethrow(error, "cannot create bool (true)"); + } + else if (strcmp("false", buf) == 0) + { + error = fz_newbool(obj, 0); + if (error) + error = fz_rethrow(error, "cannot create bool (false)"); + } + else if (strcmp("null", buf) == 0) + { + error = fz_newnull(obj); + if (error) + error = fz_rethrow(error, "cannot create null object"); + } + else + error = fz_throw("undefined keyword %s", buf); + } + + else + error = fz_throw("syntax error: unknown byte 0x%d", *s); + + *sp = s; + return error; /* already rethrown */ +} + +fz_error * +fz_packobj(fz_obj **op, char *fmt, ...) +{ + fz_error *error; + struct vap v; + va_list ap; + + va_start(ap, fmt); + va_copy(v.ap, ap); + + error = parseobj(op, &fmt, &v); + + va_end(ap); + + if (error) + return fz_rethrow(error, "cannot parse object"); + return fz_okay; +} + +fz_error * +fz_parseobj(fz_obj **op, char *str) +{ + return parseobj(op, &str, nil); +} + diff --git a/fitz/obj_print.c b/fitz/obj_print.c new file mode 100644 index 00000000..4e321127 --- /dev/null +++ b/fitz/obj_print.c @@ -0,0 +1,339 @@ +#include "fitz-base.h" +#include "fitz-stream.h" + +struct fmt +{ + char *buf; + int cap; + int len; + int indent; + int tight; + int col; + int sep; + int last; +}; + +static void fmtobj(struct fmt *fmt, fz_obj *obj); + +static inline int iswhite(int ch) +{ + return + ch == '\000' || + ch == '\011' || + ch == '\012' || + ch == '\014' || + ch == '\015' || + ch == '\040'; +} + +static inline int isdelim(int ch) +{ + return ch == '(' || ch == ')' || + ch == '<' || ch == '>' || + ch == '[' || ch == ']' || + ch == '{' || ch == '}' || + ch == '/' || + ch == '%'; +} + +static inline void fmtputc(struct fmt *fmt, int c) +{ + if (fmt->sep && !isdelim(fmt->last) && !isdelim(c)) { + fmt->sep = 0; + fmtputc(fmt, ' '); + } + fmt->sep = 0; + + if (fmt->buf && fmt->len < fmt->cap) + fmt->buf[fmt->len] = c; + + if (c == '\n') + fmt->col = 0; + else + fmt->col ++; + + fmt->len ++; + + fmt->last = c; +} + +static void fmtindent(struct fmt *fmt) +{ + int i = fmt->indent; + while (i--) { + fmtputc(fmt, ' '); + fmtputc(fmt, ' '); + } +} + +static inline void fmtputs(struct fmt *fmt, char *s) +{ + while (*s) + fmtputc(fmt, *s++); +} + +static inline void fmtsep(struct fmt *fmt) +{ + fmt->sep = 1; +} + +static void fmtstr(struct fmt *fmt, fz_obj *obj) +{ + int i; + int c; + + fmtputc(fmt, '('); + for (i = 0; i < obj->u.s.len; i++) + { + c = (unsigned char) obj->u.s.buf[i]; + if (c == '\n') + fmtputs(fmt, "\\n"); + else if (c == '\r') + fmtputs(fmt, "\\r"); + else if (c == '\t') + fmtputs(fmt, "\\t"); + else if (c == '\b') + fmtputs(fmt, "\\b"); + else if (c == '\f') + fmtputs(fmt, "\\f"); + else if (c == '(') + fmtputs(fmt, "\\("); + else if (c == ')') + fmtputs(fmt, "\\)"); + else if (c < 32 || c > 126) { + char buf[16]; + fmtputc(fmt, '\\'); + sprintf(buf, "%o", c); + fmtputs(fmt, buf); + } + else + fmtputc(fmt, c); + } + fmtputc(fmt, ')'); +} + +static void fmthex(struct fmt *fmt, fz_obj *obj) +{ + int i; + int b; + int c; + + fmtputc(fmt, '<'); + for (i = 0; i < obj->u.s.len; i++) { + b = (unsigned char) obj->u.s.buf[i]; + c = (b >> 4) & 0x0f; + fmtputc(fmt, c < 0xA ? c + '0' : c + 'A' - 0xA); + c = (b) & 0x0f; + fmtputc(fmt, c < 0xA ? c + '0' : c + 'A' - 0xA); + } + fmtputc(fmt, '>'); +} + +static void fmtname(struct fmt *fmt, fz_obj *obj) +{ + char *s = fz_toname(obj); + int i, c; + + fmtputc(fmt, '/'); + + for (i = 0; s[i]; i++) + { + if (isdelim(s[i]) || iswhite(s[i])) + { + fmtputc(fmt, '#'); + c = (s[i] >> 4) & 0xf; + fmtputc(fmt, c < 0xA ? c + '0' : c + 'A' - 0xA); + c = s[i] & 0xf; + fmtputc(fmt, c < 0xA ? c + '0' : c + 'A' - 0xA); + } + else + { + fmtputc(fmt, s[i]); + } + } +} + +static void fmtarray(struct fmt *fmt, fz_obj *obj) +{ + int i; + + if (fmt->tight) { + fmtputc(fmt, '['); + for (i = 0; i < fz_arraylen(obj); i++) { + fmtobj(fmt, fz_arrayget(obj, i)); + fmtsep(fmt); + } + fmtputc(fmt, ']'); + } + else { + fmtputs(fmt, "[ "); + for (i = 0; i < fz_arraylen(obj); i++) { + if (fmt->col > 60) { + fmtputc(fmt, '\n'); + fmtindent(fmt); + } + fmtobj(fmt, fz_arrayget(obj, i)); + fmtputc(fmt, ' '); + } + fmtputc(fmt, ']'); + fmtsep(fmt); + } +} + +static void fmtdict(struct fmt *fmt, fz_obj *obj) +{ + int i; + fz_obj *key, *val; + + if (fmt->tight) { + fmtputs(fmt, "<<"); + for (i = 0; i < fz_dictlen(obj); i++) { + fmtobj(fmt, fz_dictgetkey(obj, i)); + fmtsep(fmt); + fmtobj(fmt, fz_dictgetval(obj, i)); + fmtsep(fmt); + } + fmtputs(fmt, ">>"); + } + else { + fmtputs(fmt, "<<\n"); + fmt->indent ++; + for (i = 0; i < fz_dictlen(obj); i++) { + key = fz_dictgetkey(obj, i); + val = fz_dictgetval(obj, i); + fmtindent(fmt); + fmtobj(fmt, key); + fmtputc(fmt, ' '); + if (fz_isarray(val)) + fmt->indent ++; + fmtobj(fmt, val); + fmtputc(fmt, '\n'); + if (fz_isarray(val)) + fmt->indent --; + } + fmt->indent --; + fmtindent(fmt); + fmtputs(fmt, ">>"); + } +} + +static void fmtobj(struct fmt *fmt, fz_obj *obj) +{ + char buf[256]; + + if (!obj) { + fmtputs(fmt, ""); + return; + } + + switch (obj->kind) + { + case FZ_NULL: + fmtputs(fmt, "null"); + break; + case FZ_BOOL: + fmtputs(fmt, fz_tobool(obj) ? "true" : "false"); + break; + case FZ_INT: + sprintf(buf, "%d", fz_toint(obj)); + fmtputs(fmt, buf); + break; + case FZ_REAL: + sprintf(buf, "%g", fz_toreal(obj)); + if (strchr(buf, 'e')) /* bad news! */ + sprintf(buf, fabs(fz_toreal(obj)) > 1 ? "%1.1f" : "%1.8f", fz_toreal(obj)); + fmtputs(fmt, buf); + break; + case FZ_STRING: + { + int added = 0; + int i, c; + for (i = 0; i < obj->u.s.len; i++) { + c = (unsigned char)obj->u.s.buf[i]; + if (strchr("()\\\n\r\t\b\f", c) != 0) + added ++; + else if (c < 8) + added ++; + else if (c < 32) + added += 2; + else if (c >= 127) + added += 3; + } + if (added < obj->u.s.len) + fmtstr(fmt, obj); + else + fmthex(fmt, obj); + } + break; + case FZ_NAME: + fmtname(fmt, obj); + break; + case FZ_ARRAY: + fmtarray(fmt, obj); + break; + case FZ_DICT: + fmtdict(fmt, obj); + break; + case FZ_INDIRECT: + sprintf(buf, "%d %d R", obj->u.r.oid, obj->u.r.gid); + fmtputs(fmt, buf); + break; + case FZ_POINTER: + sprintf(buf, "$%p", obj->u.p); + fmtputs(fmt, buf); + break; + default: + sprintf(buf, "", obj->kind); + fmtputs(fmt, buf); + break; + } +} + +int +fz_sprintobj(char *s, int n, fz_obj *obj, int tight) +{ + struct fmt fmt; + + fmt.indent = 0; + fmt.col = 0; + fmt.sep = 0; + fmt.last = 0; + + fmt.tight = tight; + fmt.buf = s; + fmt.cap = n; + fmt.len = 0; + fmtobj(&fmt, obj); + + if (fmt.buf && fmt.len < fmt.cap) + fmt.buf[fmt.len] = '\0'; + + return fmt.len; +} + +void +fz_debugobj(fz_obj *obj) +{ + char buf[1024]; + char *ptr; + int n; + + n = fz_sprintobj(nil, 0, obj, 0); + if (n < sizeof buf) + { + fz_sprintobj(buf, sizeof buf, obj, 0); + fputs(buf, stdout); + fputc('\n', stdout); + } + else + { + ptr = fz_malloc(n); + if (!ptr) + return; + fz_sprintobj(ptr, n, obj, 0); + fputs(ptr, stdout); + fputc('\n', stdout); + fz_free(ptr); + } +} + diff --git a/fitz/obj_simple.c b/fitz/obj_simple.c new file mode 100644 index 00000000..d8eb77b7 --- /dev/null +++ b/fitz/obj_simple.c @@ -0,0 +1,323 @@ +#include "fitz-base.h" +#include "fitz-stream.h" + +extern void fz_droparray(fz_obj *array); +extern void fz_dropdict(fz_obj *dict); + +#define NEWOBJ(KIND,SIZE) \ + fz_obj *o; \ + o = *op = fz_malloc(SIZE); \ + if (!o) return fz_throw("outofmem: dynamic object"); \ + o->refs = 1; \ + o->kind = KIND; + +fz_error * +fz_newnull(fz_obj **op) +{ + NEWOBJ(FZ_NULL, sizeof (fz_obj)); + return fz_okay; +} + +fz_error * +fz_newbool(fz_obj **op, int b) +{ + NEWOBJ(FZ_BOOL, sizeof (fz_obj)); + o->u.b = b; + return fz_okay; +} + +fz_error * +fz_newint(fz_obj **op, int i) +{ + NEWOBJ(FZ_INT, sizeof (fz_obj)); + o->u.i = i; + return fz_okay; +} + +fz_error * +fz_newreal(fz_obj **op, float f) +{ + NEWOBJ(FZ_REAL, sizeof (fz_obj)); + o->u.f = f; + return fz_okay; +} + +fz_error * +fz_newstring(fz_obj **op, char *str, int len) +{ + NEWOBJ(FZ_STRING, offsetof(fz_obj, u.s.buf) + len + 1); + o->u.s.len = len; + memcpy(o->u.s.buf, str, len); + o->u.s.buf[len] = '\0'; + return fz_okay; +} + +fz_error * +fz_newname(fz_obj **op, char *str) +{ + NEWOBJ(FZ_NAME, offsetof(fz_obj, u.n) + strlen(str) + 1); + strcpy(o->u.n, str); + return fz_okay; +} + +fz_error * +fz_newindirect(fz_obj **op, int objid, int genid) +{ + NEWOBJ(FZ_INDIRECT, sizeof (fz_obj)); + o->u.r.oid = objid; + o->u.r.gid = genid; + return fz_okay; +} + +fz_error * +fz_newpointer(fz_obj **op, void *p) +{ + NEWOBJ(FZ_POINTER, sizeof (fz_obj)); + o->u.p = p; + return fz_okay; +} + +fz_obj * +fz_keepobj(fz_obj *o) +{ + assert(o != nil); + o->refs ++; + return o; +} + +void +fz_dropobj(fz_obj *o) +{ + assert(o != nil); + if (--o->refs == 0) + { + if (o->kind == FZ_ARRAY) + fz_droparray(o); + else if (o->kind == FZ_DICT) + fz_dropdict(o); + else + fz_free(o); + } +} + +int +fz_isnull(fz_obj *obj) +{ + return obj ? obj->kind == FZ_NULL : 0; +} + +int +fz_isbool(fz_obj *obj) +{ + return obj ? obj->kind == FZ_BOOL : 0; +} + +int +fz_isint(fz_obj *obj) +{ + return obj ? obj->kind == FZ_INT : 0; +} + +int +fz_isreal(fz_obj *obj) +{ + return obj ? obj->kind == FZ_REAL : 0; +} + +int +fz_isstring(fz_obj *obj) +{ + return obj ? obj->kind == FZ_STRING : 0; +} + +int +fz_isname(fz_obj *obj) +{ + return obj ? obj->kind == FZ_NAME : 0; +} + +int +fz_isarray(fz_obj *obj) +{ + return obj ? obj->kind == FZ_ARRAY : 0; +} + +int +fz_isdict(fz_obj *obj) +{ + return obj ? obj->kind == FZ_DICT : 0; +} + +int +fz_isindirect(fz_obj *obj) +{ + return obj ? obj->kind == FZ_INDIRECT : 0; +} + +int +fz_ispointer(fz_obj *obj) +{ + return obj ? obj->kind == FZ_POINTER : 0; +} + +int +fz_tobool(fz_obj *obj) +{ + if (fz_isbool(obj)) + return obj->u.b; + return 0; +} + +int +fz_toint(fz_obj *obj) +{ + if (fz_isint(obj)) + return obj->u.i; + if (fz_isreal(obj)) + return obj->u.f; + return 0; +} + +float +fz_toreal(fz_obj *obj) +{ + if (fz_isreal(obj)) + return obj->u.f; + if (fz_isint(obj)) + return obj->u.i; + return 0; +} + +char * +fz_toname(fz_obj *obj) +{ + if (fz_isname(obj)) + return obj->u.n; + return ""; +} + +char * +fz_tostrbuf(fz_obj *obj) +{ + if (fz_isstring(obj)) + return obj->u.s.buf; + return ""; +} + +int +fz_tostrlen(fz_obj *obj) +{ + if (fz_isstring(obj)) + return obj->u.s.len; + return 0; +} + +int +fz_tonum(fz_obj *obj) +{ + if (fz_isindirect(obj)) + return obj->u.r.oid; + return 0; +} + +int +fz_togen(fz_obj *obj) +{ + if (fz_isindirect(obj)) + return obj->u.r.gid; + return 0; +} + +void * +fz_topointer(fz_obj *obj) +{ + if (fz_ispointer(obj)) + return obj->u.p; + return fz_okay; +} + +fz_error * +fz_newnamefromstring(fz_obj **op, fz_obj *str) +{ + NEWOBJ(FZ_NAME, offsetof(fz_obj, u.n) + fz_tostrlen(str) + 1); + memcpy(o->u.n, fz_tostrbuf(str), fz_tostrlen(str)); + o->u.n[fz_tostrlen(str)] = '\0'; + return fz_okay; +} + +int +fz_objcmp(fz_obj *a, fz_obj *b) +{ + int i; + + if (a == b) + return 0; + if (a->kind != b->kind) + return 1; + + switch (a->kind) + { + case FZ_NULL: return 0; + case FZ_BOOL: return a->u.b - b->u.b; + case FZ_INT: return a->u.i - b->u.i; + case FZ_REAL: return a->u.f - b->u.f; + + case FZ_STRING: + if (a->u.s.len != b->u.s.len) + return a->u.s.len - b->u.s.len; + return memcmp(a->u.s.buf, b->u.s.buf, a->u.s.len); + + case FZ_NAME: + return strcmp(a->u.n, b->u.n); + + case FZ_INDIRECT: + if (a->u.r.oid == b->u.r.oid) + return a->u.r.gid - b->u.r.gid; + return a->u.r.oid - b->u.r.oid; + + case FZ_ARRAY: + if (a->u.a.len != b->u.a.len) + return a->u.a.len - b->u.a.len; + for (i = 0; i < a->u.a.len; i++) + if (fz_objcmp(a->u.a.items[i], b->u.a.items[i])) + return 1; + return 0; + + case FZ_DICT: + if (a->u.d.len != b->u.d.len) + return a->u.d.len - b->u.d.len; + for (i = 0; i < a->u.d.len; i++) + { + if (fz_objcmp(a->u.d.items[i].k, b->u.d.items[i].k)) + return 1; + if (fz_objcmp(a->u.d.items[i].v, b->u.d.items[i].v)) + return 1; + } + return 0; + + case FZ_POINTER: + return (char *) a->u.p - (char *) b->u.p; + } + return 1; +} + +char *fz_objkindstr(fz_obj *obj) +{ + if (obj == nil) + return ""; + switch (obj->kind) + { + case FZ_NULL: return "null"; + case FZ_BOOL: return "boolean"; + case FZ_INT: return "integer"; + case FZ_REAL: return "real"; + case FZ_STRING: return "string"; + case FZ_NAME: return "name"; + case FZ_ARRAY: return "array"; + case FZ_DICT: return "dictionary"; + case FZ_INDIRECT: return "reference"; + case FZ_POINTER: return "pointer"; + } + return ""; +} + diff --git a/fitz/res_colorspace.c b/fitz/res_colorspace.c new file mode 100644 index 00000000..04fc532e --- /dev/null +++ b/fitz/res_colorspace.c @@ -0,0 +1,88 @@ +#include "fitz-base.h" +#include "fitz-world.h" + +void +fz_convertpixmap(fz_colorspace *srcs, fz_pixmap *src, fz_colorspace *dsts, fz_pixmap *dst) +{ + srcs->convpixmap(srcs, src, dsts, dst); +} + +void +fz_convertcolor(fz_colorspace *srcs, float *srcv, fz_colorspace *dsts, float *dstv) +{ + srcs->convcolor(srcs, srcv, dsts, dstv); +} + +fz_colorspace * +fz_keepcolorspace(fz_colorspace *cs) +{ + if (cs->refs < 0) + return cs; + cs->refs ++; + return cs; +} + +void +fz_dropcolorspace(fz_colorspace *cs) +{ + if (cs && cs->refs < 0) + return; + if (cs && --cs->refs == 0) + { + if (cs->drop) + cs->drop(cs); + fz_free(cs); + } +} + +void +fz_stdconvcolor(fz_colorspace *srcs, float *srcv, fz_colorspace *dsts, float *dstv) +{ + float xyz[3]; + int i; + + if (srcs != dsts) + { + srcs->toxyz(srcs, srcv, xyz); + dsts->fromxyz(dsts, xyz, dstv); + for (i = 0; i < dsts->n; i++) + dstv[i] = CLAMP(dstv[i], 0.0, 1.0); + } + else + { + for (i = 0; i < srcs->n; i++) + dstv[i] = srcv[i]; + } +} + +void +fz_stdconvpixmap(fz_colorspace *srcs, fz_pixmap *src, fz_colorspace *dsts, fz_pixmap *dst) +{ + float srcv[FZ_MAXCOLORS]; + float dstv[FZ_MAXCOLORS]; + int y, x, k; + + unsigned char *s = src->samples; + unsigned char *d = dst->samples; + + assert(src->w == dst->w && src->h == dst->h); + assert(src->n == srcs->n + 1); + assert(dst->n == dsts->n + 1); + + for (y = 0; y < src->h; y++) + { + for (x = 0; x < src->w; x++) + { + *d++ = *s++; + + for (k = 0; k < src->n - 1; k++) + srcv[k] = *s++ / 255.0; + + fz_convertcolor(srcs, srcv, dsts, dstv); + + for (k = 0; k < dst->n - 1; k++) + *d++ = dstv[k] * 255; + } + } +} + diff --git a/fitz/res_font.c b/fitz/res_font.c new file mode 100644 index 00000000..7238cc3c --- /dev/null +++ b/fitz/res_font.c @@ -0,0 +1,408 @@ +#include "fitz-base.h" +#include "fitz-world.h" +#include "fitz-draw.h" /* for type3 font rendering */ + +#include +#include FT_FREETYPE_H + +static fz_font * +fz_newfont(void) +{ + fz_font *font; + + font = fz_malloc(sizeof(fz_font)); + if (!font) + return nil; + + font->refs = 1; + strcpy(font->name, ""); + + font->ftface = nil; + font->ftsubstitute = 0; + font->fthint = 0; + + font->t3matrix = fz_identity(); + font->t3procs = nil; + + font->bbox.x0 = 0; + font->bbox.y0 = 0; + font->bbox.x1 = 1000; + font->bbox.y1 = 1000; + + return font; +} + +fz_font * +fz_keepfont(fz_font *font) +{ + font->refs ++; + return font; +} + +void +fz_dropfont(fz_font *font) +{ + int i; + + if (font && --font->refs == 0) + { + if (font->t3procs) + { + for (i = 0; i < 256; i++) + if (font->t3procs[i]) + fz_droptree(font->t3procs[i]); + fz_free(font->t3procs); + } + + if (font->ftface) + { + FT_Done_Face((FT_Face)font->ftface); + } + + fz_free(font); + } +} + +void +fz_setfontbbox(fz_font *font, int xmin, int ymin, int xmax, int ymax) +{ + font->bbox.x0 = xmin; + font->bbox.y0 = ymin; + font->bbox.x1 = xmax; + font->bbox.y1 = ymax; +} + +/* + * Freetype hooks + */ + +static FT_Library fz_ftlib = nil; + +#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; +}; + +const struct ft_error ft_errors[] = +{ +#include FT_ERRORS_H +}; + +char *ft_errorstring(int err) +{ + const struct ft_error *e; + + for (e = ft_errors; e->str != NULL; e++) + if (e->err == err) + return e->str; + + return "Unknown error"; +} + +static fz_error * +fz_initfreetype(void) +{ + int code; + int maj, min, pat; + + if (fz_ftlib) + return fz_okay; + + code = FT_Init_FreeType(&fz_ftlib); + if (code) + return fz_throw("cannot init freetype: %s", ft_errorstring(code)); + + FT_Library_Version(fz_ftlib, &maj, &min, &pat); + if (maj == 2 && min == 1 && pat < 7) + return fz_throw("freetype version too old: %d.%d.%d", maj, min, pat); + + return fz_okay; +} + +fz_error * +fz_newfontfromfile(fz_font **fontp, char *path, int index) +{ + fz_error *error; + fz_font *font; + int code; + + error = fz_initfreetype(); + if (error) + return fz_rethrow(error, "cannot init freetype library"); + + font = fz_newfont(); + if (!font) + return fz_throw("outofmem: font struct"); + + code = FT_New_Face(fz_ftlib, path, index, (FT_Face*)&font->ftface); + if (code) + { + fz_free(font); + return fz_throw("freetype: cannot load font: %s", ft_errorstring(code)); + } + + *fontp = font; + return fz_okay; +} + +fz_error * +fz_newfontfrombuffer(fz_font **fontp, unsigned char *data, int len, int index) +{ + fz_error *error; + fz_font *font; + int code; + + error = fz_initfreetype(); + if (error) + return fz_rethrow(error, "cannot init freetype library"); + + font = fz_newfont(); + if (!font) + return fz_throw("outofmem: font struct"); + + code = FT_New_Memory_Face(fz_ftlib, data, len, index, (FT_Face*)&font->ftface); + if (code) + { + fz_free(font); + return fz_throw("freetype: cannot load font: %s", ft_errorstring(code)); + } + + *fontp = font; + return fz_okay; +} + +fz_error * +fz_renderftglyph(fz_glyph *glyph, fz_font *font, int gid, fz_matrix trm) +{ + FT_Face face = font->ftface; + FT_Matrix m; + FT_Vector v; + FT_Error fterr; + int x, y; + +#if 0 + /* We lost this feature in refactoring. + * We can't access pdf_fontdesc metrics from fz_font. + * The pdf_fontdesc metrics are character based (cid), + * where the glyph being rendered is given by glyph (gid). + */ + if (font->ftsubstitute && font->wmode == 0) + { + fz_hmtx subw; + int realw; + float scale; + + FT_Set_Char_Size(face, 1000, 1000, 72, 72); + + fterr = FT_Load_Glyph(font->ftface, gid, + FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP | FT_LOAD_IGNORE_TRANSFORM); + if (fterr) + return fz_throw("freetype failed to load glyph: %s", ft_errorstring(fterr)); + + realw = ((FT_Face)font->ftface)->glyph->advance.x; + subw = fz_gethmtx(font, cid); // <-- this is the offender + if (realw) + scale = (float) subw.w / realw; + else + scale = 1.0; + + trm = fz_concat(fz_scale(scale, 1.0), trm); + } +#endif + + glyph->w = 0; + glyph->h = 0; + glyph->x = 0; + glyph->y = 0; + glyph->samples = nil; + + /* 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 = trm.a * 64; /* should be 65536 */ + m.yx = trm.b * 64; + m.xy = trm.c * 64; + m.yy = trm.d * 64; + v.x = trm.e * 64; + v.y = trm.f * 64; + + FT_Set_Char_Size(face, 65536, 65536, 72, 72); /* should be 64, 64 */ + FT_Set_Transform(face, &m, &v); + + if (font->fthint) + { + /* 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. + */ +#ifdef USE_HINTING + /* If you really want grid fitting, enable this code. */ + float scale = fz_matrixexpansion(trm); + m.xx = trm.a * 65536 / scale; + m.xy = trm.b * 65536 / scale; + m.yx = trm.c * 65536 / scale; + m.yy = trm.d * 65536 / scale; + v.x = 0; + v.y = 0; + FT_Set_Char_Size(face, 64 * scale, 64 * scale, 72, 72); + FT_Set_Transform(face, &m, &v); +#endif + fterr = FT_Load_Glyph(face, gid, FT_LOAD_NO_BITMAP); + if (fterr) + fz_warn("freetype load glyph: %s", ft_errorstring(fterr)); + } + else + { + fterr = FT_Load_Glyph(face, gid, FT_LOAD_NO_BITMAP | FT_LOAD_NO_HINTING); + if (fterr) + fz_warn("freetype load glyph: %s", ft_errorstring(fterr)); + } + + fterr = FT_Render_Glyph(face->glyph, ft_render_mode_normal); + if (fterr) + fz_warn("freetype render glyph: %s", ft_errorstring(fterr)); + + glyph->w = face->glyph->bitmap.width; + glyph->h = face->glyph->bitmap.rows; + glyph->x = face->glyph->bitmap_left; + glyph->y = face->glyph->bitmap_top - glyph->h; + glyph->samples = face->glyph->bitmap.buffer; + + for (y = 0; y < glyph->h / 2; y++) + { + for (x = 0; x < glyph->w; x++) + { + unsigned char a = glyph->samples[y * glyph->w + x ]; + unsigned char b = glyph->samples[(glyph->h - y - 1) * glyph->w + x]; + glyph->samples[y * glyph->w + x ] = b; + glyph->samples[(glyph->h - y - 1) * glyph->w + x] = a; + } + } + + return fz_okay; +} + + +/* + * Type 3 fonts... + */ + +fz_error * +fz_newtype3font(fz_font **fontp, char *name, fz_matrix matrix, void **procs0) +{ + fz_font *font; + fz_tree **procs = (fz_tree**)procs0; + int i; + + font = fz_newfont(); + if (!font) + return fz_throw("outofmem: font struct"); + + font->t3procs = fz_malloc(sizeof(fz_tree*) * 256); + if (!font->t3procs) + { + fz_free(font); + return fz_throw("outofmem: type3 font charproc array"); + } + + font->t3matrix = matrix; + for (i = 0; i < 256; i++) + font->t3procs[i] = procs[i]; + + strlcpy(font->name, name, sizeof(font->name)); + + *fontp = font; + return fz_okay; +} + +fz_error * +fz_rendert3glyph(fz_glyph *glyph, fz_font *font, int gid, fz_matrix trm) +{ + fz_error *error; + fz_renderer *gc; + fz_tree *tree; + fz_matrix ctm; + fz_irect bbox; + + /* TODO: make it reentrant */ + static fz_pixmap *pixmap = nil; + if (pixmap) + { + fz_droppixmap(pixmap); + pixmap = nil; + } + + if (gid < 0 || gid > 255) + return fz_throw("assert: glyph out of range"); + + tree = font->t3procs[gid]; + if (!tree) + { + glyph->w = 0; + glyph->h = 0; + return fz_okay; + } + + /* XXX UGLY HACK XXX */ + extern fz_colorspace *pdf_devicegray; + + ctm = fz_concat(font->t3matrix, trm); + bbox = fz_roundrect(fz_boundtree(tree, ctm)); + + error = fz_newrenderer(&gc, pdf_devicegray, 1, 4096); + if (error) + return fz_rethrow(error, "cannot create renderer"); + error = fz_rendertree(&pixmap, gc, tree, ctm, bbox, 0); + fz_droprenderer(gc); + if (error) + return fz_rethrow(error, "cannot render glyph"); + + assert(pixmap->n == 1); + + glyph->x = pixmap->x; + glyph->y = pixmap->y; + glyph->w = pixmap->w; + glyph->h = pixmap->h; + glyph->samples = pixmap->samples; + + return fz_okay; +} + +void +fz_debugfont(fz_font *font) +{ + printf("font '%s' {\n", font->name); + + if (font->ftface) + { + printf(" freetype face %p\n", font->ftface); + if (font->ftsubstitute) + printf(" substitute font\n"); + } + + if (font->t3procs) + { + printf(" type3 matrix [%g %g %g %g]\n", + font->t3matrix.a, font->t3matrix.b, + font->t3matrix.c, font->t3matrix.d); + } + + printf(" bbox [%d %d %d %d]\n", + font->bbox.x0, font->bbox.y0, + font->bbox.x1, font->bbox.y1); + + printf("}\n"); +} + diff --git a/fitz/res_image.c b/fitz/res_image.c new file mode 100644 index 00000000..4379cf17 --- /dev/null +++ b/fitz/res_image.c @@ -0,0 +1,23 @@ +#include "fitz-base.h" +#include "fitz-world.h" + +fz_image * +fz_keepimage(fz_image *image) +{ + image->refs ++; + return image; +} + +void +fz_dropimage(fz_image *image) +{ + if (image && --image->refs == 0) + { + if (image->drop) + image->drop(image); + if (image->cs) + fz_dropcolorspace(image->cs); + fz_free(image); + } +} + diff --git a/fitz/res_shade.c b/fitz/res_shade.c new file mode 100644 index 00000000..d1bd991e --- /dev/null +++ b/fitz/res_shade.c @@ -0,0 +1,29 @@ +#include "fitz-base.h" +#include "fitz-world.h" + +fz_shade * +fz_keepshade(fz_shade *shade) +{ + shade->refs ++; + return shade; +} + +void +fz_dropshade(fz_shade *shade) +{ + if (shade && --shade->refs == 0) + { + if (shade->cs) + fz_dropcolorspace(shade->cs); + fz_free(shade->mesh); + fz_free(shade); + } +} + +fz_rect +fz_boundshade(fz_shade *shade, fz_matrix ctm) +{ + ctm = fz_concat(shade->matrix, ctm); + return fz_transformaabb(ctm, shade->bbox); +} + diff --git a/fitz/stm_buffer.c b/fitz/stm_buffer.c new file mode 100644 index 00000000..8a1e0850 --- /dev/null +++ b/fitz/stm_buffer.c @@ -0,0 +1,105 @@ +#include "fitz-base.h" +#include "fitz-stream.h" + +fz_error * +fz_newbuffer(fz_buffer **bp, int size) +{ + fz_buffer *b; + + b = *bp = fz_malloc(sizeof(fz_buffer)); + if (!b) + return fz_throw("outofmem: buffer struct"); + + b->refs = 1; + b->ownsdata = 1; + b->bp = fz_malloc(size); + if (!b->bp) + { + fz_free(b); + return fz_throw("outofmem: buffer memory"); + } + + b->rp = b->bp; + b->wp = b->bp; + b->ep = b->bp + size; + b->eof = 0; + + return fz_okay; +} + +fz_error * +fz_newbufferwithmemory(fz_buffer **bp, unsigned char *data, int size) +{ + fz_buffer *b; + + b = *bp = fz_malloc(sizeof(fz_buffer)); + if (!b) + return fz_throw("outofmem: buffer struct"); + + b->refs = 1; + b->ownsdata = 0; + b->bp = data; + + b->rp = b->bp; + b->wp = b->bp + size; + b->ep = b->bp + size; + b->eof = 0; + + return fz_okay; +} + +fz_buffer * +fz_keepbuffer(fz_buffer *buf) +{ + buf->refs ++; + return buf; +} + +void +fz_dropbuffer(fz_buffer *buf) +{ + if (--buf->refs == 0) + { + if (buf->ownsdata) + fz_free(buf->bp); + fz_free(buf); + } +} + +fz_error * +fz_growbuffer(fz_buffer *buf) +{ + unsigned char *newbp; + + int rp = buf->rp - buf->bp; + int wp = buf->wp - buf->bp; + int ep = buf->ep - buf->bp; + + if (!buf->ownsdata) + return fz_throw("assert: grow borrowed memory"); + + newbp = fz_realloc(buf->bp, ep * 2); + if (!newbp) + return fz_throw("outofmem: resize buffer memory"); + + buf->bp = newbp; + buf->rp = buf->bp + rp; + buf->wp = buf->bp + wp; + buf->ep = buf->bp + ep * 2; + + return fz_okay; +} + +fz_error * +fz_rewindbuffer(fz_buffer *buf) +{ + if (!buf->ownsdata) + return fz_throw("assert: rewind borrowed memory"); + + memmove(buf->bp, buf->rp, buf->wp - buf->rp); + buf->wp = buf->bp + (buf->wp - buf->rp); + buf->rp = buf->bp; + + return fz_okay; +} + diff --git a/fitz/stm_filter.c b/fitz/stm_filter.c new file mode 100644 index 00000000..450433d4 --- /dev/null +++ b/fitz/stm_filter.c @@ -0,0 +1,61 @@ +#include "fitz-base.h" +#include "fitz-stream.h" + +fz_error fz_kioneedin = { "", "", "", 0, nil }; +fz_error fz_kioneedout = { "", "", "", 0, nil }; +fz_error fz_kiodone = { "", "", "", 0, nil }; + +fz_error * +fz_process(fz_filter *f, fz_buffer *in, fz_buffer *out) +{ + fz_error *reason; + unsigned char *oldrp; + unsigned char *oldwp; + + assert(!out->eof); + + oldrp = in->rp; + oldwp = out->wp; + + if (f->done) + return fz_iodone; + + reason = f->process(f, in, out); + + assert(in->rp <= in->wp); + assert(out->wp <= out->ep); + + f->consumed = in->rp > oldrp; + f->produced = out->wp > oldwp; + f->count += out->wp - oldwp; + + /* iodone or error */ + if (reason != fz_ioneedin && reason != fz_ioneedout) + { + if (reason != fz_iodone) + reason = fz_rethrow(reason, "cannot process filter"); + out->eof = 1; + f->done = 1; + } + + return reason; +} + +fz_filter * +fz_keepfilter(fz_filter *f) +{ + f->refs ++; + return f; +} + +void +fz_dropfilter(fz_filter *f) +{ + if (--f->refs == 0) + { + if (f->drop) + f->drop(f); + fz_free(f); + } +} + diff --git a/fitz/stm_misc.c b/fitz/stm_misc.c new file mode 100644 index 00000000..70c1c315 --- /dev/null +++ b/fitz/stm_misc.c @@ -0,0 +1,97 @@ +/* + * Miscellaneous I/O functions + */ + +#include "fitz-base.h" +#include "fitz-stream.h" + +int +fz_tell(fz_stream *stm) +{ + if (stm->mode == FZ_SREAD) + return fz_rtell(stm); + return fz_wtell(stm); +} + +fz_error * +fz_seek(fz_stream *stm, int offset, int whence) +{ + if (stm->mode == FZ_SREAD) + return fz_rseek(stm, offset, whence); + return fz_wseek(stm, offset, whence); +} + +/* + * Read a line terminated by LF or CR or CRLF. + */ + +fz_error * +fz_readline(fz_stream *stm, char *mem, int n) +{ + fz_error *error; + + char *s = mem; + int c = EOF; + while (n > 1) + { + c = fz_readbyte(stm); + if (c == EOF) + break; + if (c == '\r') { + c = fz_peekbyte(stm); + if (c == '\n') + c = fz_readbyte(stm); + break; + } + if (c == '\n') + break; + *s++ = c; + n--; + } + if (n) + *s = '\0'; + + error = fz_readerror(stm); + if (error) + return fz_rethrow(error, "cannot read line"); + return fz_okay; +} + +/* + * Utility function to consume all the contents of an input stream into + * a freshly allocated buffer. + */ + +fz_error * +fz_readall(fz_buffer **bufp, fz_stream *stm, int sizehint) +{ + fz_error *error; + fz_buffer *buf; + int c; + + if (sizehint == 0) + sizehint = 4 * 1024; + + error = fz_newbuffer(&buf, sizehint); + if (error) + return fz_rethrow(error, "cannot create scratch buffer"); + + for (c = fz_readbyte(stm); c != EOF; c = fz_readbyte(stm)) + { + if (buf->wp == buf->ep) + { + error = fz_growbuffer(buf); + if (error) + { + fz_dropbuffer(buf); + return fz_rethrow(error, "cannot resize scratch buffer"); + } + } + + *buf->wp++ = c; + } + + *bufp = buf; + return fz_okay; +} + diff --git a/fitz/stm_open.c b/fitz/stm_open.c new file mode 100644 index 00000000..14e52642 --- /dev/null +++ b/fitz/stm_open.c @@ -0,0 +1,242 @@ +/* + * Creation and destruction. + */ + +#include "fitz-base.h" +#include "fitz-stream.h" + +static fz_stream * +newstm(int kind, int mode) +{ + fz_stream *stm; + + stm = fz_malloc(sizeof(fz_stream)); + if (!stm) + return nil; + + stm->refs = 1; + stm->kind = kind; + stm->mode = mode; + stm->dead = 0; + stm->error = fz_okay; + stm->buffer = nil; + + stm->chain = nil; + stm->filter = nil; + stm->file = -1; + + return stm; +} + +fz_stream * +fz_keepstream(fz_stream *stm) +{ + stm->refs ++; + return stm; +} + +void +fz_dropstream(fz_stream *stm) +{ + stm->refs --; + if (stm->refs == 0) + { + if (stm->error) + { + fflush(stdout); + fz_printerror(stm->error); + fz_droperror(stm->error); + fflush(stderr); + fz_warn("dropped unhandled ioerror"); + } + + if (stm->mode == FZ_SWRITE) + { + stm->buffer->eof = 1; + fz_flush(stm); + } + + switch (stm->kind) + { + case FZ_SFILE: + close(stm->file); + break; + case FZ_SFILTER: + fz_dropfilter(stm->filter); + fz_dropstream(stm->chain); + break; + case FZ_SBUFFER: + break; + } + + fz_dropbuffer(stm->buffer); + fz_free(stm); + } +} + +static fz_error * +openfile(fz_stream **stmp, char *path, int mode, int realmode) +{ + fz_error *error; + fz_stream *stm; + + stm = newstm(FZ_SFILE, mode); + if (!stm) + return fz_throw("outofmem: stream struct"); + + error = fz_newbuffer(&stm->buffer, FZ_BUFSIZE); + if (error) + { + fz_free(stm); + return fz_rethrow(error, "cannot create buffer"); + } + + stm->file = open(path, realmode, 0666); + if (stm->file < 0) + { + fz_dropbuffer(stm->buffer); + fz_free(stm); + return fz_throw("syserr: open '%s': %s", path, strerror(errno)); + } + + *stmp = stm; + return fz_okay; +} + +static fz_error * +openfilter(fz_stream **stmp, fz_filter *flt, fz_stream *src, int mode) +{ + fz_error *error; + fz_stream *stm; + + stm = newstm(FZ_SFILTER, mode); + if (!stm) + return fz_throw("outofmem: stream struct"); + + error = fz_newbuffer(&stm->buffer, FZ_BUFSIZE); + if (error) + { + fz_free(stm); + return fz_rethrow(error, "cannot create buffer"); + } + + stm->chain = fz_keepstream(src); + stm->filter = fz_keepfilter(flt); + + *stmp = stm; + return fz_okay; +} + +static fz_error * +openbuffer(fz_stream **stmp, fz_buffer *buf, int mode) +{ + fz_stream *stm; + + stm = newstm(FZ_SBUFFER, mode); + if (!stm) + return fz_throw("outofmem: stream struct"); + + stm->buffer = fz_keepbuffer(buf); + + if (mode == FZ_SREAD) + stm->buffer->eof = 1; + + *stmp = stm; + return fz_okay; +} + +fz_error * fz_openrfile(fz_stream **stmp, char *path) +{ + fz_error *error; + error = openfile(stmp, path, FZ_SREAD, O_BINARY | O_RDONLY); + if (error) + return fz_rethrow(error, "cannot open file for reading: '%s'", path); + return fz_okay; +} + +fz_error * fz_openwfile(fz_stream **stmp, char *path) +{ + fz_error *error; + error = openfile(stmp, path, FZ_SWRITE, + O_BINARY | O_WRONLY | O_CREAT | O_TRUNC); + if (error) + return fz_rethrow(error, "cannot open file for writing: '%s'", path); + return fz_okay; +} + +fz_error * fz_openafile(fz_stream **stmp, char *path) +{ + fz_error *error; + int t; + + error = openfile(stmp, path, FZ_SWRITE, O_BINARY | O_WRONLY); + if (error) + return fz_rethrow(error, "cannot open file for writing: '%s'", path); + + t = lseek((*stmp)->file, 0, 2); + if (t < 0) + { + (*stmp)->dead = 1; + return fz_throw("syserr: lseek '%s': %s", path, strerror(errno)); + } + + return fz_okay; +} + +fz_error * fz_openrfilter(fz_stream **stmp, fz_filter *flt, fz_stream *src) +{ + fz_error *error; + error = openfilter(stmp, flt, src, FZ_SREAD); + if (error) + return fz_rethrow(error, "cannot create reading filter stream"); + return fz_okay; +} + +fz_error * fz_openwfilter(fz_stream **stmp, fz_filter *flt, fz_stream *src) +{ + fz_error *error; + error = openfilter(stmp, flt, src, FZ_SWRITE); + if (error) + return fz_rethrow(error, "cannot create writing filter stream"); + return fz_okay; +} + +fz_error * fz_openrbuffer(fz_stream **stmp, fz_buffer *buf) +{ + fz_error *error; + error = openbuffer(stmp, buf, FZ_SREAD); + if (error) + return fz_rethrow(error, "cannot create reading buffer stream"); + return fz_okay; +} + +fz_error * fz_openwbuffer(fz_stream **stmp, fz_buffer *buf) +{ + fz_error *error; + error = openbuffer(stmp, buf, FZ_SWRITE); + if (error) + return fz_rethrow(error, "cannot create writing buffer stream"); + return fz_okay; +} + +fz_error * fz_openrmemory(fz_stream **stmp, unsigned char *mem, int len) +{ + fz_error *error; + fz_buffer *buf; + + error = fz_newbufferwithmemory(&buf, mem, len); + if (error) + return fz_rethrow(error, "cannot create memory buffer"); + + error = fz_openrbuffer(stmp, buf); + if (error) + { + fz_dropbuffer(buf); + return fz_rethrow(error, "cannot open memory buffer stream"); + } + + fz_dropbuffer(buf); + + return fz_okay; +} + diff --git a/fitz/stm_read.c b/fitz/stm_read.c new file mode 100644 index 00000000..e0a6e8a1 --- /dev/null +++ b/fitz/stm_read.c @@ -0,0 +1,313 @@ +/* + * Input streams. + */ + +#include "fitz-base.h" +#include "fitz-stream.h" + +fz_error * +fz_readimp(fz_stream *stm) +{ + fz_buffer *buf = stm->buffer; + fz_error *error; + fz_error *reason; + int produced; + int n; + + if (stm->dead) + return fz_throw("assert: read from dead stream"); + + if (stm->mode != FZ_SREAD) + return fz_throw("assert: read from writing stream"); + + if (buf->eof) + return fz_okay; + + error = fz_rewindbuffer(buf); + if (error) + { + stm->dead = 1; + return fz_rethrow(error, "cannot rewind output buffer"); + } + + if (buf->ep - buf->wp == 0) + { + error = fz_growbuffer(buf); + if (error) + { + stm->dead = 1; + return fz_rethrow(error, "cannot grow output buffer"); + } + } + + switch (stm->kind) + { + + case FZ_SFILE: + n = read(stm->file, buf->wp, buf->ep - buf->wp); + if (n == -1) + { + stm->dead = 1; + return fz_throw("syserr: read: %s", strerror(errno)); + } + + if (n == 0) + buf->eof = 1; + buf->wp += n; + + return fz_okay; + + case FZ_SFILTER: + produced = 0; + + while (1) + { + reason = fz_process(stm->filter, stm->chain->buffer, buf); + + if (stm->filter->produced) + produced = 1; + + if (reason == fz_ioneedin) + { + error = fz_readimp(stm->chain); + if (error) + { + stm->dead = 1; + return fz_rethrow(error, "cannot read from input stream"); + } + } + + else if (reason == fz_ioneedout) + { + if (produced) + return 0; + + if (buf->rp > buf->bp) + { + error = fz_rewindbuffer(buf); + if (error) + { + stm->dead = 1; + return fz_rethrow(error, "cannot rewind buffer"); + } + } + else + { + error = fz_growbuffer(buf); + if (error) + { + stm->dead = 1; + return fz_rethrow(error, "cannot grow buffer"); + } + } + } + + else if (reason == fz_iodone) + { + return fz_okay; + } + + else + { + stm->dead = 1; + return fz_rethrow(reason, "cannot process filter"); + } + } + + case FZ_SBUFFER: + return fz_okay; + + default: + return fz_throw("assert: unknown stream type"); + } +} + +int +fz_rtell(fz_stream *stm) +{ + fz_buffer *buf = stm->buffer; + int t; + + if (stm->dead) + return EOF; + if (stm->mode != FZ_SREAD) + return EOF; + + switch (stm->kind) + { + case FZ_SFILE: + t = lseek(stm->file, 0, 1); + if (t < 0) + { + fz_warn("syserr: lseek: %s", strerror(errno)); + stm->dead = 1; + return EOF; + } + return t - (buf->wp - buf->rp); + + case FZ_SFILTER: + return stm->filter->count - (buf->wp - buf->rp); + + case FZ_SBUFFER: + return buf->rp - buf->bp; + + default: + return EOF; + } +} + +fz_error * +fz_rseek(fz_stream *stm, int offset, int whence) +{ + fz_error *error; + fz_buffer *buf = stm->buffer; + int t, c; + + if (stm->dead) + return fz_throw("assert: seek in dead stream"); + + if (stm->mode != FZ_SREAD) + return fz_throw("assert: read operation on writing stream"); + + if (whence == 1) + { + int cur = fz_rtell(stm); + if (cur < 0) + return fz_throw("cannot tell current position"); + offset = cur + offset; + whence = 0; + } + + buf->eof = 0; + + switch (stm->kind) + { + case FZ_SFILE: + t = lseek(stm->file, offset, whence); + if (t < 0) + { + stm->dead = 1; + return fz_throw("syserr: lseek: %s", strerror(errno)); + } + + buf->rp = buf->bp; + buf->wp = buf->bp; + + return fz_okay; + + case FZ_SFILTER: + if (whence == 0) + { + if (offset < fz_rtell(stm)) + { + stm->dead = 1; + return fz_throw("assert: seek backwards in filter"); + } + while (fz_rtell(stm) < offset) + { + c = fz_readbyte(stm); + if (c == EOF) + { + error = fz_readerror(stm); + if (error) + return fz_rethrow(error, "cannot seek forward in filter"); + break; + } + } + return fz_okay; + } + + stm->dead = 1; + return fz_throw("assert: relative seek in filter"); + + case FZ_SBUFFER: + if (whence == 0) + buf->rp = CLAMP(buf->bp + offset, buf->bp, buf->ep); + else + buf->rp = CLAMP(buf->ep + offset, buf->bp, buf->ep); + return fz_okay; + + default: + return fz_throw("unknown stream type"); + } +} + +fz_error * +fz_read(int *np, fz_stream *stm, unsigned char *mem, int n) +{ + fz_error *error; + fz_buffer *buf = stm->buffer; + int i = 0; + + while (i < n) + { + while (buf->rp < buf->wp && i < n) + mem[i++] = *buf->rp++; + + if (buf->rp == buf->wp) + { + if (buf->eof) + { + *np = i; + return fz_okay; + } + + error = fz_readimp(stm); + if (error) + return fz_rethrow(error, "cannot produce data"); + } + } + + *np = i; + return fz_okay; +} + +fz_error * +fz_readerror(fz_stream *stm) +{ + fz_error *error; + if (stm->error) + { + error = stm->error; + stm->error = fz_okay; + return fz_rethrow(error, "delayed read error"); + } + return fz_okay; +} + +int +fz_readbytex(fz_stream *stm) +{ + fz_buffer *buf = stm->buffer; + + if (buf->rp == buf->wp) + { + if (!buf->eof && !stm->error) + { + fz_error *error = fz_readimp(stm); + if (error) + stm->error = fz_rethrow(error, "cannot read data"); + } + } + + return buf->rp < buf->wp ? *buf->rp++ : EOF ; +} + +int +fz_peekbytex(fz_stream *stm) +{ + fz_buffer *buf = stm->buffer; + + if (buf->rp == buf->wp) + { + if (!buf->eof && !stm->error) + { + fz_error *error = fz_readimp(stm); + if (error) + stm->error = fz_rethrow(error, "cannot read data"); + } + } + + return buf->rp < buf->wp ? *buf->rp : EOF ; +} + diff --git a/fitz/stm_write.c b/fitz/stm_write.c new file mode 100644 index 00000000..ed928b50 --- /dev/null +++ b/fitz/stm_write.c @@ -0,0 +1,313 @@ +/* + * Output streams. + */ + +#include "fitz-base.h" +#include "fitz-stream.h" + +int +fz_wtell(fz_stream *stm) +{ + fz_buffer *buf = stm->buffer; + int t; + + if (stm->dead) + return EOF; + + if (stm->mode != FZ_SWRITE) + return EOF; + + switch (stm->kind) + { + case FZ_SFILE: + t = lseek(stm->file, 0, 1); + if (t < 0) + { + fz_warn("syserr: lseek: %s", strerror(errno)); + stm->dead = 1; + return EOF; + } + return t + (buf->wp - buf->rp); + + case FZ_SFILTER: + return stm->filter->count + (buf->wp - buf->rp); + + case FZ_SBUFFER: + return buf->wp - buf->bp; + + default: + return EOF; + } +} + +fz_error * +fz_wseek(fz_stream *stm, int offset, int whence) +{ + fz_buffer *buf = stm->buffer; + int t; + + if (stm->dead) + return fz_throw("assert: seek in dead stream"); + + if (stm->mode != FZ_SWRITE) + return fz_throw("assert: write operation on reading stream"); + + if (stm->kind != FZ_SFILE) + return fz_throw("assert: write seek on non-file stream"); + + t = lseek(stm->file, offset, whence); + if (t < 0) + { + stm->dead = 1; + return fz_throw("syserr: lseek: %s", strerror(errno)); + } + + buf->rp = buf->bp; + buf->wp = buf->bp; + buf->eof = 0; + + return fz_okay; +} + +static fz_error * +fz_flushfilterimp(fz_stream *stm) +{ + fz_buffer *buf = stm->buffer; + fz_error *error; + fz_error *reason; + +loop: + + reason = fz_process(stm->filter, stm->buffer, stm->chain->buffer); + + if (reason == fz_ioneedin) + { + if (buf->rp > buf->bp) + { + error = fz_rewindbuffer(buf); + if (error) + { + stm->dead = 1; + return fz_rethrow(error, "cannot rewind buffer"); + } + } + else + { + error = fz_growbuffer(buf); + if (error) + { + stm->dead = 1; + return fz_rethrow(error, "cannot grow buffer"); + } + } + } + + else if (reason == fz_ioneedout) + { + error = fz_flush(stm->chain); + if (error) + return fz_rethrow(error, "cannot flush chain buffer"); + } + + else if (reason == fz_iodone) + { + stm->dead = 2; /* special flag that we are dead because of eod */ + } + + else + { + stm->dead = 1; + return fz_rethrow(reason, "cannot process filter"); + } + + /* if we are at eof, repeat until other filter sets otherside to eof */ + if (buf->eof && !stm->chain->buffer->eof) + goto loop; + + return fz_okay; +} + +/* + * Empty the buffer into the sink. + * Promise to make more space available. + * Called by fz_write and fz_dropstream. + * If buffer is eof, then all data must be flushed. + */ +fz_error * +fz_flush(fz_stream *stm) +{ + fz_buffer *buf = stm->buffer; + fz_error *error; + int t; + + if (stm->dead == 2) /* eod flag */ + return fz_okay; + + if (stm->dead) + return fz_throw("assert: flush on dead stream"); + + if (stm->mode != FZ_SWRITE) + return fz_throw("assert: write operation on reading stream"); + + switch (stm->kind) + { + case FZ_SFILE: + while (buf->rp < buf->wp) + { + t = write(stm->file, buf->rp, buf->wp - buf->rp); + if (t < 0) + { + stm->dead = 1; + return fz_throw("syserr: write: %s", strerror(errno)); + } + + buf->rp += t; + } + + if (buf->rp > buf->bp) + { + error = fz_rewindbuffer(buf); + if (error) + { + stm->dead = 1; + return fz_rethrow(error, "cannot rewind buffer"); + } + } + + return fz_okay; + + case FZ_SFILTER: + error = fz_flushfilterimp(stm); + if (error) + return fz_rethrow(error, "cannot flush through filter"); + return fz_okay; + + case FZ_SBUFFER: + if (!buf->eof && buf->wp == buf->ep) + { + error = fz_growbuffer(buf); + if (error) + { + stm->dead = 1; + return fz_rethrow(error, "cannot grow buffer"); + } + } + return fz_okay; + + default: + return fz_throw("unknown stream type"); + } +} + +/* + * Write data to stream. + * Buffer until internal buffer is full. + * When full, call fz_flush to make more space available. + * Return error if all the data could not be written. + */ +fz_error * +fz_write(fz_stream *stm, unsigned char *mem, int n) +{ + fz_buffer *buf = stm->buffer; + fz_error *error; + int i = 0; + + if (stm->dead) + return fz_throw("assert: write on dead stream"); + + if (stm->mode != FZ_SWRITE) + return fz_throw("assert: write on reading stream"); + + while (i < n) + { + while (buf->wp < buf->ep && i < n) + *buf->wp++ = mem[i++]; + + if (buf->wp == buf->ep && i < n) + { + error = fz_flush(stm); + if (error) + return fz_rethrow(error, "cannot flush buffer"); + if (stm->dead) + return fz_throw("assert: write on dead stream"); + } + } + + return fz_okay; +} + +fz_error * +fz_printstr(fz_stream *stm, char *s) +{ + return fz_write(stm, (unsigned char *) s, strlen(s)); +} + +fz_error * +fz_printobj(fz_stream *file, fz_obj *obj, int tight) +{ + fz_error *error; + unsigned char buf[1024]; + char *ptr; + int n; + + n = fz_sprintobj(nil, 0, obj, tight); + if (n < sizeof buf) + { + fz_sprintobj(buf, sizeof buf, obj, tight); + error = fz_write(file, (unsigned char *) buf, n); + if (error) + return fz_rethrow(error, "cannot write buffer"); + return fz_okay; + } + else + { + ptr = fz_malloc(n); + if (!ptr) + return fz_throw("outofmem: scratch buffer"); + fz_sprintobj(ptr, n, obj, tight); + error = fz_write(file, (unsigned char *) ptr, n); + fz_free(ptr); + if (error) + return fz_rethrow(error, "cannot write buffer"); + return fz_okay; + } +} + +fz_error * +fz_print(fz_stream *stm, char *fmt, ...) +{ + fz_error *error; + va_list ap; + char buf[1024]; + char *p; + int n; + + va_start(ap, fmt); + n = vsnprintf(buf, sizeof buf, fmt, ap); + va_end(ap); + + if (n < sizeof buf) + { + error = fz_write(stm, (unsigned char *) buf, n); + if (error) + return fz_rethrow(error, "cannot write buffer"); + return fz_okay; + } + + p = fz_malloc(n); + if (!p) + return fz_throw("outofmem: scratch buffer"); + + va_start(ap, fmt); + vsnprintf(p, n, fmt, ap); + va_end(ap); + + error = fz_write(stm, (unsigned char *) p, n); + + fz_free(p); + + if (error) + return fz_rethrow(error, "cannot write buffer"); + return fz_okay; +} + diff --git a/fitz/util_getopt.c b/fitz/util_getopt.c new file mode 100644 index 00000000..8025334e --- /dev/null +++ b/fitz/util_getopt.c @@ -0,0 +1,117 @@ +/* + * Copyright (c) 1987 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)getopt.c 4.13 (Berkeley) 2/23/91"; +#endif /* LIBC_SCCS and not lint */ + +#include +#include +#include + +/* + * get option letter from argument vector + */ +int opterr = 1, /* if error message should be printed */ + optind = 1, /* index into parent argv vector */ + optopt; /* character checked for validity */ +char *optarg; /* argument associated with option */ + +#define BADCH (int)'?' +#define EMSG "" + +int getopt(int nargc, char * const * nargv, const char *ostr) +{ + static char *place = EMSG; /* option letter processing */ + register char *oli; /* option letter list index */ + char *p; + + if (!*place) { /* update scanning pointer */ + if (optind >= nargc || *(place = nargv[optind]) != '-') { + place = EMSG; + return(EOF); + } + if (place[1] && *++place == '-') { /* found "--" */ + ++optind; + place = EMSG; + return(EOF); + } + } /* option letter okay? */ + if ((optopt = (int)*place++) == (int)':' || + !(oli = strchr(ostr, optopt))) { + /* + * if the user didn't specify '-' as an option, + * assume it means EOF. + */ + if (optopt == (int)'-') + return(EOF); + if (!*place) + ++optind; + if (opterr) { + if (!(p = strrchr(*nargv, '/'))) + p = *nargv; + else + ++p; + (void)fprintf(stderr, "%s: illegal option -- %c\n", + p, optopt); + } + return(BADCH); + } + if (*++oli != ':') { /* don't need argument */ + optarg = NULL; + if (!*place) + ++optind; + } + else { /* need an argument */ + if (*place) /* no white space */ + optarg = place; + else if (nargc <= ++optind) { /* no arg */ + place = EMSG; + if (!(p = strrchr(*nargv, '/'))) + p = *nargv; + else + ++p; + if (opterr) + (void)fprintf(stderr, + "%s: option requires an argument -- %c\n", + p, optopt); + return(BADCH); + } + else /* white space */ + optarg = nargv[optind]; + place = EMSG; + ++optind; + } + return(optopt); /* dump back option letter */ +} + diff --git a/fitz/util_gettimeofday.c b/fitz/util_gettimeofday.c new file mode 100644 index 00000000..fee36673 --- /dev/null +++ b/fitz/util_gettimeofday.c @@ -0,0 +1,50 @@ +#include +#include +#include + +#if defined(_MSC_VER) || defined(_MSC_EXTENSIONS) + #define DELTA_EPOCH_IN_MICROSECS 11644473600000000Ui64 +#else + #define DELTA_EPOCH_IN_MICROSECS 11644473600000000ULL +#endif + +struct timezone +{ + int tz_minuteswest; /* minutes W of Greenwich */ + int tz_dsttime; /* type of dst correction */ +}; + +int gettimeofday(struct timeval *tv, struct timezone *tz) +{ + FILETIME ft; + unsigned __int64 tmpres = 0; + static int tzflag = 0; + + if (NULL != 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); + } + + if (NULL != tz) + { + if (!tzflag) + { + _tzset(); + tzflag++; + } + tz->tz_minuteswest = _timezone / 60; + tz->tz_dsttime = _daylight; + } + + return 0; +} diff --git a/fitz/util_strlcpy.c b/fitz/util_strlcpy.c new file mode 100644 index 00000000..15b378b2 --- /dev/null +++ b/fitz/util_strlcpy.c @@ -0,0 +1,65 @@ +#include + +/* Copy src to string dst of size siz. At most siz-1 characters + * will be copied. Always NUL terminates (unless siz == 0). + * Returns strlen(src); if retval >= siz, truncation occurred. + */ + +int 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 */ +} + +/* Appends src to string dst of size siz (unlike strncat, siz is the + * full size of dst, not space left). At most siz-1 characters + * will be copied. Always NUL terminates (unless siz == 0). + * Returns strlen(src); if retval >= siz, truncation occurred. + */ + +int 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 */ +} + diff --git a/fitz/util_strsep.c b/fitz/util_strsep.c new file mode 100644 index 00000000..e54903ce --- /dev/null +++ b/fitz/util_strsep.c @@ -0,0 +1,11 @@ +#include + +char *strsep(char **stringp, const char *delim) +{ + char *ret = *stringp; + if (ret == NULL) return NULL; + if ((*stringp = strpbrk(*stringp, delim)) != NULL) + *((*stringp)++) = '\0'; + return ret; +} + diff --git a/fitzdraw/Jamfile b/fitzdraw/Jamfile new file mode 100644 index 00000000..c76d9c6d --- /dev/null +++ b/fitzdraw/Jamfile @@ -0,0 +1,21 @@ +SubDir TOP fitzdraw ; + +Library libfitzdraw : + glyphcache.c + pixmap.c + porterduff.c + meshdraw.c + imagedraw.c + imageunpack.c + imagescale.c + pathscan.c + pathfill.c + pathstroke.c + render.c + blendmodes.c + ; + +if $(OSPLAT) = PPC { Library libfitzdraw : archppc.c ; } +if $(OSPLAT) = SPARC { Library libfitzdraw : archsparc.c ; } +if $(OSPLAT) = X86 { Library libfitzdraw : archx86.c ; } + diff --git a/fitzdraw/archppc.c b/fitzdraw/archppc.c new file mode 100644 index 00000000..30dbd780 --- /dev/null +++ b/fitzdraw/archppc.c @@ -0,0 +1,67 @@ +/* + * PowerPC specific render optims live here + */ + +#include "fitz-base.h" +#include "fitz-world.h" +#include "fitz-draw.h" + +typedef unsigned char byte; + +#ifdef HAVE_ALTIVEC + +static void srow1ppc(byte *src, byte *dst, int w, int denom) +{ + int x, left; + int sum; + + left = 0; + sum = 0; + + for (x = 0; x < w; x++) + { + sum += *src++; + if (++left == denom) + { + left = 0; + *dst++ = sum / denom; + sum = 0; + } + } + + if (left) + *dst++ = sum / left; +} + +static void scol1ppc(byte *src, byte *dst, int w, int denom) +{ + int x, y; + unsigned char *s; + int sum; + + for (x = 0; x < w; x++) + { + s = src + x; + sum = 0; + for (y = 0; y < denom; y++) + sum += s[y * w]; + *dst++ = sum / denom; + } +} + +#endif /* HAVE_ALTIVEC */ + +#if defined (ARCH_PPC) +void +fz_accelerate(void) +{ +# ifdef HAVE_ALTIVEC + if (fz_cpuflags & HAVE_ALTIVEC) + { + fz_srow1 = srow1ppc; + fz_scol1 = scol1ppc; + } +# endif +} +#endif + diff --git a/fitzdraw/archsparc.c b/fitzdraw/archsparc.c new file mode 100644 index 00000000..b78e5a4d --- /dev/null +++ b/fitzdraw/archsparc.c @@ -0,0 +1,23 @@ +/* +SPARC specific render optims live here +*/ +#include "fitz-base.h" +#include "fitz-world.h" +#include "fitz-draw.h" + +#ifdef HAVE_VIS + +#endif + +#if defined (ARCH_SPARC) +void +fz_accelerate(void) +{ +# ifdef HAVE_VIS + if (fz_cpuflags & HAVE_VIS) + { + } +# endif +} +#endif + diff --git a/fitzdraw/archx86.c b/fitzdraw/archx86.c new file mode 100644 index 00000000..261b8a16 --- /dev/null +++ b/fitzdraw/archx86.c @@ -0,0 +1,232 @@ +/* + * x86 specific render optims live here + */ + +#include "fitz-base.h" +#include "fitz-world.h" +#include "fitz-draw.h" + +typedef unsigned char byte; + +/* always surround cpu specific code with HAVE_XXX */ +#ifdef HAVE_MMX + +/* -mmmx for gcc >= 3.4 enables the mmx intrinsic functions, icc and VC + shouldn't require anything */ +#include + +static void duff_4i1o4mmx(byte *sp0, int sw, byte *mp0, int mw, byte *dp0, int dw, int w0, int h) +{ + /* + rendering all pages of + x11pdf ~/doc/OpenGL/Presentations/CEDEC2003_Venus_and_Vulcan.pdf + % cumulative self self total + time seconds seconds calls ms/call ms/call name + 30.50 20.04 20.04 261 76.76 76.76 duff_4i1o4 + 21.67 22.02 10.95 221 49.55 49.55 duff_4i1o4mmx + */ + __m64 mzero = _mm_setzero_si64(); + while (h--) + { + byte *sp = sp0; + byte *mp = mp0; + byte *dp = dp0; + + unsigned *s = (unsigned *)sp; + unsigned *d = (unsigned *)dp; + + int w = w0; + + /* TODO: unroll and process two pixels/iteration */ + while (w--) + { + int ts = *s++; + int ma = *mp++ + 1; + int sa = ((ts & 0xff) * ma) >> 8; + int ssa = 256 - sa; + + __m64 d0 = _mm_cvtsi32_si64(*d); + __m64 s0 = _mm_cvtsi32_si64(ts); + + /* 4 x 9 bit alpha value */ + __m64 mma = _mm_set1_pi16(ma); + __m64 mssa = _mm_set1_pi16(ssa); + + /* unpack 0000argb => a0r0g0b0 */ + __m64 d1 = _mm_unpacklo_pi8(d0, mzero); + __m64 s1 = _mm_unpacklo_pi8(s0, mzero); + + /* s1 * ma => a0r0g0b0 */ + __m64 msma = _mm_mullo_pi16(s1, mma); + /* d1 * mssa */ + __m64 mdssa = _mm_mullo_pi16(d1, mssa); + + __m64 res0 = _mm_add_pi16(msma, mdssa); + /* TODO: is it possible to get rid of the shift? */ + __m64 res1 = _mm_srli_pi16(res0, 8); + + /* pack */ + __m64 res2 = _mm_packs_pu16(res1, mzero); + + *d++ = _mm_cvtsi64_si32(res2); + } + + sp0 += sw; + mp0 += mw; + dp0 += dw; + } + + _mm_empty(); +} + +static inline unsigned +getargb(unsigned *s, int w, int h, int u, int v) +{ + if ((u < 0) | (u >= w) | (v < 0) | (v >= h)) return 0; + return s[w * v + u]; +} + +static void img_4o4mmx(FZ_PSRC, FZ_PDST, FZ_PCTM) +{ + /* since mmx does not have an unsigned multiply instruction we use + 17.15 fixed point */ + u0 >>= 1; v0 >>= 1; + fa >>= 1; fb >>= 1; + fc >>= 1; fd >>= 1; + + while (h--) + { + unsigned *s = (unsigned *)src; + unsigned *d = (unsigned *)dst0; + int u = u0; + int v = v0; + int w = w0; + + __m64 mzero = _mm_setzero_si64(); + __m64 m256 = _mm_set1_pi16(256); + __m64 malphamask = _mm_cvtsi32_si64(0xff); + + while (w--) + { + int iu = u >> 15; + int iv = v >> 15; + + int fu = u & 0x7fff; + int fv = v & 0x7fff; + + int atedge = + (iu < 0) | (iu >= (srcw - 1)) | + (iv < 0) | (iv >= (srch - 1)); + + __m64 ms0s1; + __m64 ms2s3; + + if (atedge) + { + unsigned s0, s1, s2, s3; + + /* edge cases use scalar loads */ + s0 = getargb(s, srcw, srch, iu + 0, iv + 0); + s1 = getargb(s, srcw, srch, iu + 1, iv + 0); + s2 = getargb(s, srcw, srch, iu + 0, iv + 1); + s3 = getargb(s, srcw, srch, iu + 1, iv + 1); + + /* move to mmx registers */ + ms0s1 = _mm_set_pi32(s1, s0); + ms2s3 = _mm_set_pi32(s3, s2); + } + else + { + __m64 *m0s = (__m64*)(s + srcw * (iv + 0) + iu); + __m64 *m2s = (__m64*)(s + srcw * (iv + 1) + iu); + + /* faster vector loads for interior */ + ms0s1 = *m0s; + ms2s3 = *m2s; + } + + /* unpack src into 4x16bit vectors */ + __m64 ms0 = _mm_unpacklo_pi8(ms0s1, mzero); + __m64 ms1 = _mm_unpackhi_pi8(ms0s1, mzero); + __m64 ms2 = _mm_unpacklo_pi8(ms2s3, mzero); + __m64 ms3 = _mm_unpackhi_pi8(ms2s3, mzero); + + /* lerp fu */ + + __m64 mfu = _mm_set1_pi16(fu); + + /* t2 = (s1 - s0) * fu + s0 */ + __m64 t0 = _mm_sub_pi16(ms1, ms0); + __m64 t1 = _mm_mulhi_pi16(t0, mfu); + t1 = _mm_adds_pi16(t1, t1); + __m64 t2 = _mm_add_pi16(t1, ms0); + + /* t3 = (s3 - s2) * fu + s2 */ + __m64 t3 = _mm_sub_pi16(ms3, ms2); + __m64 t4 = _mm_mulhi_pi16(t3, mfu); + t4 = _mm_adds_pi16(t4, t4); + __m64 t5 = _mm_add_pi16(t4, ms2); + + /* lerp fv */ + + __m64 mfv = _mm_set1_pi16(fv); + + /* t8 = (t5 - t2) * fv + t2 */ + __m64 t6 = _mm_sub_pi16(t5, t2); + __m64 t7 = _mm_mulhi_pi16(t6, mfv); + t7 = _mm_adds_pi16(t7, t7); + __m64 t8 = _mm_add_pi16(t7, t2); + + /* load and prepare dst */ + __m64 d0 = _mm_cvtsi32_si64(*d); + + __m64 d1 = _mm_unpacklo_pi8(d0, mzero); + + /* get src alpha */ + + /* splat alpha */ + __m64 a0001 = _mm_and_si64(malphamask, t8); + __m64 a0011 = _mm_unpacklo_pi16(a0001, a0001); + __m64 a1111 = _mm_unpacklo_pi16(a0011, a0011); + + /* 255+1 - sa */ + __m64 sna = _mm_sub_pi16(m256, a1111); + + /* blend src with dst */ + __m64 d2 = _mm_mullo_pi16(d1, sna); + __m64 d3 = _mm_srli_pi16(d2, 8); + __m64 d4 = _mm_add_pi16(t8, d3); + + /* pack and store new dst */ + __m64 d5 = _mm_packs_pu16(d4, mzero); + + *d++ = _mm_cvtsi64_si32(d5); + + u += fa; + v += fb; + } + + dst0 += dstw; + u0 += fc; + v0 += fd; + } + + _mm_empty(); +} + +#endif /* HAVE_MMX */ + +#if defined (ARCH_X86) || defined(ARCH_X86_64) +void +fz_accelerate(void) +{ +# ifdef HAVE_MMX + if (fz_cpuflags & HAVE_MMX) + { + fz_duff_4i1o4 = duff_4i1o4mmx; + fz_img_4o4 = img_4o4mmx; + } +# endif +} +#endif + diff --git a/fitzdraw/blendmodes.c b/fitzdraw/blendmodes.c new file mode 100644 index 00000000..f3ba8ac5 --- /dev/null +++ b/fitzdraw/blendmodes.c @@ -0,0 +1,213 @@ +#include "fitz-base.h" +#include "fitz-world.h" +#include "fitz-draw.h" + +typedef unsigned char byte; + +/* +PDF 1.4 blend modes, except Normal and Multiply which are Over and In respectively. +Only the actual blend routines are here, not the node rendering logic which lives in render.c. +These are slow. +*/ + + +/* These functions apply to a single component, 0-255 range typically */ + +static int +fz_screen_byte(int bd, int s) +{ + return bd + s - fz_mul255(bd, s); +} + + +static int +fz_hardlight_byte(int bd, int s) +{ + int s2 = s << 1; + if (s <= 127) + return fz_mul255(bd, s2); + else + return fz_screen_byte(bd, s2); +} + + +static int +fz_overlay_byte(int bd, int s) +{ + return fz_hardlight_byte(s, bd); // note swapped order +} + + +static int +fz_darken_byte(int bd, int s) +{ + return MIN(bd, s); +} + + +static int +fz_lighten_byte(int bd, int s) +{ + return MAX(bd, s); +} + + +static int +fz_colordodge_byte(int bd, int s) +{ + if (s < 255) + return MIN(255, 255 * bd / (255 - s)); + else + return 255; +} + + +static int +fz_colorburn_byte(int bd, int s) +{ + if (s > 0) + return 255 - MIN(255, 255 * (255 - bd) / s); + else + return 0; +} + + +static int +fz_softlight_byte(int bd, int s) +{ + /* review this */ + if (s < 128) { + return bd - fz_mul255(fz_mul255((255 - (s<<1)), bd), 255 - bd); + } + else { + int dbd; + if (bd < 64) + dbd = fz_mul255(fz_mul255((bd << 4) - 12, bd) + 4, bd); + else + dbd = (int)sqrtf(255.0f * bd); + return bd + fz_mul255(((s<<1) - 255), (dbd - bd)); + } +} + + +static int +fz_difference_byte(int bd, int s) +{ + return ABS(bd - s); +} + + +static int +fz_exclusion_byte(int bd, int s) +{ + return bd + s - (fz_mul255(bd, s)<<1); +} + + +/* Non-separable blend modes */ + + +static int +lum(int r, int g, int b) +{ + /* 0.3, 0.59, 0.11 in 16.16 fixed point */ + return (19662 * r + 38666 * g + 7208 * b) >> 16; +} + + +static void +clipcolor(int r, int g, int b, int *dr, int *dg, int *db) +{ + int l = lum(r, g, b); + int n = MIN(MIN(r, g), b); + int x = MAX(MAX(r, g), b); + if (n < 0) { + *dr = l + 255 * (r - l) / (l - n); + *dg = l + 255 * (g - l) / (l - n); + *db = l + 255 * (b - l) / (l - n); + } + else { + *dr = l + 255 * (255 - l) / (x - l); + *dg = l + 255 * (255 - l) / (x - l); + *db = l + 255 * (255 - l) / (x - l); + } +} + + +static void +setlum(int r, int g, int b, int l, int *dr, int *dg, int *db) +{ + int d = 255 - lum(r, g, b); + clipcolor(r + d, g + d, b + d, dr, dg, db); +} + + +static int +sat(int r, int g, int b) +{ + return MAX(MAX(r, g), b) - MIN(MIN(r, g), b); +} + + +static void +setsat(int r, int g, int b, int s, int *dr, int *dg, int *db) +{ + int *m[3] = { &r, &g, &b }; /* min, med, max */ + int *t; +#define SWAP(a, b) (t = a, a = b, b = t) + if (*m[0] > *m[1]) + SWAP(m[0], m[1]); + if (*m[0] > *m[2]) + SWAP(m[0], m[2]); + if (*m[1] > *m[2]) + SWAP(m[1], m[2]); + + if (*m[2] > *m[0]) { + *m[1] = (*m[1] - *m[0]) * s / (*m[2] - *m[0]); + *m[2] = s; + } + else { + *m[1] = 0; + *m[2] = 0; + } + *dr = r; + *dg = g; + *db = b; +} + + +static void +fz_hue_rgb(int *bdr, int *bdg, int *bdb, int sr, int sg, int sb) +{ + int tr, tg, tb; + setsat(sr, sg, sb, sat(*bdr, *bdg, *bdb), &tr, &tg, &tb); + setlum(tr, tg, tb, lum(*bdr, *bdg, *bdb), bdr, bdg, bdb); +} + + +static void +fz_saturation_rgb(int *bdr, int *bdg, int *bdb, int sr, int sg, int sb) +{ + int tr, tg, tb; + setsat(*bdr, *bdg, *bdb, sat(sr, sg, sb), &tr, &tg, &tb); + setlum(tr, tg, tb, lum(*bdr, *bdg, *bdb), bdr, bdg, bdb); +} + + +static void +fz_color_rgb(int *bdr, int *bdg, int *bdb, int sr, int sg, int sb) +{ + setlum(sr, sg, sb, lum(*bdr, *bdg, *bdb), bdr, bdg, bdb); +} + + +static void +fz_luminosity_rgb(int *bdr, int *bdg, int *bdb, int sr, int sg, int sb) +{ + setlum(*bdr, *bdg, *bdb, lum(sr, sg, sb), bdr, bdg, bdb); +} + + +//fz_separable_blend(, fz_blendkind mode) +//{ +//} diff --git a/fitzdraw/glyphcache.c b/fitzdraw/glyphcache.c new file mode 100644 index 00000000..fe03524e --- /dev/null +++ b/fitzdraw/glyphcache.c @@ -0,0 +1,406 @@ +#include "fitz-base.h" +#include "fitz-world.h" +#include "fitz-draw.h" + +typedef struct fz_hash_s fz_hash; +typedef struct fz_key_s fz_key; +typedef struct fz_val_s fz_val; + +struct fz_glyphcache_s +{ + int slots; + int size; + fz_hash *hash; + fz_val *lru; + unsigned char *buffer; + int load; + int used; +}; + +struct fz_key_s +{ + void *fid; + int a, b; + int c, d; + unsigned short cid; + unsigned char e, f; +}; + +struct fz_hash_s +{ + fz_key key; + fz_val *val; +}; + +struct fz_val_s +{ + fz_hash *ent; + unsigned char *samples; + short w, h, x, y; + int uses; +}; + +static unsigned int hashkey(fz_key *key) +{ + unsigned char *s = (unsigned char*)key; + unsigned int hash = 0; + unsigned int i; + for (i = 0; i < sizeof(fz_key); i++) + { + hash += s[i]; + hash += (hash << 10); + hash ^= (hash >> 6); + } + hash += (hash << 3); + hash ^= (hash >> 11); + hash += (hash << 15); + return hash; +} + +fz_error * +fz_newglyphcache(fz_glyphcache **arenap, int slots, int size) +{ + fz_glyphcache *arena; + + arena = *arenap = fz_malloc(sizeof(fz_glyphcache)); + if (!arena) + return fz_outofmem; + + arena->slots = slots; + arena->size = size; + + arena->hash = nil; + arena->lru = nil; + arena->buffer = nil; + + arena->hash = fz_malloc(sizeof(fz_hash) * slots); + if (!arena->hash) + goto cleanup; + + arena->lru = fz_malloc(sizeof(fz_val) * slots); + if (!arena->lru) + goto cleanup; + + arena->buffer = fz_malloc(size); + if (!arena->buffer) + goto cleanup; + + memset(arena->hash, 0, sizeof(fz_hash) * slots); + memset(arena->lru, 0, sizeof(fz_val) * slots); + memset(arena->buffer, 0, size); + arena->load = 0; + arena->used = 0; + + return fz_okay; + +cleanup: + fz_free(arena->hash); + fz_free(arena->lru); + fz_free(arena->buffer); + fz_free(arena); + return fz_outofmem; +} + +void +fz_dropglyphcache(fz_glyphcache *arena) +{ + fz_free(arena->hash); + fz_free(arena->lru); + fz_free(arena->buffer); + fz_free(arena); +} + +static int hokay = 0; +static int hcoll = 0; +static int hdist = 0; +static int coos = 0; +static int covf = 0; + +static int ghits = 0; +static int gmisses = 0; + +static fz_val * +hashfind(fz_glyphcache *arena, fz_key *key) +{ + fz_hash *tab = arena->hash; + int pos = hashkey(key) % arena->slots; + + while (1) + { + if (!tab[pos].val) + return nil; + + if (memcmp(key, &tab[pos].key, sizeof (fz_key)) == 0) + return tab[pos].val; + + pos = pos + 1; + if (pos == arena->slots) + pos = 0; + } +} + +static void +hashinsert(fz_glyphcache *arena, fz_key *key, fz_val *val) +{ + fz_hash *tab = arena->hash; + int pos = hashkey(key) % arena->slots; +int didcoll = 0; + + while (1) + { + if (!tab[pos].val) + { + tab[pos].key = *key; + tab[pos].val = val; + tab[pos].val->ent = &tab[pos]; +if (didcoll) hcoll ++; else hokay ++; hdist += didcoll; + return; + } + + pos = pos + 1; + if (pos == arena->slots) + pos = 0; +didcoll ++; + } +} + +/* +static void +hashremove(fz_glyphcache *arena, fz_key *key) +{ + fz_hash *tab = arena->hash; + unsigned int pos = hashkey(key) % arena->slots; + unsigned int hole; + unsigned int look; + unsigned int code; + + while (1) + { + if (!tab[pos].val) + return; // boo hoo! tried to remove non-existant key + + if (memcmp(key, &tab[pos].key, sizeof (fz_key)) == 0) + { + tab[pos].val = nil; + + hole = pos; + look = hole + 1; + if (look == arena->slots) + look = 0; + + while (tab[look].val) + { + code = (hashkey(&tab[look].key) % arena->slots); + if ((code <= hole && hole < look) || + (look < code && code <= hole) || + (hole < look && look < code)) + { + tab[hole] = tab[look]; + tab[hole].val->ent = &tab[hole]; + tab[look].val = nil; + hole = look; + } + + look = look + 1; + if (look == arena->slots) + look = 0; + } + + return; + } + + pos = pos + 1; + if (pos == arena->slots) + pos = 0; + } +} +*/ + +void +fz_debugglyphcache(fz_glyphcache *arena) +{ + printf("cache load %d / %d (%d / %d bytes)\n", + arena->load, arena->slots, arena->used, arena->size); + printf("no-colliders: %d colliders: %d\n", hokay, hcoll); + printf("avg dist: %d / %d: %g\n", hdist, hcoll, (double)hdist / hcoll); + printf("out-of-space evicts: %d\n", coos); + printf("out-of-hash evicts: %d\n", covf); + printf("hits = %d misses = %d ratio = %g\n", ghits, gmisses, (float)ghits / (ghits + gmisses)); +/* + int i; + for (i = 0; i < arena->slots; i++) + { + if (!arena->hash[i].val) + printf("glyph % 4d: empty\n", i); + else { + fz_key *k = &arena->hash[i].key; + fz_val *b = arena->hash[i].val; + printf("glyph % 4d: %p %d [%g %g %g %g + %d %d] " + "-> [%dx%d %d,%d]\n", i, + k->fid, k->cid, + k->a / 65536.0, + k->b / 65536.0, + k->c / 65536.0, + k->d / 65536.0, + k->e, k->f, + b->w, b->h, b->x, b->y); + } + } + + for (i = 0; i < arena->load; i++) + printf("lru %04d: glyph %d (%d)\n", i, + arena->lru[i].ent - arena->hash, arena->lru[i].uses); +*/ +} + +static void +bubble(fz_glyphcache *arena, int i) +{ + fz_val tmp; + + if (i == 0 || arena->load < 2) + return; + + tmp = arena->lru[i - 1]; + arena->lru[i - 1] = arena->lru[i]; + arena->lru[i] = tmp; + + arena->lru[i - 1].ent->val = &arena->lru[i - 1]; + arena->lru[i].ent->val = &arena->lru[i]; +} + +/* +static void +evictlast(fz_glyphcache *arena) +{ + fz_val *lru = arena->lru; + unsigned char *s, *e; + int i, k; + fz_key key; + + if (arena->load == 0) + return; + + k = arena->load - 1; + s = lru[k].samples; + e = s + lru[k].w * lru[k].h; + + // pack buffer to fill hole + memmove(s, e, arena->buffer + arena->used - e); + memset(arena->buffer + arena->used - (e - s), 0, e - s); + arena->used -= e - s; + + // update lru pointers + for (i = 0; i < k; i++) // XXX this is DOG slow! XXX + if (lru[i].samples >= e) + lru[i].samples -= e - s; + + // remove hash entry + key = lru[k].ent->key; + hashremove(arena, &key); + + arena->load --; +} +*/ + +static void +evictall(fz_glyphcache *arena) +{ + memset(arena->hash, 0, sizeof(fz_hash) * arena->slots); + memset(arena->lru, 0, sizeof(fz_val) * arena->slots); + memset(arena->buffer, 0, arena->size); + arena->load = 0; + arena->used = 0; +} + +fz_error * +fz_renderglyph(fz_glyphcache *arena, fz_glyph *glyph, fz_font *font, int cid, fz_matrix ctm) +{ + fz_error *error; + fz_key key; + fz_val *val; + int size; + + key.fid = font; + key.cid = cid; + key.a = ctm.a * 65536; + key.b = ctm.b * 65536; + key.c = ctm.c * 65536; + key.d = ctm.d * 65536; + key.e = (ctm.e - fz_floor(ctm.e)) * 256; + key.f = (ctm.f - fz_floor(ctm.f)) * 256; + + val = hashfind(arena, &key); + if (val) + { + val->uses ++; + glyph->w = val->w; + glyph->h = val->h; + glyph->x = val->x; + glyph->y = val->y; + glyph->samples = val->samples; + + bubble(arena, val - arena->lru); + + ghits++; + + return fz_okay; + } + + gmisses++; + + ctm.e = fz_floor(ctm.e) + key.e / 256.0; + ctm.f = fz_floor(ctm.f) + key.f / 256.0; + + if (font->ftface) + { + error = fz_renderftglyph(glyph, font, cid, ctm); + if (error) + return error; + } + else if (font->t3procs) + { + error = fz_rendert3glyph(glyph, font, cid, ctm); + if (error) + return error; + } + else + { + return fz_throw("uninitialized font structure"); + } + + size = glyph->w * glyph->h; + + if (size > arena->size / 6) + return fz_okay; + + while (arena->load > arena->slots * 75 / 100) + { + covf ++; + evictall(arena); + } + + while (arena->used + size >= arena->size) + { + coos ++; + evictall(arena); + } + + val = &arena->lru[arena->load++]; + val->uses = 0; + val->w = glyph->w; + val->h = glyph->h; + val->x = glyph->x; + val->y = glyph->y; + val->samples = arena->buffer + arena->used; + + arena->used += size; + + memcpy(val->samples, glyph->samples, glyph->w * glyph->h); + glyph->samples = val->samples; + + hashinsert(arena, &key, val); + + return fz_okay; +} + diff --git a/fitzdraw/imagedraw.c b/fitzdraw/imagedraw.c new file mode 100644 index 00000000..1ad74bf7 --- /dev/null +++ b/fitzdraw/imagedraw.c @@ -0,0 +1,242 @@ +#include "fitz-base.h" +#include "fitz-world.h" +#include "fitz-draw.h" + +typedef unsigned char byte; + +#define lerp(a,b,t) (a + (((b - a) * t) >> 16)) + +static inline byte getcomp(byte *s, int w, int h, int u, int v, int n, int k) +{ + if (u < 0 || u >= w) return 0; + if (v < 0 || v >= h) return 0; + return s[(w * v + u) * n + k]; +} + +static inline int samplecomp(byte *s, int w, int h, int u, int v, int n, int k) +{ + int ui = u >> 16; + int vi = v >> 16; + int ud = u & 0xFFFF; + int vd = v & 0xFFFF; + int a = getcomp(s, w, h, ui, vi, n, k); + int b = getcomp(s, w, h, ui+1, vi, n, k); + int c = getcomp(s, w, h, ui, vi+1, n, k); + int d = getcomp(s, w, h, ui+1, vi+1, n, k); + int ab = lerp(a, b, ud); + int cd = lerp(c, d, ud); + return lerp(ab, cd, vd); +} + +static inline byte getmask(byte *s, int w, int h, int u, int v) +{ + if (u < 0 || u >= w) return 0; + if (v < 0 || v >= h) return 0; + return s[w * v + u]; +} + +static inline int samplemask(byte *s, int w, int h, int u, int v) +{ + int ui = u >> 16; + int vi = v >> 16; + int ud = u & 0xFFFF; + int vd = v & 0xFFFF; + int a = getmask(s, w, h, ui, vi); + int b = getmask(s, w, h, ui+1, vi); + int c = getmask(s, w, h, ui, vi+1); + int d = getmask(s, w, h, ui+1, vi+1); + int ab = lerp(a, b, ud); + int cd = lerp(c, d, ud); + return lerp(ab, cd, vd); +} + +static inline void lerpargb(byte *dst, byte *a, byte *b, int t) +{ + dst[0] = lerp(a[0], b[0], t); + dst[1] = lerp(a[1], b[1], t); + dst[2] = lerp(a[2], b[2], t); + dst[3] = lerp(a[3], b[3], t); +} + +static inline byte *getargb(byte *s, int w, int h, int u, int v) +{ + static byte zero[4] = { 0, 0, 0, 0 }; + if (u < 0 || u >= w) return zero; + if (v < 0 || v >= h) return zero; + return s + ((w * v + u) << 2); +} + +static inline void sampleargb(byte *s, int w, int h, int u, int v, byte *abcd) +{ + byte ab[4]; + byte cd[4]; + int ui = u >> 16; + int vi = v >> 16; + int ud = u & 0xFFFF; + int vd = v & 0xFFFF; + byte *a = getargb(s, w, h, ui, vi); + byte *b = getargb(s, w, h, ui+1, vi); + byte *c = getargb(s, w, h, ui, vi+1); + byte *d = getargb(s, w, h, ui+1, vi+1); + lerpargb(ab, a, b, ud); + lerpargb(cd, c, d, ud); + lerpargb(abcd, ab, cd, vd); +} + +static void img_ncn(FZ_PSRC, int srcn, FZ_PDST, FZ_PCTM) +{ + int k; + while (h--) + { + byte *dstp = dst0; + int u = u0; + int v = v0; + int w = w0; + while (w--) + { + for (k = 0; k < srcn; k++) + { + dstp[k] = samplecomp(src, srcw, srch, u, v, srcn, k); + dstp += srcn; + u += fa; + v += fb; + } + } + dst0 += dstw; + u0 += fc; + v0 += fd; + } +} + +static void img_1c1(FZ_PSRC, FZ_PDST, FZ_PCTM) +{ + while (h--) + { + byte *dstp = dst0; + int u = u0; + int v = v0; + int w = w0; + while (w--) + { + dstp[0] = samplemask(src, srcw, srch, u, v); + dstp ++; + u += fa; + v += fb; + } + dst0 += dstw; + u0 += fc; + v0 += fd; + } +} + +static void img_4c4(FZ_PSRC, FZ_PDST, FZ_PCTM) +{ + while (h--) + { + byte *dstp = dst0; + int u = u0; + int v = v0; + int w = w0; + while (w--) + { + sampleargb(src, srcw, srch, u, v, dstp); + dstp += 4; + u += fa; + v += fb; + } + dst0 += dstw; + u0 += fc; + v0 += fd; + } +} + +static void img_1o1(FZ_PSRC, FZ_PDST, FZ_PCTM) +{ + byte srca; + while (h--) + { + byte *dstp = dst0; + int u = u0; + int v = v0; + int w = w0; + while (w--) + { + srca = samplemask(src, srcw, srch, u, v); + dstp[0] = srca + fz_mul255(dstp[0], 255 - srca); + dstp ++; + u += fa; + v += fb; + } + dst0 += dstw; + u0 += fc; + v0 += fd; + } +} + +static void img_4o4(FZ_PSRC, FZ_PDST, FZ_PCTM) +{ + byte argb[4]; + byte ssa; + while (h--) + { + byte *dstp = dst0; + int u = u0; + int v = v0; + int w = w0; + while (w--) + { + sampleargb(src, srcw, srch, u, v, argb); + ssa = 255 - argb[0]; + dstp[0] = argb[0] + fz_mul255(dstp[0], ssa); + dstp[1] = argb[1] + fz_mul255(dstp[1], ssa); + dstp[2] = argb[2] + fz_mul255(dstp[2], ssa); + dstp[3] = argb[3] + fz_mul255(dstp[3], ssa); + dstp += 4; + u += fa; + v += fb; + } + dst0 += dstw; + u0 += fc; + v0 += fd; + } +} + +static void img_w4i1o4(byte *argb, FZ_PSRC, FZ_PDST, FZ_PCTM) +{ + byte alpha = argb[0]; + byte r = argb[4]; + byte g = argb[5]; + byte b = argb[6]; + byte cov; + byte ca; + while (h--) + { + byte *dstp = dst0; + int u = u0; + int v = v0; + int w = w0; + while (w--) + { + cov = samplemask(src, srcw, srch, u, v); + ca = fz_mul255(cov, alpha); + dstp[0] = ca + fz_mul255(dstp[0], 255 - ca); + dstp[1] = fz_mul255((short)r - dstp[1], ca) + dstp[1]; + dstp[2] = fz_mul255((short)g - dstp[2], ca) + dstp[2]; + dstp[3] = fz_mul255((short)b - dstp[3], ca) + dstp[3]; + dstp += 4; + u += fa; + v += fb; + } + dst0 += dstw; + u0 += fc; + v0 += fd; + } +} + +void (*fz_img_ncn)(FZ_PSRC, int sn, FZ_PDST, FZ_PCTM) = img_ncn; +void (*fz_img_1c1)(FZ_PSRC, FZ_PDST, FZ_PCTM) = img_1c1; +void (*fz_img_4c4)(FZ_PSRC, FZ_PDST, FZ_PCTM) = img_4c4; +void (*fz_img_1o1)(FZ_PSRC, FZ_PDST, FZ_PCTM) = img_1o1; +void (*fz_img_4o4)(FZ_PSRC, FZ_PDST, FZ_PCTM) = img_4o4; +void (*fz_img_w4i1o4)(byte*,FZ_PSRC,FZ_PDST,FZ_PCTM) = img_w4i1o4; + diff --git a/fitzdraw/imagescale.c b/fitzdraw/imagescale.c new file mode 100644 index 00000000..f25d4d5a --- /dev/null +++ b/fitzdraw/imagescale.c @@ -0,0 +1,358 @@ +#include "fitz-base.h" +#include "fitz-world.h" +#include "fitz-draw.h" + +typedef unsigned char byte; + +static inline void srown(byte * restrict src, byte * restrict dst, int w, int denom, int n) +{ + int invdenom = (1<<16) / denom; + int x, left, k; + unsigned sum[FZ_MAXCOLORS]; + + left = 0; + for (k = 0; k < n; k++) + sum[k] = 0; + + for (x = 0; x < w; x++) + { + for (k = 0; k < n; k++) + sum[k] += src[x * n + k]; + if (++left == denom) + { + left = 0; + for (k = 0; k < n; k++) + { + dst[k] = (sum[k] * invdenom + (1<<15)) >> 16; + sum[k] = 0; + } + dst += n; + } + } + + /* left overs */ + if (left) + for (k = 0; k < n; k++) + dst[k] = sum[k] / left; +} + +/* special-case common 1-5 components - the compiler optimizes this */ +static inline void srowc(byte * restrict src, byte * restrict dst, int w, int denom, int n) +{ + int invdenom = (1<<16) / denom; + int x, left; + unsigned sum1 = 0; + unsigned sum2 = 0; + unsigned sum3 = 0; + unsigned sum4 = 0; + unsigned sum5 = 0; + + assert(n <= 5); + + left = 0; + + for (x = 0; x < w; x++) + { + sum1 += src[x * n + 0]; + /* the compiler eliminates these if-tests */ + if (n >= 2) + sum2 += src[x * n + 1]; + if (n >= 3) + sum3 += src[x * n + 2]; + if (n >= 4) + sum4 += src[x * n + 3]; + if (n >= 5) + sum5 += src[x * n + 4]; + + if (++left == denom) + { + left = 0; + + dst[0] = (sum1 * invdenom + (1<<15)) >> 16; + sum1 = 0; + if (n >= 2) { + dst[1] = (sum2 * invdenom + (1<<15)) >> 16; + sum2 = 0; + } + if (n >= 3) { + dst[2] = (sum3 * invdenom + (1<<15)) >> 16; + sum3 = 0; + } + if (n >= 4) { + dst[3] = (sum4 * invdenom + (1<<15)) >> 16; + sum4 = 0; + } + if (n >= 5) { + dst[4] = (sum5 * invdenom + (1<<15)) >> 16; + sum5 = 0; + } + + + dst += n; + } + } + + /* left overs */ + if (left) { + dst[0] = sum1 / left; + if (n >=2) + dst[1] = sum2 / left; + if (n >=3) + dst[2] = sum3 / left; + if (n >=4) + dst[3] = sum4 / left; + if (n >=5) + dst[4] = sum5 / left; + } +} + +static void srow1(byte *src, byte *dst, int w, int denom) +{ + srowc(src, dst, w, denom, 1); +} + +static void srow2(byte *src, byte *dst, int w, int denom) +{ + srowc(src, dst, w, denom, 2); +} + +static void srow4(byte *src, byte *dst, int w, int denom) +{ + srowc(src, dst, w, denom, 4); +} + +static void srow5(byte *src, byte *dst, int w, int denom) +{ + srowc(src, dst, w, denom, 5); +} + +static inline void scoln(byte * restrict src, byte * restrict dst, int w, int denom, int n) +{ + int invdenom = (1<<16) / denom; + int x, y, k; + byte *s; + int sum[FZ_MAXCOLORS]; + + for (x = 0; x < w; x++) + { + s = src + (x * n); + for (k = 0; k < n; k++) + sum[k] = 0; + for (y = 0; y < denom; y++) + for (k = 0; k < n; k++) + sum[k] += s[y * w * n + k]; + for (k = 0; k < n; k++) + dst[k] = (sum[k] * invdenom + (1<<15)) >> 16; + dst += n; + } +} + +static void scol1(byte *src, byte *dst, int w, int denom) +{ + scoln(src, dst, w, denom, 1); +} + +static void scol2(byte *src, byte *dst, int w, int denom) +{ + scoln(src, dst, w, denom, 2); +} + +static void scol4(byte *src, byte *dst, int w, int denom) +{ + scoln(src, dst, w, denom, 4); +} + +static void scol5(byte *src, byte *dst, int w, int denom) +{ + scoln(src, dst, w, denom, 5); +} + +void (*fz_srown)(byte *src, byte *dst, int w, int denom, int n) = srown; +void (*fz_srow1)(byte *src, byte *dst, int w, int denom) = srow1; +void (*fz_srow2)(byte *src, byte *dst, int w, int denom) = srow2; +void (*fz_srow4)(byte *src, byte *dst, int w, int denom) = srow4; +void (*fz_srow5)(byte *src, byte *dst, int w, int denom) = srow5; + +void (*fz_scoln)(byte *src, byte *dst, int w, int denom, int n) = scoln; +void (*fz_scol1)(byte *src, byte *dst, int w, int denom) = scol1; +void (*fz_scol2)(byte *src, byte *dst, int w, int denom) = scol2; +void (*fz_scol4)(byte *src, byte *dst, int w, int denom) = scol4; +void (*fz_scol5)(byte *src, byte *dst, int w, int denom) = scol5; + +fz_error * +fz_newscaledpixmap(fz_pixmap **dstp, int w, int h, int n, int xdenom, int ydenom) +{ + int ow = (w + xdenom - 1) / xdenom; + int oh = (h + ydenom - 1) / ydenom; + return fz_newpixmap(dstp, 0, 0, ow, oh, n); +} + +/* TODO: refactor */ +fz_error * +fz_scalepixmaptile(fz_pixmap *dst, int xoffs, int yoffs, fz_pixmap *src, int xdenom, int ydenom) +{ + unsigned char *buf; + unsigned char *dstsamples; + int y, iy, oy; + int ow, oh, n; + int remaining; + + void (*srowx)(byte *src, byte *dst, int w, int denom) = nil; + void (*scolx)(byte *src, byte *dst, int w, int denom) = nil; + + ow = (src->w + xdenom - 1) / xdenom; + oh = (src->h + ydenom - 1) / ydenom; + xoffs /= xdenom; + yoffs /= ydenom; + n = src->n; + + assert(xoffs == 0); /* don't handle stride properly yet */ + assert(dst->n == n); + assert(dst->w >= xoffs + ow && dst->h >= yoffs + oh); + + buf = fz_malloc(ow * n * ydenom); + if (!buf) + return fz_outofmem; + + switch (n) + { + case 1: srowx = fz_srow1; scolx = fz_scol1; break; + case 2: srowx = fz_srow2; scolx = fz_scol2; break; + case 4: srowx = fz_srow4; scolx = fz_scol4; break; + case 5: srowx = fz_srow5; scolx = fz_scol5; break; + } + + dstsamples = dst->samples + (yoffs * dst->w + xoffs)*dst->n; + if (srowx && scolx) + { + for (y = 0, oy = 0; y < (src->h / ydenom) * ydenom; y += ydenom, oy++) + { + for (iy = 0; iy < ydenom; iy++) + srowx(src->samples + (y + iy) * src->w * n, + buf + iy * ow * n, + src->w, xdenom); + scolx(buf, dstsamples + oy * dst->w * n, ow, ydenom); + } + + remaining = src->h - y; + if (remaining) + { + for (iy = 0; iy < remaining; iy++) + srowx(src->samples + (y + iy) * src->w * n, + buf + iy * ow * n, + src->w, xdenom); + scolx(buf, dstsamples + oy * dst->w * n, ow, ydenom); + } + } + + else + { + for (y = 0, oy = 0; y < (src->h / ydenom) * ydenom; y += ydenom, oy++) + { + for (iy = 0; iy < ydenom; iy++) + fz_srown(src->samples + (y + iy) * src->w * n, + buf + iy * ow * n, + src->w, xdenom, n); + fz_scoln(buf, dstsamples + oy * dst->w * n, ow, ydenom, n); + } + + remaining = src->h - y; + if (remaining) + { + for (iy = 0; iy < remaining; iy++) + fz_srown(src->samples + (y + iy) * src->w * n, + buf + iy * ow * n, + src->w, xdenom, n); + fz_scoln(buf, dstsamples + oy * dst->w * n, ow, ydenom, n); + } + } + + fz_free(buf); + return fz_okay; +} + +fz_error * +fz_scalepixmap(fz_pixmap **dstp, fz_pixmap *src, int xdenom, int ydenom) +{ + fz_error *error; + fz_pixmap *dst; + unsigned char *buf; + int y, iy, oy; + int ow, oh, n; + int remaining; + + void (*srowx)(byte *src, byte *dst, int w, int denom) = nil; + void (*scolx)(byte *src, byte *dst, int w, int denom) = nil; + + ow = (src->w + xdenom - 1) / xdenom; + oh = (src->h + ydenom - 1) / ydenom; + n = src->n; + + buf = fz_malloc(ow * n * ydenom); + if (!buf) + return fz_outofmem; + + error = fz_newpixmap(&dst, 0, 0, ow, oh, src->n); + if (error) + { + fz_free(buf); + return error; + } + + switch (n) + { + case 1: srowx = fz_srow1; scolx = fz_scol1; break; + case 2: srowx = fz_srow2; scolx = fz_scol2; break; + case 4: srowx = fz_srow4; scolx = fz_scol4; break; + case 5: srowx = fz_srow5; scolx = fz_scol5; break; + } + + if (srowx && scolx) + { + for (y = 0, oy = 0; y < (src->h / ydenom) * ydenom; y += ydenom, oy++) + { + for (iy = 0; iy < ydenom; iy++) + srowx(src->samples + (y + iy) * src->w * n, + buf + iy * ow * n, + src->w, xdenom); + scolx(buf, dst->samples + oy * dst->w * n, dst->w, ydenom); + } + + remaining = src->h - y; + if (remaining) + { + for (iy = 0; iy < remaining; iy++) + srowx(src->samples + (y + iy) * src->w * n, + buf + iy * ow * n, + src->w, xdenom); + scolx(buf, dst->samples + oy * dst->w * n, dst->w, ydenom); + } + } + + else + { + for (y = 0, oy = 0; y < (src->h / ydenom) * ydenom; y += ydenom, oy++) + { + for (iy = 0; iy < ydenom; iy++) + fz_srown(src->samples + (y + iy) * src->w * n, + buf + iy * ow * n, + src->w, xdenom, n); + fz_scoln(buf, dst->samples + oy * dst->w * n, dst->w, ydenom, n); + } + + remaining = src->h - y; + if (remaining) + { + for (iy = 0; iy < remaining; iy++) + fz_srown(src->samples + (y + iy) * src->w * n, + buf + iy * ow * n, + src->w, xdenom, n); + fz_scoln(buf, dst->samples + oy * dst->w * n, dst->w, ydenom, n); + } + } + + fz_free(buf); + *dstp = dst; + return fz_okay; +} + diff --git a/fitzdraw/imageunpack.c b/fitzdraw/imageunpack.c new file mode 100644 index 00000000..a07d4f16 --- /dev/null +++ b/fitzdraw/imageunpack.c @@ -0,0 +1,233 @@ +#include "fitz-base.h" +#include "fitz-world.h" +#include "fitz-draw.h" + +typedef unsigned char byte; + +/* + * Apply decode parameters + */ + +static void decodetile(fz_pixmap *pix, int skip, float *decode) +{ + int min[FZ_MAXCOLORS]; + int max[FZ_MAXCOLORS]; + int sub[FZ_MAXCOLORS]; + int needed = 0; + int n = pix->n; + byte *p = pix->samples; + int wh = pix->w * pix->h; + int i; + int justinvert = 1; + + min[0] = 0; + max[0] = 255; + sub[0] = 255; + + for (i = skip; i < n; i++) + { + min[i] = decode[(i - skip) * 2] * 255; + max[i] = decode[(i - skip) * 2 + 1] * 255; + sub[i] = max[i] - min[i]; + needed |= (min[i] != 0) | (max[i] != 255); + justinvert &= min[i] == 255 && max[i] == 0 && sub[i] == -255; + } + + if (!needed) + return; + + switch (n) { + case 1: + while (wh--) + { + p[0] = min[0] + fz_mul255(sub[0], p[0]); + p ++; + } + break; + case 2: + if (justinvert) { + unsigned *wp = (unsigned *)p; + + if ((((unsigned)wp) & 3) == 0) { + int hwh = wh / 2; + wh = wh - 2 * hwh; + while(hwh--) { + unsigned in = *wp; +#if BYTE_ORDER == LITTLE_ENDIAN + unsigned out = in ^ 0xff00ff00; +#else + unsigned out = in ^ 0x00ff00ff; +#endif + *wp++ = out; + } + p = (byte *)wp; + } + if (wh--) { + p[0] = p[0]; + p[1] = 255 - p[1]; + p += 2; + } + } + else + while (wh--) + { + p[0] = min[0] + fz_mul255(sub[0], p[0]); + p[1] = min[1] + fz_mul255(sub[1], p[1]); + p += 2; + } + break; + default: + while (wh--) + { + for (i = 0; i < n; i++) + p[i] = min[i] + fz_mul255(sub[i], p[i]); + p += n; + } + } +} + +/* + * Unpack image samples and optionally pad pixels with opaque alpha + */ + +#define tbit(buf,x) ((buf[x >> 3] >> ( 7 - (x & 7) ) ) & 1 ) * 255 +#define ttwo(buf,x) ((buf[x >> 2] >> ( ( 3 - (x & 3) ) << 1 ) ) & 3 ) * 85 +#define tnib(buf,x) ((buf[x >> 1] >> ( ( 1 - (x & 1) ) << 2 ) ) & 15 ) * 17 +#define toct(buf,x) (buf[x]) + +static byte t1pad0[256][8]; +static byte t1pad1[256][16]; + +static void init1() +{ + static int inited = 0; + byte bits[1]; + int i, k, x; + + if (inited) + return; + + for (i = 0; i < 256; i++) + { + bits[0] = i; + for (k = 0; k < 8; k++) + { + x = tbit(bits, k); + t1pad0[i][k] = x; + t1pad1[i][k * 2 + 0] = 255; + t1pad1[i][k * 2 + 1] = x; + } + } + + inited = 1; +} + +static void loadtile1(byte * restrict src, int sw, byte * restrict dst, int dw, int w, int h, int pad) +{ + byte *sp; + byte *dp; + int x; + + init1(); + + if (pad == 0) + { + int w3 = w >> 3; + while (h--) + { + sp = src; + dp = dst; + for (x = 0; x < w3; x++) + { + memcpy(dp, t1pad0[*sp++], 8); + dp += 8; + } + x = x << 3; + if (x < w) + memcpy(dp, t1pad0[*sp], w - x); + src += sw; + dst += dw; + } + } + + else if (pad == 1) + { + int w3 = w >> 3; + while (h--) + { + sp = src; + dp = dst; + for (x = 0; x < w3; x++) + { + memcpy(dp, t1pad1[*sp++], 16); + dp += 16; + } + x = x << 3; + if (x < w) + memcpy(dp, t1pad1[*sp], (w - x) << 1); + src += sw; + dst += dw; + } + } + + else + { + while (h--) + { + dp = dst; + for (x = 0; x < w; x++) + { + if ((x % pad) == 0) + *dp++ = 255; + *dp++ = tbit(src, x); + } + src += sw; + dst += dw; + } + } +} + +#define TILE(getf) \ +{ \ + int x; \ + if (!pad) \ + while (h--) \ + { \ + for (x = 0; x < w; x++) \ + dst[x] = getf(src, x); \ + src += sw; \ + dst += dw; \ + } \ + else { \ + int tpad; \ + while (h--) \ + { \ + byte *dp = dst; \ + tpad = 0; \ + for (x = 0; x < w; x++) \ + { \ + if (!tpad--) { \ + tpad = pad-1; \ + *dp++ = 255; \ + } \ + *dp++ = getf(src, x); \ + } \ + src += sw; \ + dst += dw; \ + } \ + } \ +} + +static void loadtile2(byte * restrict src, int sw, byte * restrict dst, int dw, int w, int h, int pad) + TILE(ttwo) +static void loadtile4(byte * restrict src, int sw, byte * restrict dst, int dw, int w, int h, int pad) + TILE(tnib) +static void loadtile8(byte * restrict src, int sw, byte * restrict dst, int dw, int w, int h, int pad) + TILE(toct) + +void (*fz_decodetile)(fz_pixmap *pix, int skip, float *decode) = decodetile; +void (*fz_loadtile1)(byte*, int sw, byte*, int dw, int w, int h, int pad) = loadtile1; +void (*fz_loadtile2)(byte*, int sw, byte*, int dw, int w, int h, int pad) = loadtile2; +void (*fz_loadtile4)(byte*, int sw, byte*, int dw, int w, int h, int pad) = loadtile4; +void (*fz_loadtile8)(byte*, int sw, byte*, int dw, int w, int h, int pad) = loadtile8; + diff --git a/fitzdraw/meshdraw.c b/fitzdraw/meshdraw.c new file mode 100644 index 00000000..abdcaaa1 --- /dev/null +++ b/fitzdraw/meshdraw.c @@ -0,0 +1,408 @@ +#include "fitz-base.h" +#include "fitz-world.h" +#include "fitz-draw.h" + +/* + * polygon clipping + */ + +enum { IN, OUT, ENTER, LEAVE }; +enum { MAXV = 3 + 4 }; +enum { MAXN = 2 + FZ_MAXCOLORS }; + +static int clipx(float val, int ismax, float *v1, float *v2, int n) +{ + float t; + int i; + int v1o = ismax ? v1[0] > val : v1[0] < val; + int v2o = ismax ? v2[0] > val : v2[0] < val; + if (v1o + v2o == 0) + return IN; + if (v1o + v2o == 2) + return OUT; + if (v2o) + { + t = (val - v1[0]) / (v2[0] - v1[0]); + v2[0] = val; + v2[1] = v1[1] + t * (v2[1] - v1[1]); + for (i = 2; i < n; i++) + v2[i] = v1[i] + t * (v2[i] - v1[i]); + return LEAVE; + } + else + { + t = (val - v2[0]) / (v1[0] - v2[0]); + v1[0] = val; + v1[1] = v2[1] + t * (v1[1] - v2[1]); + for (i = 2; i < n; i++) + v1[i] = v2[i] + t * (v1[i] - v2[i]); + return ENTER; + } +} + +static int clipy(float val, int ismax, float *v1, float *v2, int n) +{ + float t; + int i; + int v1o = ismax ? v1[1] > val : v1[1] < val; + int v2o = ismax ? v2[1] > val : v2[1] < val; + if (v1o + v2o == 0) + return IN; + if (v1o + v2o == 2) + return OUT; + if (v2o) + { + t = (val - v1[1]) / (v2[1] - v1[1]); + v2[0] = v1[0] + t * (v2[0] - v1[0]); + v2[1] = val; + for (i = 2; i < n; i++) + v2[i] = v1[i] + t * (v2[i] - v1[i]); + return LEAVE; + } + else + { + t = (val - v2[1]) / (v1[1] - v2[1]); + v1[0] = v2[0] + t * (v1[0] - v2[0]); + v1[1] = val; + for (i = 2; i < n; i++) + v1[i] = v2[i] + t * (v1[i] - v2[i]); + return ENTER; + } +} + +static inline void copyvert(float *dst, float *src, int n) +{ + while (n--) + *dst++ = *src++; +} + +static int clippoly(float src[MAXV][MAXN], + float dst[MAXV][MAXN], int len, int n, + float val, int isy, int ismax) +{ + float cv1[MAXN]; + float cv2[MAXN]; + int v1, v2, cp; + int r; + + v1 = len - 1; + cp = 0; + + for (v2 = 0; v2 < len; v2++) + { + copyvert(cv1, src[v1], n); + copyvert(cv2, src[v2], n); + + if (isy) + r = clipy(val, ismax, cv1, cv2, n); + else + r = clipx(val, ismax, cv1, cv2, n); + + switch (r) + { + case IN: + copyvert(dst[cp++], cv2, n); + break; + case OUT: + break; + case LEAVE: + copyvert(dst[cp++], cv2, n); + break; + case ENTER: + copyvert(dst[cp++], cv1, n); + copyvert(dst[cp++], cv2, n); + break; + } + v1 = v2; + } + + return cp; +} + +/* + * gouraud shaded polygon scan conversion + */ + +static inline void +drawscan(fz_pixmap *pix, int y, int x1, int x2, int *v1, int *v2, int n) +{ + unsigned char *p = pix->samples + ((y - pix->y) * pix->w + (x1 - pix->x)) * pix->n; + int v[FZ_MAXCOLORS]; + int dv[FZ_MAXCOLORS]; + int w = x2 - x1; + int k; + + assert(w >= 0); + assert(y >= pix->y); + assert(y < pix->y + pix->h); + assert(x1 >= pix->x); + assert(x2 <= pix->x + pix->w); + + if (w == 0) + return; + + for (k = 0; k < n; k++) + { + v[k] = v1[k]; + dv[k] = (v2[k] - v1[k]) / w; + } + + while (w--) + { + *p++ = 255; + for (k = 0; k < n; k++) + { + *p++ = v[k] >> 16; + v[k] += dv[k]; + } + } +} + +static inline int +findnext(int gel[MAXV][MAXN], int len, int a, int *s, int *e, int d) +{ + int b; + + while (1) + { + b = a + d; + if (b == len) + b = 0; + if (b == -1) + b = len - 1; + + if (gel[b][1] == gel[a][1]) + { + a = b; + continue; + } + + if (gel[b][1] > gel[a][1]) + { + *s = a; + *e = b; + return 0; + } + + return 1; + } +} + +static inline void +loadedge(int gel[MAXV][MAXN], int s, int e, int *ael, int *del, int n) +{ + int swp, k, dy; + + if (gel[s][1] > gel[s][1]) + { + swp = s; s = e; e = swp; + } + + dy = gel[e][1] - gel[s][1]; + + ael[0] = gel[s][0]; + del[0] = (gel[e][0] - gel[s][0]) / dy; + for (k = 2; k < n; k++) + { + ael[k] = gel[s][k]; + del[k] = (gel[e][k] - gel[s][k]) / dy; + } +} + +static inline void +stepedge(int *ael, int *del, int n) +{ + int k; + ael[0] += del[0]; + for (k = 2; k < n; k++) + ael[k] += del[k]; +} + +void +fz_drawtriangle(fz_pixmap *pix, float *av, float *bv, float *cv, int n) +{ + float poly[MAXV][MAXN]; + float temp[MAXV][MAXN]; + float cx0 = pix->x; + float cy0 = pix->y; + float cx1 = pix->x + pix->w; + float cy1 = pix->y + pix->h; + + int gel[MAXV][MAXN]; + int ael[2][MAXN]; + int del[2][MAXN]; + int y, s0, s1, e0, e1; + int top, bot, len; + + int i, k; + + copyvert(poly[0], av, n); + copyvert(poly[1], bv, n); + copyvert(poly[2], cv, n); + + len = clippoly(poly, temp, 3, n, cx0, 0, 0); + len = clippoly(temp, poly, len, n, cx1, 0, 1); + len = clippoly(poly, temp, len, n, cy0, 1, 0); + len = clippoly(temp, poly, len, n, cy1, 1, 1); + + if (len < 3) + return; + + for (i = 0; i < len; i++) + { + gel[i][0] = fz_floor(poly[i][0] + 0.5) * 65536; /* trunc and fix */ + gel[i][1] = fz_floor(poly[i][1] + 0.5); /* y is not fixpoint */ + for (k = 2; k < n; k++) + gel[i][k] = poly[i][k] * 65536; /* fix with precision */ + } + + top = bot = 0; + for (i = 0; i < len; i++) + { + if (gel[i][1] < gel[top][1]) + top = i; + if (gel[i][1] > gel[bot][1]) + bot = i; + } + + if (gel[bot][1] - gel[top][1] == 0) + return; + + y = gel[top][1]; + + if (findnext(gel, len, top, &s0, &e0, 1)) + return; + if (findnext(gel, len, top, &s1, &e1, -1)) + return; + + loadedge(gel, s0, e0, ael[0], del[0], n); + loadedge(gel, s1, e1, ael[1], del[1], n); + + while (1) + { + int x0 = ael[0][0] >> 16; + int x1 = ael[1][0] >> 16; + + if (ael[0][0] < ael[1][0]) + drawscan(pix, y, x0, x1, ael[0]+2, ael[1]+2, n-2); + else + drawscan(pix, y, x1, x0, ael[1]+2, ael[0]+2, n-2); + + stepedge(ael[0], del[0], n); + stepedge(ael[1], del[1], n); + y ++; + + if (y >= gel[e0][1]) + { + if (findnext(gel, len, e0, &s0, &e0, 1)) + return; + loadedge(gel, s0, e0, ael[0], del[0], n); + } + + if (y >= gel[e1][1]) + { + if (findnext(gel, len, e1, &s1, &e1, -1)) + return; + loadedge(gel, s1, e1, ael[1], del[1], n); + } + } +} + +/* + * mesh drawing + */ + +fz_error * +fz_rendershade(fz_shade *shade, fz_matrix ctm, fz_colorspace *destcs, fz_pixmap *dest) +{ + unsigned char clut[256][3]; + unsigned char *s, *d; + fz_error *error; + fz_pixmap *temp; + float rgb[3]; + float tri[3][MAXN]; + fz_point p; + int i, j, k, n; + + assert(dest->n == 4); + + ctm = fz_concat(shade->matrix, ctm); + + if (shade->usefunction) + { + n = 3; + error = fz_newpixmap(&temp, dest->x, dest->y, dest->w, dest->h, 2); + if (error) + return error; + } + else if (shade->cs != destcs) + { + n = 2 + shade->cs->n; + error = fz_newpixmap(&temp, dest->x, dest->y, dest->w, dest->h, + shade->cs->n + 1); + if (error) + return error; + } + else + { + n = 2 + shade->cs->n; + temp = dest; + } + + fz_clearpixmap(temp); + + for (i = 0; i < shade->meshlen; i++) + { + for (k = 0; k < 3; k++) + { + p.x = shade->mesh[(i * 3 + k) * n + 0]; + p.y = shade->mesh[(i * 3 + k) * n + 1]; + p = fz_transformpoint(ctm, p); + if (isnan(p.y) || isnan(p.x)) // How is this happening? + goto baddata; + tri[k][0] = p.x; + tri[k][1] = p.y; + for (j = 2; j < n; j++) + tri[k][j] = shade->mesh[( i * 3 + k) * n + j] * 255; + } + fz_drawtriangle(temp, tri[0], tri[1], tri[2], n); + baddata: + ; + } + + if (shade->usefunction) + { + for (i = 0; i < 256; i++) + { + fz_convertcolor(shade->cs, shade->function[i], destcs, rgb); + clut[i][0] = rgb[0] * 255; + clut[i][1] = rgb[1] * 255; + clut[i][2] = rgb[2] * 255; + } + + n = temp->w * temp->h; + s = temp->samples; + d = dest->samples; + + while (n--) + { + d[0] = s[0]; + d[1] = fz_mul255(s[0], clut[s[1]][0]); + d[2] = fz_mul255(s[0], clut[s[1]][1]); + d[3] = fz_mul255(s[0], clut[s[1]][2]); + s += 2; + d += 4; + } + + fz_droppixmap(temp); + } + + else if (shade->cs != destcs) + { + fz_convertpixmap(shade->cs, temp, destcs, dest); + fz_droppixmap(temp); + } + + return fz_okay; +} + diff --git a/fitzdraw/pathfill.c b/fitzdraw/pathfill.c new file mode 100644 index 00000000..3040e6a3 --- /dev/null +++ b/fitzdraw/pathfill.c @@ -0,0 +1,134 @@ +#include "fitz-base.h" +#include "fitz-world.h" +#include "fitz-draw.h" + +static fz_error * +line(fz_gel *gel, fz_matrix *ctm, float x0, float y0, float x1, float y1) +{ + float tx0 = ctm->a * x0 + ctm->c * y0 + ctm->e; + float ty0 = ctm->b * x0 + ctm->d * y0 + ctm->f; + float tx1 = ctm->a * x1 + ctm->c * y1 + ctm->e; + float ty1 = ctm->b * x1 + ctm->d * y1 + ctm->f; + return fz_insertgel(gel, tx0, ty0, tx1, ty1); +} + +static fz_error * +bezier(fz_gel *gel, fz_matrix *ctm, float flatness, + float xa, float ya, + float xb, float yb, + float xc, float yc, + float xd, float yd) +{ + fz_error *error; + float dmax; + float xab, yab; + float xbc, ybc; + float xcd, ycd; + float xabc, yabc; + float xbcd, ybcd; + float xabcd, yabcd; + + /* termination check */ + dmax = ABS(xa - xb); + dmax = MAX(dmax, ABS(ya - yb)); + dmax = MAX(dmax, ABS(xd - xc)); + dmax = MAX(dmax, ABS(yd - yc)); + if (dmax < flatness) + return line(gel, ctm, xa, ya, xd, yd); + + xab = xa + xb; + yab = ya + yb; + xbc = xb + xc; + ybc = yb + yc; + xcd = xc + xd; + ycd = yc + yd; + + xabc = xab + xbc; + yabc = yab + ybc; + xbcd = xbc + xcd; + ybcd = ybc + ycd; + + xabcd = xabc + xbcd; + yabcd = yabc + ybcd; + + xab *= 0.5f; yab *= 0.5f; + xbc *= 0.5f; ybc *= 0.5f; + xcd *= 0.5f; ycd *= 0.5f; + + xabc *= 0.25f; yabc *= 0.25f; + xbcd *= 0.25f; ybcd *= 0.25f; + + xabcd *= 0.125f; yabcd *= 0.125f; + + error = bezier(gel, ctm, flatness, xa, ya, xab, yab, xabc, yabc, xabcd, yabcd); + if (error) + return error; + return bezier(gel, ctm, flatness, xabcd, yabcd, xbcd, ybcd, xcd, ycd, xd, yd); +} + +fz_error * +fz_fillpath(fz_gel *gel, fz_pathnode *path, fz_matrix ctm, float flatness) +{ + fz_error *error; + float x1, y1, x2, y2, x3, y3; + float cx = 0; + float cy = 0; + float bx = 0; + float by = 0; + int i = 0; + + while (i < path->len) + { + switch (path->els[i++].k) + { + case FZ_MOVETO: + x1 = path->els[i++].v; + y1 = path->els[i++].v; + cx = bx = x1; + cy = by = y1; + break; + + case FZ_LINETO: + x1 = path->els[i++].v; + y1 = path->els[i++].v; + error = line(gel, &ctm, cx, cy, x1, y1); + if (error) + return error; + cx = x1; + cy = y1; + break; + + case FZ_CURVETO: + x1 = path->els[i++].v; + y1 = path->els[i++].v; + x2 = path->els[i++].v; + y2 = path->els[i++].v; + x3 = path->els[i++].v; + y3 = path->els[i++].v; + error = bezier(gel, &ctm, flatness, cx, cy, x1, y1, x2, y2, x3, y3); + if (error) + return error; + cx = x3; + cy = y3; + break; + + case FZ_CLOSEPATH: + error = line(gel, &ctm, cx, cy, bx, by); + if (error) + return error; + cx = bx; + cy = by; + break; + } + } + + if (i && (cx != bx || cy != by)) + { + error = line(gel, &ctm, cx, cy, bx, by); + if (error) + return error; + } + + return fz_okay; +} + diff --git a/fitzdraw/pathscan.c b/fitzdraw/pathscan.c new file mode 100644 index 00000000..0ea46502 --- /dev/null +++ b/fitzdraw/pathscan.c @@ -0,0 +1,531 @@ +#include "fitz-base.h" +#include "fitz-world.h" +#include "fitz-draw.h" + +enum { HSCALE = 17, VSCALE = 15, SF = 1 }; + +/* + * Global Edge List -- list of straight path segments for scan conversion + * + * Stepping along the edges is with bresenham's line algorithm. + * + * See Mike Abrash -- Graphics Programming Black Book (notably chapter 40) + */ + +fz_error * +fz_newgel(fz_gel **gelp) +{ + fz_gel *gel; + + gel = *gelp = fz_malloc(sizeof(fz_gel)); + if (!gel) + return fz_outofmem; + + gel->edges = nil; + + gel->cap = 512; + gel->len = 0; + gel->edges = fz_malloc(sizeof(fz_edge) * gel->cap); + if (!gel->edges) { + fz_free(gel); + return fz_outofmem; + } + + gel->clip.x0 = gel->clip.y0 = INT_MAX; + gel->clip.x1 = gel->clip.y1 = INT_MIN; + + gel->bbox.x0 = gel->bbox.y0 = INT_MAX; + gel->bbox.x1 = gel->bbox.y1 = INT_MIN; + + return fz_okay; +} + +void +fz_resetgel(fz_gel *gel, fz_irect clip) +{ + if (fz_isinfiniterect(clip)) + { + gel->clip.x0 = gel->clip.y0 = INT_MAX; + gel->clip.x1 = gel->clip.y1 = INT_MIN; + } + else { + gel->clip.x0 = clip.x0 * HSCALE; + gel->clip.x1 = clip.x1 * HSCALE; + gel->clip.y0 = clip.y0 * VSCALE; + gel->clip.y1 = clip.y1 * VSCALE; + } + + gel->bbox.x0 = gel->bbox.y0 = INT_MAX; + gel->bbox.x1 = gel->bbox.y1 = INT_MIN; + + gel->len = 0; +} + +void +fz_dropgel(fz_gel *gel) +{ + fz_free(gel->edges); + fz_free(gel); +} + +fz_irect +fz_boundgel(fz_gel *gel) +{ + fz_irect bbox; + bbox.x0 = fz_idiv(gel->bbox.x0, HSCALE); + bbox.y0 = fz_idiv(gel->bbox.y0, VSCALE); + bbox.x1 = fz_idiv(gel->bbox.x1, HSCALE) + 1; + bbox.y1 = fz_idiv(gel->bbox.y1, VSCALE) + 1; + return bbox; +} + +enum { INSIDE, OUTSIDE, LEAVE, ENTER }; + +#define cliplerpy(v,m,x0,y0,x1,y1,t) cliplerpx(v,m,y0,x0,y1,x1,t) + +static int +cliplerpx(int val, int m, int x0, int y0, int x1, int y1, int *out) +{ + int v0out = m ? x0 > val : x0 < val; + int v1out = m ? x1 > val : x1 < val; + + if (v0out + v1out == 0) + return INSIDE; + + if (v0out + v1out == 2) + return OUTSIDE; + + if (v1out) + { + *out = y0 + (y1 - y0) * (val - x0) / (x1 - x0); + return LEAVE; + } + + else + { + *out = y1 + (y0 - y1) * (val - x1) / (x0 - x1); + return ENTER; + } +} + +fz_error * +fz_insertgel(fz_gel *gel, float fx0, float fy0, float fx1, float fy1) +{ + fz_edge *edge; + int dx, dy; + int winding; + int width; + int tmp; + int v; + int d; + + int x0 = fz_floor(fx0 * HSCALE); + int y0 = fz_floor(fy0 * VSCALE); + int x1 = fz_floor(fx1 * HSCALE); + int y1 = fz_floor(fy1 * VSCALE); + + d = cliplerpy(gel->clip.y0, 0, x0, y0, x1, y1, &v); + if (d == OUTSIDE) return fz_okay; + if (d == LEAVE) { y1 = gel->clip.y0; x1 = v; } + if (d == ENTER) { y0 = gel->clip.y0; x0 = v; } + + d = cliplerpy(gel->clip.y1, 1, x0, y0, x1, y1, &v); + if (d == OUTSIDE) return fz_okay; + if (d == LEAVE) { y1 = gel->clip.y1; x1 = v; } + if (d == ENTER) { y0 = gel->clip.y1; x0 = v; } + + if (y0 == y1) + return fz_okay; + + if (y0 > y1) { + winding = -1; + tmp = x0; x0 = x1; x1 = tmp; + tmp = y0; y0 = y1; y1 = tmp; + } + else + winding = 1; + + if (x0 < gel->bbox.x0) gel->bbox.x0 = x0; + if (x0 > gel->bbox.x1) gel->bbox.x1 = x0; + if (x1 < gel->bbox.x0) gel->bbox.x0 = x1; + if (x1 > gel->bbox.x1) gel->bbox.x1 = x1; + + if (y0 < gel->bbox.y0) gel->bbox.y0 = y0; + if (y1 > gel->bbox.y1) gel->bbox.y1 = y1; + + if (gel->len + 1 == gel->cap) { + int newcap = gel->cap + 512; + fz_edge *newedges = fz_realloc(gel->edges, sizeof(fz_edge) * newcap); + if (!newedges) + return fz_outofmem; + gel->cap = newcap; + gel->edges = newedges; + } + + edge = &gel->edges[gel->len++]; + + dy = y1 - y0; + dx = x1 - x0; + width = dx < 0 ? -dx : dx; + + edge->xdir = dx > 0 ? 1 : -1; + edge->ydir = winding; + edge->x = x0; + edge->y = y0; + edge->h = dy; + edge->adjdown = dy; + + /* initial error term going l->r and r->l */ + if (dx >= 0) + edge->e = 0; + else + edge->e = -dy + 1; + + /* y-major edge */ + if (dy >= width) { + edge->xmove = 0; + edge->adjup = width; + } + + /* x-major edge */ + else { + edge->xmove = (width / dy) * edge->xdir; + edge->adjup = width % dy; + } + + return fz_okay; +} + +void +fz_sortgel(fz_gel *gel) +{ + fz_edge *a = gel->edges; + int n = gel->len; + + int h, i, k; + fz_edge t; + + h = 1; + if (n < 14) { + h = 1; + } + else { + while (h < n) + h = 3 * h + 1; + h /= 3; + h /= 3; + } + + while (h > 0) + { + for (i = 0; i < n; i++) { + t = a[i]; + k = i - h; + /* TODO: sort on y major, x minor */ + while (k >= 0 && a[k].y > t.y) { + a[k + h] = a[k]; + k -= h; + } + a[k + h] = t; + } + + h /= 3; + } +} + +/* + * Active Edge List -- keep track of active edges while sweeping + */ + +fz_error * +fz_newael(fz_ael **aelp) +{ + fz_ael *ael; + + ael = *aelp = fz_malloc(sizeof(fz_ael)); + if (!ael) + return fz_outofmem; + + ael->cap = 64; + ael->len = 0; + ael->edges = fz_malloc(sizeof(fz_edge*) * ael->cap); + if (!ael->edges) { + fz_free(ael); + return fz_outofmem; + } + + return fz_okay; +} + +void +fz_dropael(fz_ael *ael) +{ + fz_free(ael->edges); + fz_free(ael); +} + +static inline void +sortael(fz_edge **a, int n) +{ + int h, i, k; + fz_edge *t; + + h = 1; + if (n < 14) { + h = 1; + } + else { + while (h < n) + h = 3 * h + 1; + h /= 3; + h /= 3; + } + + while (h > 0) + { + for (i = 0; i < n; i++) { + t = a[i]; + k = i - h; + while (k >= 0 && a[k]->x > t->x) { + a[k + h] = a[k]; + k -= h; + } + a[k + h] = t; + } + + h /= 3; + } +} + +static fz_error * +insertael(fz_ael *ael, fz_gel *gel, int y, int *e) +{ + /* insert edges that start here */ + while (*e < gel->len && gel->edges[*e].y == y) { + if (ael->len + 1 == ael->cap) { + int newcap = ael->cap + 64; + fz_edge **newedges = fz_realloc(ael->edges, sizeof(fz_edge*) * newcap); + if (!newedges) + return fz_outofmem; + ael->edges = newedges; + ael->cap = newcap; + } + ael->edges[ael->len++] = &gel->edges[(*e)++]; + } + + /* shell-sort the edges by increasing x */ + sortael(ael->edges, ael->len); + + return fz_okay; +} + +static void +advanceael(fz_ael *ael) +{ + fz_edge *edge; + int i = 0; + + while (i < ael->len) + { + edge = ael->edges[i]; + + edge->h --; + + /* terminator! */ + if (edge->h == 0) { + ael->edges[i] = ael->edges[--ael->len]; + } + + else { + edge->x += edge->xmove; + edge->e += edge->adjup; + if (edge->e > 0) { + edge->x += edge->xdir; + edge->e -= edge->adjdown; + } + i ++; + } + } +} + +/* + * Scan convert + */ + +static inline void +addspan(unsigned char *list, int x0, int x1, int xofs) +{ + int x0pix, x0sub; + int x1pix, x1sub; + + if (x0 == x1) + return; + + /* x between 0 and width of bbox */ + x0 -= xofs; + x1 -= xofs; + + x0pix = x0 / HSCALE; + x0sub = x0 % HSCALE; + x1pix = x1 / HSCALE; + x1sub = x1 % HSCALE; + + if (x0pix == x1pix) + { + list[x0pix] += x1sub - x0sub; + list[x0pix+1] += x0sub - x1sub; + } + + else + { + list[x0pix] += HSCALE - x0sub; + list[x0pix+1] += x0sub; + list[x1pix] += x1sub - HSCALE; + list[x1pix+1] += -x1sub; + } +} + +static inline void +nonzerowinding(fz_ael *ael, unsigned char *list, int xofs) +{ + int winding = 0; + int x = 0; + int i; + for (i = 0; i < ael->len; i++) + { + if (!winding && (winding + ael->edges[i]->ydir)) + x = ael->edges[i]->x; + if (winding && !(winding + ael->edges[i]->ydir)) + addspan(list, x, ael->edges[i]->x, xofs); + winding += ael->edges[i]->ydir; + } +} + +static inline void +evenodd(fz_ael *ael, unsigned char *list, int xofs) +{ + int even = 0; + int x = 0; + int i; + for (i = 0; i < ael->len; i++) + { + if (!even) + x = ael->edges[i]->x; + else + addspan(list, x, ael->edges[i]->x, xofs); + even = !even; + } +} + +static inline void toalpha(unsigned char *list, int n) +{ + int d = 0; + while (n--) + { + d += *list; + *list++ = d; + } +} + +static inline void blit(fz_pixmap *pix, int x, int y, + unsigned char *list, int skipx, int len, + unsigned char *argb, int over) +{ + unsigned char *dst; + unsigned char cov; + + dst = pix->samples + ( (y - pix->y) * pix->w + (x - pix->x) ) * pix->n; + cov = 0; + + while (skipx--) + { + cov += *list; + *list = 0; + ++list; + } + + if (argb) + fz_path_w4i1o4(argb, list, cov, len, dst); + else if (over) + fz_path_1o1(list, cov, len, dst); + else + fz_path_1c1(list, cov, len, dst); +} + +fz_error * +fz_scanconvert(fz_gel *gel, fz_ael *ael, int eofill, fz_irect clip, + fz_pixmap *pix, unsigned char *argb, int over) +{ + fz_error *error; + unsigned char *deltas; + int y, e; + int yd, yc; + + int xmin = fz_idiv(gel->bbox.x0, HSCALE); + int xmax = fz_idiv(gel->bbox.x1, HSCALE) + 1; + + int xofs = xmin * HSCALE; + + int skipx = clip.x0 - xmin; + int clipn = clip.x1 - clip.x0; + + assert(clip.x0 >= xmin); + assert(clip.x1 <= xmax); + + if (gel->len == 0) + return fz_okay; + + deltas = fz_malloc(xmax - xmin + 1); + if (!deltas) + return fz_outofmem; + + memset(deltas, 0, xmax - xmin + 1); + + e = 0; + y = gel->edges[0].y; + yc = fz_idiv(y, VSCALE); + yd = yc; + + while (ael->len > 0 || e < gel->len) + { + yc = fz_idiv(y, VSCALE); + if (yc != yd) + { + if (yd >= clip.y0 && yd < clip.y1) + { + blit(pix, xmin + skipx, yd, deltas, skipx, clipn, argb, over); + } + } + yd = yc; + + error = insertael(ael, gel, y, &e); + if (error) { + fz_free(deltas); + return error; + } + + if (yd >= clip.y0 && yd < clip.y1) + { + if (eofill) + evenodd(ael, deltas, xofs); + else + nonzerowinding(ael, deltas, xofs); + } + + advanceael(ael); + + if (ael->len > 0) + y ++; + else if (e < gel->len) + y = gel->edges[e].y; + } + + if (yd >= clip.y0 && yd < clip.y1) + { + blit(pix, xmin + skipx, yd, deltas, skipx, clipn, argb, over); + } + + fz_free(deltas); + return fz_okay; +} + diff --git a/fitzdraw/pathstroke.c b/fitzdraw/pathstroke.c new file mode 100644 index 00000000..d68f38ed --- /dev/null +++ b/fitzdraw/pathstroke.c @@ -0,0 +1,737 @@ +#include "fitz-base.h" +#include "fitz-world.h" +#include "fitz-draw.h" + +enum { BUTT = 0, ROUND = 1, SQUARE = 2, MITER = 0, BEVEL = 2 }; + +struct sctx +{ + fz_gel *gel; + fz_matrix *ctm; + float flatness; + + int linecap; + int linejoin; + float linewidth; + float miterlimit; + fz_point beg[2]; + fz_point seg[2]; + int sn, bn; + int dot; + + fz_dash *dash; + int toggle; + int offset; + float phase; + fz_point cur; +}; + +static fz_error * +line(struct sctx *s, float x0, float y0, float x1, float y1) +{ + float tx0 = s->ctm->a * x0 + s->ctm->c * y0 + s->ctm->e; + float ty0 = s->ctm->b * x0 + s->ctm->d * y0 + s->ctm->f; + float tx1 = s->ctm->a * x1 + s->ctm->c * y1 + s->ctm->e; + float ty1 = s->ctm->b * x1 + s->ctm->d * y1 + s->ctm->f; + return fz_insertgel(s->gel, tx0, ty0, tx1, ty1); +} + +static fz_error * +arc(struct sctx *s, + float xc, float yc, + float x0, float y0, + float x1, float y1) +{ + fz_error *error; + float th0, th1, r; + float theta; + float ox, oy, nx, ny; + int n, i; + + r = fabs(s->linewidth); + theta = 2 * M_SQRT2 * sqrt(s->flatness / r); + th0 = atan2(y0, x0); + th1 = atan2(y1, x1); + + if (r > 0) + { + if (th0 < th1) + th0 += M_PI * 2; + n = ceil((th0 - th1) / theta); + } + else + { + if (th1 < th0) + th1 += M_PI * 2; + n = ceil((th1 - th0) / theta); + } + + ox = x0; + oy = y0; + for (i = 1; i < n; i++) + { + theta = th0 + (th1 - th0) * i / n; + nx = cos(theta) * r; + ny = sin(theta) * r; + error = line(s, xc + ox, yc + oy, xc + nx, yc + ny); + if (error) return error; + ox = nx; + oy = ny; + } + + error = line(s, xc + ox, yc + oy, xc + x1, yc + y1); + if (error) return error; + + return fz_okay; +} + +static fz_error * +linestroke(struct sctx *s, fz_point a, fz_point b) +{ + fz_error *error; + + float dx = b.x - a.x; + float dy = b.y - a.y; + float scale = s->linewidth / sqrt(dx * dx + dy * dy); + float dlx = dy * scale; + float dly = -dx * scale; + + error = line(s, a.x - dlx, a.y - dly, b.x - dlx, b.y - dly); + if (error) return error; + + error = line(s, b.x + dlx, b.y + dly, a.x + dlx, a.y + dly); + if (error) return error; + + return fz_okay; +} + +static fz_error * +linejoin(struct sctx *s, fz_point a, fz_point b, fz_point c) +{ + fz_error *error; + float miterlimit = s->miterlimit; + float linewidth = s->linewidth; + int linejoin = s->linejoin; + float dx0, dy0; + float dx1, dy1; + float dlx0, dly0; + float dlx1, dly1; + float dmx, dmy; + float dmr2; + float scale; + float cross; + + dx0 = b.x - a.x; + dy0 = b.y - a.y; + + dx1 = c.x - b.x; + dy1 = c.y - b.y; + + if (dx0 * dx0 + dy0 * dy0 < FLT_EPSILON) + return fz_okay; + if (dx1 * dx1 + dy1 * dy1 < FLT_EPSILON) + return fz_okay; + + scale = linewidth / sqrt(dx0 * dx0 + dy0 * dy0); + dlx0 = dy0 * scale; + dly0 = -dx0 * scale; + + scale = linewidth / sqrt(dx1 * dx1 + dy1 * dy1); + dlx1 = dy1 * scale; + dly1 = -dx1 * scale; + + cross = dx1 * dy0 - dx0 * dy1; + + dmx = (dlx0 + dlx1) * 0.5; + dmy = (dly0 + dly1) * 0.5; + dmr2 = dmx * dmx + dmy * dmy; + + if (cross * cross < FLT_EPSILON && dx0 * dx1 + dy0 * dy1 >= 0) + linejoin = BEVEL; + + if (linejoin == MITER) + if (dmr2 * miterlimit * miterlimit < linewidth * linewidth) + linejoin = BEVEL; + + if (linejoin == BEVEL) + { + error = line(s, b.x - dlx0, b.y - dly0, b.x - dlx1, b.y - dly1); + if (error) return error; + error = line(s, b.x + dlx1, b.y + dly1, b.x + dlx0, b.y + dly0); + if (error) return error; + } + + if (linejoin == MITER) + { + scale = linewidth * linewidth / dmr2; + dmx *= scale; + dmy *= scale; + + if (cross < 0) + { + error = line(s, b.x - dlx0, b.y - dly0, b.x - dlx1, b.y - dly1); + if (error) return error; + error = line(s, b.x + dlx1, b.y + dly1, b.x + dmx, b.y + dmy); + if (error) return error; + error = line(s, b.x + dmx, b.y + dmy, b.x + dlx0, b.y + dly0); + if (error) return error; + } + else + { + error = line(s, b.x + dlx1, b.y + dly1, b.x + dlx0, b.y + dly0); + if (error) return error; + error = line(s, b.x - dlx0, b.y - dly0, b.x - dmx, b.y - dmy); + if (error) return error; + error = line(s, b.x - dmx, b.y - dmy, b.x - dlx1, b.y - dly1); + if (error) return error; + } + } + + if (linejoin == ROUND) + { + if (cross < 0) + { + error = line(s, b.x - dlx0, b.y - dly0, b.x - dlx1, b.y - dly1); + if (error) return error; + error = arc(s, b.x, b.y, dlx1, dly1, dlx0, dly0); + if (error) return error; + } + else + { + error = line(s, b.x + dlx1, b.y + dly1, b.x + dlx0, b.y + dly0); + if (error) return error; + error = arc(s, b.x, b.y, -dlx0, -dly0, -dlx1, -dly1); + if (error) return error; + } + } + + return fz_okay; +} + +static fz_error * +linecap(struct sctx *s, fz_point a, fz_point b) +{ + fz_error *error; + float flatness = s->flatness; + float linewidth = s->linewidth; + int linecap = s->linecap; + + float dx = b.x - a.x; + float dy = b.y - a.y; + + float scale = linewidth / sqrt(dx * dx + dy * dy); + float dlx = dy * scale; + float dly = -dx * scale; + + if (linecap == BUTT) + return line(s, b.x - dlx, b.y - dly, b.x + dlx, b.y + dly); + + if (linecap == ROUND) + { + int i; + int n = ceil(M_PI / (2.0 * M_SQRT2 * sqrt(flatness / linewidth))); + float ox = b.x - dlx; + float oy = b.y - dly; + for (i = 1; i < n; i++) + { + float theta = M_PI * i / n; + float cth = cos(theta); + float sth = sin(theta); + float nx = b.x - dlx * cth - dly * sth; + float ny = b.y - dly * cth + dlx * sth; + error = line(s, ox, oy, nx, ny); + if (error) return error; + ox = nx; + oy = ny; + } + error = line(s, ox, oy, b.x + dlx, b.y + dly); + if (error) return error; + } + + if (linecap == SQUARE) + { + error = line(s, b.x - dlx, b.y - dly, + b.x - dlx - dly, + b.y - dly + dlx); + if (error) return error; + error = line(s, b.x - dlx - dly, + b.y - dly + dlx, + b.x + dlx - dly, + b.y + dly + dlx); + if (error) return error; + error = line(s, b.x + dlx - dly, + b.y + dly + dlx, + b.x + dlx, b.y + dly); + if (error) return error; + } + + return fz_okay; +} + +static fz_error * +linedot(struct sctx *s, fz_point a) +{ + fz_error *error; + float flatness = s->flatness; + float linewidth = s->linewidth; + int n = ceil(M_PI / (M_SQRT2 * sqrt(flatness / linewidth))); + float ox = a.x - linewidth; + float oy = a.y; + int i; + for (i = 1; i < n; i++) + { + float theta = M_PI * 2 * i / n; + float cth = cos(theta); + float sth = sin(theta); + float nx = a.x - cth * linewidth; + float ny = a.y + sth * linewidth; + error = line(s, ox, oy, nx, ny); + if (error) return error; + ox = nx; + oy = ny; + } + error = line(s, ox, oy, a.x - linewidth, a.y); + if (error) return error; + return fz_okay; +} + +static fz_error * +strokeflush(struct sctx *s) +{ + fz_error *error; + + if (s->sn == 2) + { + error = linecap(s, s->beg[1], s->beg[0]); + if (error) return error; + error = linecap(s, s->seg[0], s->seg[1]); + if (error) return error; + } + else if (s->dot) + { + error = linedot(s, s->beg[0]); + if (error) return error; + } + + s->dot = 0; + + return fz_okay; +} + +static fz_error * +strokemoveto(struct sctx *s, fz_point cur) +{ + fz_error *error; + + error = strokeflush(s); + if (error) return error; + + s->seg[0] = cur; + s->beg[0] = cur; + s->sn = 1; + s->bn = 1; + + return fz_okay; +} + +static fz_error * +strokelineto(struct sctx *s, fz_point cur) +{ + fz_error *error; + + float dx = cur.x - s->seg[s->sn-1].x; + float dy = cur.y - s->seg[s->sn-1].y; + + if (dx * dx + dy * dy < s->flatness * s->flatness * 0.25) + { + s->dot = 1; + return fz_okay; + } + + error = linestroke(s, s->seg[s->sn-1], cur); + if (error) return error; + + if (s->sn == 2) + { + error = linejoin(s, s->seg[0], s->seg[1], cur); + if (error) return error; + + s->seg[0] = s->seg[1]; + s->seg[1] = cur; + } + + if (s->sn == 1) + s->seg[s->sn++] = cur; + if (s->bn == 1) + s->beg[s->bn++] = cur; + + return fz_okay; +} + +static fz_error * +strokeclosepath(struct sctx *s) +{ + fz_error *error; + + if (s->sn == 2) + { + error = strokelineto(s, s->beg[0]); + if (error) return error; + + if (s->seg[1].x == s->beg[0].x && s->seg[1].y == s->beg[0].y) + error = linejoin(s, s->seg[0], s->beg[0], s->beg[1]); + else + error = linejoin(s, s->seg[1], s->beg[0], s->beg[1]); + if (error) return error; + } + + else if (s->dot) + { + error = linedot(s, s->beg[0]); + if (error) return error; + } + + s->bn = 0; + s->sn = 0; + s->dot = 0; + + return fz_okay; +} + +static fz_error * +strokebezier(struct sctx *s, + float xa, float ya, + float xb, float yb, + float xc, float yc, + float xd, float yd) +{ + fz_error *error; + float dmax; + float xab, yab; + float xbc, ybc; + float xcd, ycd; + float xabc, yabc; + float xbcd, ybcd; + float xabcd, yabcd; + + /* termination check */ + dmax = ABS(xa - xb); + dmax = MAX(dmax, ABS(ya - yb)); + dmax = MAX(dmax, ABS(xd - xc)); + dmax = MAX(dmax, ABS(yd - yc)); + if (dmax < s->flatness) { + fz_point p; + p.x = xd; + p.y = yd; + return strokelineto(s, p); + } + + xab = xa + xb; + yab = ya + yb; + xbc = xb + xc; + ybc = yb + yc; + xcd = xc + xd; + ycd = yc + yd; + + xabc = xab + xbc; + yabc = yab + ybc; + xbcd = xbc + xcd; + ybcd = ybc + ycd; + + xabcd = xabc + xbcd; + yabcd = yabc + ybcd; + + xab *= 0.5f; yab *= 0.5f; + xbc *= 0.5f; ybc *= 0.5f; + xcd *= 0.5f; ycd *= 0.5f; + + xabc *= 0.25f; yabc *= 0.25f; + xbcd *= 0.25f; ybcd *= 0.25f; + + xabcd *= 0.125f; yabcd *= 0.125f; + + error = strokebezier(s, xa, ya, xab, yab, xabc, yabc, xabcd, yabcd); + if (error) + return error; + + return strokebezier(s, xabcd, yabcd, xbcd, ybcd, xcd, ycd, xd, yd); +} + +fz_error * +fz_strokepath(fz_gel *gel, fz_pathnode *path, fz_matrix ctm, float flatness, float linewidth) +{ + fz_error *error; + struct sctx s; + fz_point p0, p1, p2, p3; + int i; + + s.gel = gel; + s.ctm = &ctm; + s.flatness = flatness; + + s.linecap = path->linecap; + s.linejoin = path->linejoin; + s.linewidth = linewidth * 0.5; /* hairlines use a different value from the path value */ + s.miterlimit = path->miterlimit; + s.sn = 0; + s.bn = 0; + s.dot = 0; + + i = 0; + + if (path->len > 0 && path->els[0].k != FZ_MOVETO) + return fz_throw("path must begin with moveto"); + + p0.x = p0.y = 0; /* FZ_MOVETO guarantees p0 to be set, silence compiler */ + + while (i < path->len) + { + switch (path->els[i++].k) + { + case FZ_MOVETO: + p1.x = path->els[i++].v; + p1.y = path->els[i++].v; + error = strokemoveto(&s, p1); + if (error) + return error; + p0 = p1; + break; + + case FZ_LINETO: + p1.x = path->els[i++].v; + p1.y = path->els[i++].v; + error = strokelineto(&s, p1); + if (error) + return error; + p0 = p1; + break; + + case FZ_CURVETO: + p1.x = path->els[i++].v; + p1.y = path->els[i++].v; + p2.x = path->els[i++].v; + p2.y = path->els[i++].v; + p3.x = path->els[i++].v; + p3.y = path->els[i++].v; + error = strokebezier(&s, p0.x, p0.y, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y); + if (error) + return error; + p0 = p3; + break; + + case FZ_CLOSEPATH: + error = strokeclosepath(&s); + if (error) + return error; + break; + } + } + + return strokeflush(&s); +} + +static fz_error * +dashmoveto(struct sctx *s, fz_point a) +{ + s->toggle = 1; + s->offset = 0; + s->phase = s->dash->phase; + + while (s->phase >= s->dash->array[s->offset]) + { + s->toggle = !s->toggle; + s->phase -= s->dash->array[s->offset]; + s->offset ++; + if (s->offset == s->dash->len) + s->offset = 0; + } + + s->cur = a; + + if (s->toggle) + return strokemoveto(s, a); + + return fz_okay; +} + +static fz_error * +dashlineto(struct sctx *s, fz_point b) +{ + fz_error *error; + float dx, dy; + float total, used, ratio; + fz_point a; + fz_point m; + + a = s->cur; + dx = b.x - a.x; + dy = b.y - a.y; + total = sqrt(dx * dx + dy * dy); + used = 0; + + while (total - used > s->dash->array[s->offset] - s->phase) + { + used += s->dash->array[s->offset] - s->phase; + ratio = used / total; + m.x = a.x + ratio * dx; + m.y = a.y + ratio * dy; + + if (s->toggle) + error = strokelineto(s, m); + else + error = strokemoveto(s, m); + if (error) + return error; + + s->toggle = !s->toggle; + s->phase = 0; + s->offset ++; + if (s->offset == s->dash->len) + s->offset = 0; + } + + s->phase += total - used; + + s->cur = b; + + if (s->toggle) + return strokelineto(s, b); + + return fz_okay; +} + +static fz_error * +dashbezier(struct sctx *s, + float xa, float ya, + float xb, float yb, + float xc, float yc, + float xd, float yd) +{ + fz_error *error; + float dmax; + float xab, yab; + float xbc, ybc; + float xcd, ycd; + float xabc, yabc; + float xbcd, ybcd; + float xabcd, yabcd; + + /* termination check */ + dmax = ABS(xa - xb); + dmax = MAX(dmax, ABS(ya - yb)); + dmax = MAX(dmax, ABS(xd - xc)); + dmax = MAX(dmax, ABS(yd - yc)); + if (dmax < s->flatness) { + fz_point p; + p.x = xd; + p.y = yd; + return dashlineto(s, p); + } + + xab = xa + xb; + yab = ya + yb; + xbc = xb + xc; + ybc = yb + yc; + xcd = xc + xd; + ycd = yc + yd; + + xabc = xab + xbc; + yabc = yab + ybc; + xbcd = xbc + xcd; + ybcd = ybc + ycd; + + xabcd = xabc + xbcd; + yabcd = yabc + ybcd; + + xab *= 0.5f; yab *= 0.5f; + xbc *= 0.5f; ybc *= 0.5f; + xcd *= 0.5f; ycd *= 0.5f; + + xabc *= 0.25f; yabc *= 0.25f; + xbcd *= 0.25f; ybcd *= 0.25f; + + xabcd *= 0.125f; yabcd *= 0.125f; + + error = dashbezier(s, xa, ya, xab, yab, xabc, yabc, xabcd, yabcd); + if (error) return error; + return dashbezier(s, xabcd, yabcd, xbcd, ybcd, xcd, ycd, xd, yd); +} + +fz_error * +fz_dashpath(fz_gel *gel, fz_pathnode *path, fz_matrix ctm, float flatness, float linewidth) +{ + fz_error *error; + struct sctx s; + fz_point p0, p1, p2, p3, beg; + int i; + + s.gel = gel; + s.ctm = &ctm; + s.flatness = flatness; + + s.linecap = path->linecap; + s.linejoin = path->linejoin; + s.linewidth = linewidth * 0.5; + s.miterlimit = path->miterlimit; + s.sn = 0; + s.bn = 0; + s.dot = 0; + + s.dash = path->dash; + s.toggle = 0; + s.offset = 0; + s.phase = 0; + + i = 0; + + if (path->len > 0 && path->els[0].k != FZ_MOVETO) + return fz_throw("path must begin with moveto"); + + p0.x = p0.y = 0; /* FZ_MOVETO guarantees p0 to be set, silence compiler */ + + while (i < path->len) + { + switch (path->els[i++].k) + { + case FZ_MOVETO: + p1.x = path->els[i++].v; + p1.y = path->els[i++].v; + error = dashmoveto(&s, p1); + if (error) + return error; + beg = p0 = p1; + break; + + case FZ_LINETO: + p1.x = path->els[i++].v; + p1.y = path->els[i++].v; + error = dashlineto(&s, p1); + if (error) + return error; + p0 = p1; + break; + + case FZ_CURVETO: + p1.x = path->els[i++].v; + p1.y = path->els[i++].v; + p2.x = path->els[i++].v; + p2.y = path->els[i++].v; + p3.x = path->els[i++].v; + p3.y = path->els[i++].v; + error = dashbezier(&s, p0.x, p0.y, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y); + if (error) + return error; + p0 = p3; + break; + + case FZ_CLOSEPATH: + error = dashlineto(&s, beg); + if (error) + return error; + break; + } + } + + return strokeflush(&s); +} + diff --git a/fitzdraw/pixmap.c b/fitzdraw/pixmap.c new file mode 100644 index 00000000..077009f8 --- /dev/null +++ b/fitzdraw/pixmap.c @@ -0,0 +1,188 @@ +#include "fitz-base.h" +#include "fitz-world.h" +#include "fitz-draw.h" + +fz_error * +fz_newpixmap(fz_pixmap **pixp, int x, int y, int w, int h, int n) +{ + fz_pixmap *pix; + + pix = *pixp = fz_malloc(sizeof(fz_pixmap)); + if (!pix) + return fz_outofmem; + + pix->x = x; + pix->y = y; + pix->w = w; + pix->h = h; + pix->n = n; + + pix->samples = fz_malloc(pix->w * pix->h * pix->n * sizeof(fz_sample)); + if (!pix->samples) { + fz_free(pix); + return fz_outofmem; + } + + return fz_okay; +} + +fz_error * +fz_newpixmapwithrect(fz_pixmap **pixp, fz_irect r, int n) +{ + return fz_newpixmap(pixp, + r.x0, r.y0, + r.x1 - r.x0, + r.y1 - r.y0, n); +} + +fz_error * +fz_newpixmapcopy(fz_pixmap **pixp, fz_pixmap *old) +{ + fz_error *error; + error = fz_newpixmap(pixp, old->x, old->y, old->w, old->h, old->n); + if (error) + return error; + memcpy((*pixp)->samples, old->samples, old->w * old->h * old->n); + return fz_okay; +} + +void +fz_droppixmap(fz_pixmap *pix) +{ + fz_free(pix->samples); + fz_free(pix); +} + +void +fz_clearpixmap(fz_pixmap *pix) +{ + memset(pix->samples, 0, pix->w * pix->h * pix->n * sizeof(fz_sample)); +} + +void +fz_gammapixmap(fz_pixmap *pix, float gamma) +{ + unsigned char table[256]; + int n = pix->w * pix->h * pix->n; + unsigned char *p = pix->samples; + int i; + for (i = 0; i < 256; i++) + table[i] = CLAMP(pow(i / 255.0, gamma) * 255.0, 0, 255); + while (n--) + { + *p = table[*p]; + p++; + } +} + +void +fz_debugpixmap(fz_pixmap *pix, char *prefix) +{ + static int counter = 0; + char colorname[40]; + char alphaname[40]; + FILE *color = NULL; + FILE *alpha = NULL; + int x, y; + + sprintf(alphaname, "%s-%04d-alpha.pgm", prefix, counter); + alpha = fopen(alphaname, "wb"); + if (!alpha) + goto cleanup; + + if (pix->n > 1) + { + if (pix->n > 2) + sprintf(colorname, "%s-%04d-color.ppm", prefix, counter); + else + sprintf(colorname, "%s-%04d-color.pgm", prefix, counter); + + color = fopen(colorname, "wb"); + if (!color) + goto cleanup; + } + + counter ++; + + if (pix->n == 5) + { + fprintf(alpha, "P5\n%d %d\n255\n", pix->w, pix->h); + fprintf(color, "P6\n%d %d\n255\n", pix->w, pix->h); + + for (y = 0; y < pix->h; y++) + { + for (x = 0; x < pix->w; x++) + { + int a = pix->samples[x * pix->n + y * pix->w * pix->n + 0]; + int cc = pix->samples[x * pix->n + y * pix->w * pix->n + 1]; + int mm = pix->samples[x * pix->n + y * pix->w * pix->n + 2]; + int yy = pix->samples[x * pix->n + y * pix->w * pix->n + 3]; + int kk = pix->samples[x * pix->n + y * pix->w * pix->n + 4]; + int r = 255 - MIN(cc + kk, 255); + int g = 255 - MIN(mm + kk, 255); + int b = 255 - MIN(yy + kk, 255); + fputc(a, alpha); + fputc(r, color); + fputc(g, color); + fputc(b, color); + } + } + } + + else if (pix->n == 4) + { + fprintf(alpha, "P5\n%d %d\n255\n", pix->w, pix->h); + fprintf(color, "P6\n%d %d\n255\n", pix->w, pix->h); + + for (y = 0; y < pix->h; y++) + { + for (x = 0; x < pix->w; x++) + { + int a = pix->samples[x * pix->n + y * pix->w * pix->n + 0]; + int r = pix->samples[x * pix->n + y * pix->w * pix->n + 1]; + int g = pix->samples[x * pix->n + y * pix->w * pix->n + 2]; + int b = pix->samples[x * pix->n + y * pix->w * pix->n + 3]; + fputc(a, alpha); + fputc(r, color); + fputc(g, color); + fputc(b, color); + } + } + } + + else if (pix->n == 2) + { + fprintf(alpha, "P5\n%d %d\n255\n", pix->w, pix->h); + fprintf(color, "P5\n%d %d\n255\n", pix->w, pix->h); + + for (y = 0; y < pix->h; y++) + { + for (x = 0; x < pix->w; x++) + { + int a = pix->samples[x * pix->n + y * pix->w * pix->n + 0]; + int g = pix->samples[x * pix->n + y * pix->w * pix->n + 1]; + fputc(a, alpha); + fputc(g, color); + } + } + } + + else if (pix->n == 1) + { + fprintf(alpha, "P5\n%d %d\n255\n", pix->w, pix->h); + + for (y = 0; y < pix->h; y++) + { + for (x = 0; x < pix->w; x++) + { + int g = pix->samples[x * pix->n + y * pix->w * pix->n + 0]; + fputc(g, alpha); + } + } + } + +cleanup: + if (alpha) fclose(alpha); + if (color) fclose(color); +} + diff --git a/fitzdraw/porterduff.c b/fitzdraw/porterduff.c new file mode 100644 index 00000000..8f2b9862 --- /dev/null +++ b/fitzdraw/porterduff.c @@ -0,0 +1,361 @@ +#include "fitz-base.h" +#include "fitz-world.h" +#include "fitz-draw.h" + +typedef unsigned char byte; + +/* + * Blend pixmap regions + */ + +/* dst = src over dst */ +static void +duff_non(byte * restrict sp0, int sw, int sn, byte * restrict dp0, int dw, int w0, int h) +{ + int k; + while (h--) + { + byte *sp = sp0; + byte *dp = dp0; + int w = w0; + while (w--) + { + byte sa = sp[0]; + byte ssa = 255 - sa; + for (k = 0; k < sn; k++) + { + dp[k] = sp[k] + fz_mul255(dp[k], ssa); + } + sp += sn; + dp += sn; + } + sp0 += sw; + dp0 += dw; + } +} + +/* dst = src in msk */ +static void +duff_nimcn(byte * restrict sp0, int sw, int sn, byte * restrict mp0, int mw, int mn, byte * restrict dp0, int dw, int w0, int h) +{ + int k; + while (h--) + { + byte *sp = sp0; + byte *mp = mp0; + byte *dp = dp0; + int w = w0; + while (w--) + { + byte ma = mp[0]; + for (k = 0; k < sn; k++) + dp[k] = fz_mul255(sp[k], ma); + sp += sn; + mp += mn; + dp += sn; + } + sp0 += sw; + mp0 += mw; + dp0 += dw; + } +} + +/* dst = src in msk over dst */ +static void +duff_nimon(byte * restrict sp0, int sw, int sn, byte * restrict mp0, int mw, int mn, byte * restrict dp0, int dw, int w0, int h) +{ + int k; + while (h--) + { + byte *sp = sp0; + byte *mp = mp0; + byte *dp = dp0; + int w = w0; + while (w--) + { + /* TODO: validate this */ + byte ma = mp[0]; + byte sa = fz_mul255(sp[0], ma); + byte ssa = 255 - sa; + for (k = 0; k < sn; k++) + { + dp[k] = fz_mul255(sp[k], ma) + fz_mul255(dp[k], ssa); + } + sp += sn; + mp += mn; + dp += sn; + } + sp0 += sw; + mp0 += mw; + dp0 += dw; + } +} + +static void duff_1o1(byte * restrict sp0, int sw, byte * restrict dp0, int dw, int w0, int h) +{ + /* duff_non(sp0, sw, 1, dp0, dw, w0, h); */ + while (h--) + { + byte *sp = sp0; + byte *dp = dp0; + int w = w0; + while (w--) + { + dp[0] = sp[0] + fz_mul255(dp[0], 255 - sp[0]); + sp ++; + dp ++; + } + sp0 += sw; + dp0 += dw; + } +} + +static void duff_4o4(byte *sp0, int sw, byte *dp0, int dw, int w0, int h) +{ + /* duff_non(sp0, sw, 4, dp0, dw, w0, h); */ + while (h--) + { + byte *sp = sp0; + byte *dp = dp0; + int w = w0; + while (w--) + { + byte ssa = 255 - sp[0]; + dp[0] = sp[0] + fz_mul255(dp[0], ssa); + dp[1] = sp[1] + fz_mul255(dp[1], ssa); + dp[2] = sp[2] + fz_mul255(dp[2], ssa); + dp[3] = sp[3] + fz_mul255(dp[3], ssa); + sp += 4; + dp += 4; + } + sp0 += sw; + dp0 += dw; + } +} + +static void duff_1i1c1(byte * restrict sp0, int sw, byte * restrict mp0, int mw, byte * restrict dp0, int dw, int w0, int h) +{ + /* duff_nimcn(sp0, sw, 1, mp0, mw, 1, dp0, dw, w0, h); */ + while (h--) + { + byte *sp = sp0; + byte *mp = mp0; + byte *dp = dp0; + int w = w0; + while (w--) + { + dp[0] = fz_mul255(sp[0], mp[0]); + sp ++; + mp ++; + dp ++; + } + sp0 += sw; + mp0 += mw; + dp0 += dw; + } +} + +static void duff_4i1c4(byte * restrict sp0, int sw, byte * restrict mp0, int mw, byte * restrict dp0, int dw, int w0, int h) +{ + /* duff_nimcn(sp0, sw, 4, mp0, mw, 1, dp0, dw, w0, h); */ + while (h--) + { + byte *sp = sp0; + byte *mp = mp0; + byte *dp = dp0; + int w = w0; + while (w--) + { + byte ma = mp[0]; + dp[0] = fz_mul255(sp[0], ma); + dp[1] = fz_mul255(sp[1], ma); + dp[2] = fz_mul255(sp[2], ma); + dp[3] = fz_mul255(sp[3], ma); + sp += 4; + mp += 1; + dp += 4; + } + sp0 += sw; + mp0 += mw; + dp0 += dw; + } +} + +static void duff_1i1o1(byte * restrict sp0, int sw, byte * restrict mp0, int mw, byte * restrict dp0, int dw, int w0, int h) +{ + /* duff_nimon(sp0, sw, 1, mp0, mw, 1, dp0, dw, w0, h); */ + while (h--) + { + byte *sp = sp0; + byte *mp = mp0; + byte *dp = dp0; + int w = w0; + while (w--) + { + byte ma = mp[0]; + byte sa = fz_mul255(sp[0], ma); + byte ssa = 255 - sa; + dp[0] = fz_mul255(sp[0], ma) + fz_mul255(dp[0], ssa); + sp ++; + mp ++; + dp ++; + } + sp0 += sw; + mp0 += mw; + dp0 += dw; + } +} + +static void duff_4i1o4(byte * restrict sp0, int sw, byte * restrict mp0, int mw, byte * restrict dp0, int dw, int w0, int h) +{ + /* duff_nimon(sp0, sw, 4, mp0, mw, 1, dp0, dw, w0, h); */ + while (h--) + { + byte *sp = sp0; + byte *mp = mp0; + byte *dp = dp0; + int w = w0; + while (w--) + { + byte ma = mp[0]; + byte sa = fz_mul255(sp[0], ma); + byte ssa = 255 - sa; + dp[0] = fz_mul255(sp[0], ma) + fz_mul255(dp[0], ssa); + dp[1] = fz_mul255(sp[1], ma) + fz_mul255(dp[1], ssa); + dp[2] = fz_mul255(sp[2], ma) + fz_mul255(dp[2], ssa); + dp[3] = fz_mul255(sp[3], ma) + fz_mul255(dp[3], ssa); + sp += 4; + mp += 1; + dp += 4; + } + sp0 += sw; + mp0 += mw; + dp0 += dw; + } +} + +/* + * Path and text masks + */ + +static void path_1c1(byte * restrict src, byte cov, int len, byte * restrict dst) +{ + while (len--) + { + cov += *src; *src = 0; src++; + *dst++ = cov; + } +} + +static void path_1o1(byte * restrict src, byte cov, int len, byte * restrict dst) +{ + while (len--) + { + cov += *src; *src = 0; src++; + dst[0] = cov + fz_mul255(dst[0], 255 - cov); + dst++; + } +} + +// With 4 In 1 Over 4 +static void path_w4i1o4(byte * restrict argb, byte * restrict src, byte cov, int len, byte * restrict dst) +{ + byte alpha = argb[0]; + byte r = argb[4]; + byte g = argb[5]; + byte b = argb[6]; + while (len--) + { + byte ca; + cov += *src; *src = 0; src++; + ca = fz_mul255(cov, alpha); + dst[0] = ca + fz_mul255(dst[0], 255 - ca); + dst[1] = fz_mul255((short)r - dst[1], ca) + dst[1]; + dst[2] = fz_mul255((short)g - dst[2], ca) + dst[2]; + dst[3] = fz_mul255((short)b - dst[3], ca) + dst[3]; + dst += 4; + } +} + +static void text_1c1(byte * restrict src0, int srcw, byte * restrict dst0, int dstw, int w0, int h) +{ + while (h--) + { + byte * restrict src = src0; + byte * restrict dst = dst0; + int w = w0; + while (w--) + { + *dst++ = *src++; + } + src0 += srcw; + dst0 += dstw; + } +} + +static void text_1o1(byte * restrict src0, int srcw, byte * restrict dst0, int dstw, int w0, int h) +{ + while (h--) + { + byte *src = src0; + byte *dst = dst0; + int w = w0; + while (w--) + { + dst[0] = src[0] + fz_mul255(dst[0], 255 - src[0]); + src++; + dst++; + } + src0 += srcw; + dst0 += dstw; + } +} + +static void text_w4i1o4(byte * restrict argb, byte * restrict src0, int srcw, byte * restrict dst0, int dstw, int w0, int h) +{ + unsigned char alpha = argb[0]; + unsigned char r = argb[4]; + unsigned char g = argb[5]; + unsigned char b = argb[6]; + while (h--) + { + byte *src = src0; + byte *dst = dst0; + int w = w0; + while (w--) + { + byte ca = fz_mul255(src[0], alpha); + dst[0] = ca + fz_mul255(dst[0], 255 - ca); + dst[1] = fz_mul255((short)r - dst[1], ca) + dst[1]; + dst[2] = fz_mul255((short)g - dst[2], ca) + dst[2]; + dst[3] = fz_mul255((short)b - dst[3], ca) + dst[3]; + src ++; + dst += 4; + } + src0 += srcw; + dst0 += dstw; + } +} + +/* + * ... and the function pointers + */ + +void (*fz_duff_non)(byte*,int,int,byte*,int,int,int) = duff_non; +void (*fz_duff_nimcn)(byte*,int,int,byte*,int,int,byte*,int,int,int) = duff_nimcn; +void (*fz_duff_nimon)(byte*,int,int,byte*,int,int,byte*,int,int,int) = duff_nimon; +void (*fz_duff_1o1)(byte*,int,byte*,int,int,int) = duff_1o1; +void (*fz_duff_4o4)(byte*,int,byte*,int,int,int) = duff_4o4; +void (*fz_duff_1i1c1)(byte*,int,byte*,int,byte*,int,int,int) = duff_1i1c1; +void (*fz_duff_4i1c4)(byte*,int,byte*,int,byte*,int,int,int) = duff_4i1c4; +void (*fz_duff_1i1o1)(byte*,int,byte*,int,byte*,int,int,int) = duff_1i1o1; +void (*fz_duff_4i1o4)(byte*,int,byte*,int,byte*,int,int,int) = duff_4i1o4; + +void (*fz_path_1c1)(byte*,byte,int,byte*) = path_1c1; +void (*fz_path_1o1)(byte*,byte,int,byte*) = path_1o1; +void (*fz_path_w4i1o4)(byte*,byte*,byte,int,byte*) = path_w4i1o4; + +void (*fz_text_1c1)(byte*,int,byte*,int,int,int) = text_1c1; +void (*fz_text_1o1)(byte*,int,byte*,int,int,int) = text_1o1; +void (*fz_text_w4i1o4)(byte*,byte*,int,byte*,int,int,int) = text_w4i1o4; + diff --git a/fitzdraw/render.c b/fitzdraw/render.c new file mode 100644 index 00000000..90ead6a7 --- /dev/null +++ b/fitzdraw/render.c @@ -0,0 +1,969 @@ +#include "fitz-base.h" +#include "fitz-world.h" +#include "fitz-draw.h" + +#ifdef _MSC_VER +#define noDebug printf +#ifndef DEBUG +#define DEBUG +#endif +#else +#define noDEBUG(args...) printf(args) +#ifndef DEBUG +#define DEBUG(args...) +#endif +#endif +#define QUANT(x,a) (((int)((x) * (a))) / (a)) +#define HSUBPIX 5.0 +#define VSUBPIX 5.0 + +#define FNONE 0 +#define FOVER 1 +#define FRGB 4 + +static fz_error *rendernode(fz_renderer *gc, fz_node *node, fz_matrix ctm); + +fz_error * +fz_newrenderer(fz_renderer **gcp, fz_colorspace *pcm, int maskonly, int gcmem) +{ + fz_error *error; + fz_renderer *gc; + + gc = fz_malloc(sizeof(fz_renderer)); + if (!gc) + return fz_outofmem; + + gc->maskonly = maskonly; + gc->model = pcm; + gc->cache = nil; + gc->gel = nil; + gc->ael = nil; + + error = fz_newglyphcache(&gc->cache, gcmem / 24, gcmem); + if (error) + goto cleanup; + + error = fz_newgel(&gc->gel); + if (error) + goto cleanup; + + error = fz_newael(&gc->ael); + if (error) + goto cleanup; + + gc->dest = nil; + gc->over = nil; + gc->argb[0] = 255; + gc->argb[1] = 0; + gc->argb[2] = 0; + gc->argb[3] = 0; + gc->argb[4] = 0; + gc->argb[5] = 0; + gc->argb[6] = 0; + gc->flag = 0; + + *gcp = gc; + return fz_okay; + +cleanup: + if (gc->model) fz_dropcolorspace(gc->model); + if (gc->cache) fz_dropglyphcache(gc->cache); + if (gc->gel) fz_dropgel(gc->gel); + if (gc->ael) fz_dropael(gc->ael); + fz_free(gc); + return error; +} + +void +fz_droprenderer(fz_renderer *gc) +{ + if (gc->dest) fz_droppixmap(gc->dest); + if (gc->over) fz_droppixmap(gc->over); + + if (gc->model) fz_dropcolorspace(gc->model); + if (gc->cache) fz_dropglyphcache(gc->cache); + if (gc->gel) fz_dropgel(gc->gel); + if (gc->ael) fz_dropael(gc->ael); + fz_free(gc); +} + +/* + * Transform + */ + +static fz_error * +rendertransform(fz_renderer *gc, fz_transformnode *transform, fz_matrix ctm) +{ + fz_error *error; +DEBUG("transform [%g %g %g %g %g %g]\n", +transform->m.a, transform->m.b, +transform->m.c, transform->m.d, +transform->m.e, transform->m.f); +DEBUG("{\n"); + ctm = fz_concat(transform->m, ctm); + error = rendernode(gc, transform->super.first, ctm); +DEBUG("}\n"); + return error; +} + +/* + * Color + */ + +static fz_error * +rendersolid(fz_renderer *gc, fz_solidnode *solid, fz_matrix ctm) +{ + fz_error *error; + float rgb[3]; + unsigned char a, r, g, b; + unsigned char *p; + int n; + + if (gc->maskonly) + return fz_throw("assert: mask only renderer"); + if (gc->model->n != 3) + return fz_throw("assert: non-rgb renderer"); + + fz_convertcolor(solid->cs, solid->samples, gc->model, rgb); + gc->argb[0] = solid->a * 255; + gc->argb[1] = rgb[0] * solid->a * 255; + gc->argb[2] = rgb[1] * solid->a * 255; + gc->argb[3] = rgb[2] * solid->a * 255; + gc->argb[4] = rgb[0] * 255; + gc->argb[5] = rgb[1] * 255; + gc->argb[6] = rgb[2] * 255; + +DEBUG("solid %s [%d %d %d %d];\n", solid->cs->name, gc->argb[0], gc->argb[1], gc->argb[2], gc->argb[3]); + + if (gc->flag == FOVER) + { + p = gc->over->samples; + n = gc->over->w * gc->over->h; + } + else + { + error = fz_newpixmapwithrect(&gc->dest, gc->clip, 4); + if (error) + return error; + p = gc->dest->samples; + n = gc->dest->w * gc->dest->h; + } + + a = gc->argb[0]; + r = gc->argb[1]; + g = gc->argb[2]; + b = gc->argb[3]; + if (((unsigned)p & 3)) { + while (n--) + { + p[0] = a; + p[1] = r; + p[2] = g; + p[3] = b; + p += 4; + } + } + else + { + unsigned *pw = (unsigned *)p; +#if BYTE_ORDER == LITTLE_ENDIAN + unsigned argb = a | (r << 8) | (g << 16) | (b << 24); +#else + unsigned argb = (a << 24) | (r << 16) | (g << 8) | b; +#endif + while (n--) + { + *pw++ = argb; + } + } + + return fz_okay; +} + +/* + * Path + */ + +static fz_error * +renderpath(fz_renderer *gc, fz_pathnode *path, fz_matrix ctm) +{ + fz_error *error; + float flatness; + fz_irect gbox; + fz_irect clip; + float expansion = fz_matrixexpansion(ctm); + + flatness = 0.3 / expansion; + if (flatness < 0.1) + flatness = 0.1; + + fz_resetgel(gc->gel, gc->clip); + + if (path->paint == FZ_STROKE) + { + float lw = path->linewidth; + /* Check for hairline */ + if (lw * expansion < 0.1) { + lw = 1.0f / expansion; + } + if (path->dash) + error = fz_dashpath(gc->gel, path, ctm, flatness, lw); + else + error = fz_strokepath(gc->gel, path, ctm, flatness, lw); + } + else + error = fz_fillpath(gc->gel, path, ctm, flatness); + if (error) + return error; + + fz_sortgel(gc->gel); + + gbox = fz_boundgel(gc->gel); + clip = fz_intersectirects(gc->clip, gbox); + + if (fz_isemptyrect(clip)) + return fz_okay; + +DEBUG("path %s;\n", path->paint == FZ_STROKE ? "stroke" : "fill"); + + if (gc->flag & FRGB) + { +DEBUG(" path rgb %d %d %d %d, %d %d %d\n", gc->argb[0], gc->argb[1], gc->argb[2], gc->argb[3], gc->argb[4], gc->argb[5], gc->argb[6]); + return fz_scanconvert(gc->gel, gc->ael, path->paint == FZ_EOFILL, + clip, gc->over, gc->argb, 1); + } + else if (gc->flag & FOVER) + { + return fz_scanconvert(gc->gel, gc->ael, path->paint == FZ_EOFILL, + clip, gc->over, nil, 1); + } + else + { + error = fz_newpixmapwithrect(&gc->dest, clip, 1); + if (error) + return error; + fz_clearpixmap(gc->dest); + return fz_scanconvert(gc->gel, gc->ael, path->paint == FZ_EOFILL, + clip, gc->dest, nil, 0); + } +} + +/* + * Text + */ + +static void drawglyph(fz_renderer *gc, fz_pixmap *dst, fz_glyph *src, int xorig, int yorig) +{ + unsigned char *dp, *sp; + int w, h; + + int dx0 = dst->x; + int dy0 = dst->y; + int dx1 = dst->x + dst->w; + int dy1 = dst->y + dst->h; + + int x0 = xorig + src->x; + int y0 = yorig + src->y; + int x1 = x0 + src->w; + int y1 = y0 + src->h; + + int sx0 = 0; + int sy0 = 0; + int sx1 = src->w; + int sy1 = src->h; + + if (x1 <= dx0 || x0 >= dx1) return; + if (y1 <= dy0 || y0 >= dy1) return; + if (x0 < dx0) { sx0 += dx0 - x0; x0 = dx0; } + if (y0 < dy0) { sy0 += dy0 - y0; y0 = dy0; } + if (x1 > dx1) { sx1 += dx1 - x1; x1 = dx1; } + if (y1 > dy1) { sy1 += dy1 - y1; y1 = dy1; } + + sp = src->samples + (sy0 * src->w + sx0); + dp = dst->samples + ((y0 - dst->y) * dst->w + (x0 - dst->x)) * dst->n; + + w = sx1 - sx0; + h = sy1 - sy0; + + switch (gc->flag) + { + case FNONE: + assert(dst->n == 1); + fz_text_1o1(sp, src->w, dp, dst->w, w, h); + break; + + case FOVER: + assert(dst->n == 1); + fz_text_1o1(sp, src->w, dp, dst->w, w, h); + break; + + case FOVER | FRGB: + assert(dst->n == 4); + fz_text_w4i1o4(gc->argb, sp, src->w, dp, dst->w * 4, w, h); + break; + + default: + assert(!"impossible flag in text span function"); + } +} + +static fz_error * +rendertext(fz_renderer *gc, fz_textnode *text, fz_matrix ctm) +{ + fz_error *error; + fz_irect tbox; + fz_irect clip; + fz_matrix tm, trm; + fz_glyph glyph; + int i, x, y, gid; + + tbox = fz_roundrect(fz_boundnode((fz_node*)text, ctm)); + clip = fz_intersectirects(gc->clip, tbox); + +DEBUG("text %s n=%d [%g %g %g %g];\n", +text->font->name, text->len, +text->trm.a, text->trm.b, text->trm.c, text->trm.d); + + if (fz_isemptyrect(clip)) + return fz_okay; + + if (!(gc->flag & FOVER)) + { + error = fz_newpixmapwithrect(&gc->dest, clip, 1); + if (error) + return error; + fz_clearpixmap(gc->dest); + } + + tm = text->trm; + + for (i = 0; i < text->len; i++) + { + gid = text->els[i].gid; + tm.e = text->els[i].x; + tm.f = text->els[i].y; + trm = fz_concat(tm, ctm); + x = fz_floor(trm.e); + y = fz_floor(trm.f); + trm.e = QUANT(trm.e - fz_floor(trm.e), HSUBPIX); + trm.f = QUANT(trm.f - fz_floor(trm.f), VSUBPIX); + + error = fz_renderglyph(gc->cache, &glyph, text->font, gid, trm); + if (error) + return error; + + if (!(gc->flag & FOVER)) + drawglyph(gc, gc->dest, &glyph, x, y); + else + drawglyph(gc, gc->over, &glyph, x, y); + } + + return fz_okay; +} + +/* + * Image + */ + +static inline void +calcimagescale(fz_matrix ctm, int w, int h, int *odx, int *ody) +{ + float sx, sy; + int dx, dy; + + sx = sqrt(ctm.a * ctm.a + ctm.b * ctm.b); + dx = 1; + while (((w+dx-1)/dx)/sx > 2.0 && (w+dx-1)/dx > 1) + dx++; + + sy = sqrt(ctm.c * ctm.c + ctm.d * ctm.d); + dy = 1; + while (((h+dy-1)/dy)/sy > 2.0 && (h+dy-1)/dy > 1) + dy++; + + *odx = dx; + *ody = dy; +} + +static fz_error * +renderimage(fz_renderer *gc, fz_imagenode *node, fz_matrix ctm) +{ + fz_error *error; + fz_image *image = node->image; + fz_irect bbox; + fz_irect clip; + int dx, dy; + fz_pixmap *tile; + fz_pixmap *temp; + fz_matrix imgmat; + fz_matrix invmat; + int fa, fb, fc, fd; + int u0, v0; + int x0, y0; + int w, h; + int tileheight; + +DEBUG("image %dx%d %d+%d %s\n{\n", image->w, image->h, image->n, image->a, image->cs?image->cs->name:"(nil)"); + + bbox = fz_roundrect(fz_boundnode((fz_node*)node, ctm)); + clip = fz_intersectirects(gc->clip, bbox); + + if (fz_isemptyrect(clip)) + return fz_okay; + if (image->w == 0 || image->h == 0) + return fz_okay; + + calcimagescale(ctm, image->w, image->h, &dx, &dy); + + /* try to fit tile into a typical L2 cachce */ + tileheight = 512 * 1024 / (image->w * (image->n + image->a)); + /* tileheight must be an even multiple of dy, except for last band */ + tileheight = (tileheight + dy - 1) / dy * dy; + + if ((dx != 1 || dy != 1) && image->h > tileheight) { + int y = 0; + + DEBUG(" load image tile size = %dx%d\n", image->w, tileheight); + error = fz_newpixmap(&tile, 0, 0, image->w, + tileheight, image->n + 1); + if (error) + return error; + + error = fz_newscaledpixmap(&temp, image->w, image->h, image->n + 1, dx, dy); + if (error) + goto cleanup; + + do { + if (y + tileheight > image->h) + tileheight = image->h - y; + tile->y = y; + tile->h = tileheight; + DEBUG(" tile xywh=%d %d %d %d sxsy=1/%d 1/%d\n", + 0, y, image->w, tileheight, dx, dy); + error = image->loadtile(image, tile); + if (error) + goto cleanup1; + + error = fz_scalepixmaptile(temp, 0, y, tile, dx, dy); + if (error) + goto cleanup1; + + y += tileheight; + } while (y < image->h); + + fz_droppixmap(tile); + tile = temp; + } + else { + + +DEBUG(" load image\n"); + error = fz_newpixmap(&tile, 0, 0, image->w, image->h, image->n + 1); + if (error) + return error; + + error = image->loadtile(image, tile); + if (error) + goto cleanup; + + if (dx != 1 || dy != 1) + { +DEBUG(" scale image 1/%d 1/%d\n", dx, dy); + error = fz_scalepixmap(&temp, tile, dx, dy); + if (error) + goto cleanup; + fz_droppixmap(tile); + tile = temp; + } + } + + if (image->cs && image->cs != gc->model) + { +DEBUG(" convert from %s to %s\n", image->cs->name, gc->model->name); + error = fz_newpixmap(&temp, tile->x, tile->y, tile->w, tile->h, gc->model->n + 1); + if (error) + goto cleanup; + fz_convertpixmap(image->cs, tile, gc->model, temp); + fz_droppixmap(tile); + tile = temp; + } + + imgmat.a = 1.0 / tile->w; + imgmat.b = 0.0; + imgmat.c = 0.0; + imgmat.d = -1.0 / tile->h; + imgmat.e = 0.0; + imgmat.f = 1.0; + invmat = fz_invertmatrix(fz_concat(imgmat, ctm)); + + w = clip.x1 - clip.x0; + h = clip.y1 - clip.y0; + x0 = clip.x0; + y0 = clip.y0; + u0 = (invmat.a * (x0+0.5) + invmat.c * (y0+0.5) + invmat.e) * 65536; + v0 = (invmat.b * (x0+0.5) + invmat.d * (y0+0.5) + invmat.f) * 65536; + fa = invmat.a * 65536; + fb = invmat.b * 65536; + fc = invmat.c * 65536; + fd = invmat.d * 65536; + +#define PSRC tile->samples, tile->w, tile->h +#define PDST(p) p->samples + ((y0-p->y) * p->w + (x0-p->x)) * p->n, p->w * p->n +#define PCTM u0, v0, fa, fb, fc, fd, w, h + + switch (gc->flag) + { + case FNONE: + { +DEBUG(" fnone %d x %d\n", w, h); + if (image->cs) + error = fz_newpixmapwithrect(&gc->dest, clip, gc->model->n + 1); + else + error = fz_newpixmapwithrect(&gc->dest, clip, 1); + if (error) + goto cleanup; + + if (image->cs) + fz_img_4c4(PSRC, PDST(gc->dest), PCTM); + else + fz_img_1c1(PSRC, PDST(gc->dest), PCTM); + } + break; + + case FOVER: + { +DEBUG(" fover %d x %d\n", w, h); + if (image->cs) + fz_img_4o4(PSRC, PDST(gc->over), PCTM); + else + fz_img_1o1(PSRC, PDST(gc->over), PCTM); + } + break; + + case FOVER | FRGB: +DEBUG(" fover+rgb %d x %d\n", w, h); + fz_img_w4i1o4(gc->argb, PSRC, PDST(gc->over), PCTM); + break; + + default: + assert(!"impossible flag in image span function"); + } + +DEBUG("}\n"); + + fz_droppixmap(tile); + return fz_okay; + +cleanup1: + fz_droppixmap(temp); +cleanup: + fz_droppixmap(tile); + return error; +} + +/* + * Shade + */ + +static fz_error * +rendershade(fz_renderer *gc, fz_shadenode *node, fz_matrix ctm) +{ + fz_error *error; + fz_irect bbox; + + assert(!gc->maskonly); + + DEBUG("shade;\n"); + + bbox = fz_roundrect(fz_boundnode((fz_node*)node, ctm)); + bbox = fz_intersectirects(gc->clip, bbox); + + error = fz_newpixmapwithrect(&gc->dest, bbox, gc->model->n + 1); + if (error) + return error; + + return fz_rendershade(node->shade, ctm, gc->model, gc->dest); +} + +/* + * Over, Mask and Blend + */ + +static void +blendover(fz_renderer *gc, fz_pixmap *src, fz_pixmap *dst) +{ + unsigned char *sp, *dp; + fz_irect sr, dr; + int x, y, w, h; + + sr.x0 = src->x; + sr.y0 = src->y; + sr.x1 = src->x + src->w; + sr.y1 = src->y + src->h; + + dr.x0 = dst->x; + dr.y0 = dst->y; + dr.x1 = dst->x + dst->w; + dr.y1 = dst->y + dst->h; + + dr = fz_intersectirects(sr, dr); + x = dr.x0; + y = dr.y0; + w = dr.x1 - dr.x0; + h = dr.y1 - dr.y0; + + sp = src->samples + ((y - src->y) * src->w + (x - src->x)) * src->n; + dp = dst->samples + ((y - dst->y) * dst->w + (x - dst->x)) * dst->n; + + if (src->n == 1 && dst->n == 1) + fz_duff_1o1(sp, src->w, dp, dst->w, w, h); + else if (src->n == 4 && dst->n == 4) + fz_duff_4o4(sp, src->w * 4, dp, dst->w * 4, w, h); + else if (src->n == dst->n) + fz_duff_non(sp, src->w * src->n, src->n, dp, dst->w * dst->n, w, h); + else + assert(!"blendover src and dst mismatch"); +} + +static void +blendmask(fz_renderer *gc, fz_pixmap *src, fz_pixmap *msk, fz_pixmap *dst, int over) +{ + unsigned char *sp, *dp, *mp; + fz_irect sr, dr, mr; + int x, y, w, h; + + sr.x0 = src->x; + sr.y0 = src->y; + sr.x1 = src->x + src->w; + sr.y1 = src->y + src->h; + + dr.x0 = dst->x; + dr.y0 = dst->y; + dr.x1 = dst->x + dst->w; + dr.y1 = dst->y + dst->h; + + mr.x0 = msk->x; + mr.y0 = msk->y; + mr.x1 = msk->x + msk->w; + mr.y1 = msk->y + msk->h; + + dr = fz_intersectirects(sr, dr); + dr = fz_intersectirects(dr, mr); + x = dr.x0; + y = dr.y0; + w = dr.x1 - dr.x0; + h = dr.y1 - dr.y0; + + sp = src->samples + ((y - src->y) * src->w + (x - src->x)) * src->n; + mp = msk->samples + ((y - msk->y) * msk->w + (x - msk->x)) * msk->n; + dp = dst->samples + ((y - dst->y) * dst->w + (x - dst->x)) * dst->n; + + if (over) + { + if (src->n == 1 && msk->n == 1 && dst->n == 1) + fz_duff_1i1o1(sp, src->w, mp, msk->w, dp, dst->w, w, h); + else if (src->n == 4 && msk->n == 1 && dst->n == 4) + fz_duff_4i1o4(sp, src->w * 4, mp, msk->w, dp, dst->w * 4, w, h); + else if (src->n == dst->n) + fz_duff_nimon(sp, src->w * src->n, src->n, mp, msk->w * msk->n, msk->n, dp, dst->w * dst->n, w, h); + else + assert(!"blendmaskover src and msk and dst mismatch"); + } + else + { + if (src->n == 1 && msk->n == 1 && dst->n == 1) + fz_duff_1i1c1(sp, src->w, mp, msk->w, dp, dst->w, w, h); + else if (src->n == 4 && msk->n == 1 && dst->n == 4) + fz_duff_4i1c4(sp, src->w * 4, mp, msk->w, dp, dst->w * 4, w, h); + else if (src->n == dst->n) + fz_duff_nimcn(sp, src->w * src->n, src->n, mp, msk->w * msk->n, msk->n, dp, dst->w * dst->n, w, h); + else + assert(!"blendmask src and msk and dst mismatch"); + } +} + +static fz_error * +renderover(fz_renderer *gc, fz_overnode *over, fz_matrix ctm) +{ + fz_error *error; + fz_node *child; + int cluster = 0; + + if (!gc->over) + { +DEBUG("over cluster %d\n{\n", gc->maskonly ? 1 : 4); + cluster = 1; + if (gc->maskonly) + error = fz_newpixmapwithrect(&gc->over, gc->clip, 1); + else + error = fz_newpixmapwithrect(&gc->over, gc->clip, 4); + if (error) + return error; + fz_clearpixmap(gc->over); + } +else DEBUG("over\n{\n"); + + for (child = over->super.first; child; child = child->next) + { + error = rendernode(gc, child, ctm); + if (error) + return error; + if (gc->dest) + { + blendover(gc, gc->dest, gc->over); + fz_droppixmap(gc->dest); + gc->dest = nil; + } + } + + if (cluster) + { + gc->dest = gc->over; + gc->over = nil; + } + +DEBUG("}\n"); + + return fz_okay; +} + +static fz_error * +rendermask(fz_renderer *gc, fz_masknode *mask, fz_matrix ctm) +{ + fz_error *error; + int oldmaskonly; + fz_pixmap *oldover; + fz_irect oldclip; + fz_irect bbox; + fz_irect clip; + fz_pixmap *shapepix = nil; + fz_pixmap *colorpix = nil; + fz_node *shape; + fz_node *color; + float rgb[3]; + + shape = mask->super.first; + color = shape->next; + + /* special case black voodo */ + if (gc->flag & FOVER) + { + if (fz_issolidnode(color)) + { + fz_solidnode *solid = (fz_solidnode*)color; + + fz_convertcolor(solid->cs, solid->samples, gc->model, rgb); + gc->argb[0] = solid->a * 255; + gc->argb[1] = rgb[0] * solid->a * 255; + gc->argb[2] = rgb[1] * solid->a * 255; + gc->argb[3] = rgb[2] * solid->a * 255; + gc->argb[4] = rgb[0] * 255; + gc->argb[5] = rgb[1] * 255; + gc->argb[6] = rgb[2] * 255; + gc->flag |= FRGB; + + /* we know these can handle the FRGB shortcut */ + if (fz_ispathnode(shape)) + return renderpath(gc, (fz_pathnode*)shape, ctm); + if (fz_istextnode(shape)) + return rendertext(gc, (fz_textnode*)shape, ctm); + if (fz_isimagenode(shape)) + return renderimage(gc, (fz_imagenode*)shape, ctm); + } + } + + oldclip = gc->clip; + oldover = gc->over; + + bbox = fz_roundrect(fz_boundnode(shape, ctm)); + clip = fz_intersectirects(bbox, gc->clip); + bbox = fz_roundrect(fz_boundnode(color, ctm)); + clip = fz_intersectirects(bbox, clip); + + if (fz_isemptyrect(clip)) + return fz_okay; + +DEBUG("mask [%d %d %d %d]\n{\n", clip.x0, clip.y0, clip.x1, clip.y1); + +{ +fz_irect sbox = fz_roundrect(fz_boundnode(shape, ctm)); +fz_irect cbox = fz_roundrect(fz_boundnode(color, ctm)); +if (cbox.x0 >= sbox.x0 && cbox.x1 <= sbox.x1) +if (cbox.y0 >= sbox.y0 && cbox.y1 <= sbox.y1) +DEBUG("potentially useless mask\n"); +} + + gc->clip = clip; + gc->over = nil; + + oldmaskonly = gc->maskonly; + gc->maskonly = 1; + + error = rendernode(gc, shape, ctm); + if (error) + goto cleanup; + shapepix = gc->dest; + gc->dest = nil; + + gc->maskonly = oldmaskonly; + + error = rendernode(gc, color, ctm); + if (error) + goto cleanup; + colorpix = gc->dest; + gc->dest = nil; + + gc->clip = oldclip; + gc->over = oldover; + + if (shapepix && colorpix) + { + if (gc->over) + { + blendmask(gc, colorpix, shapepix, gc->over, 1); + } + else + { + clip.x0 = MAX(colorpix->x, shapepix->x); + clip.y0 = MAX(colorpix->y, shapepix->y); + clip.x1 = MIN(colorpix->x+colorpix->w, shapepix->x+shapepix->w); + clip.y1 = MIN(colorpix->y+colorpix->h, shapepix->y+shapepix->h); + error = fz_newpixmapwithrect(&gc->dest, clip, colorpix->n); + if (error) + goto cleanup; + blendmask(gc, colorpix, shapepix, gc->dest, 0); + } + } + +DEBUG("}\n"); + + if (shapepix) fz_droppixmap(shapepix); + if (colorpix) fz_droppixmap(colorpix); + return fz_okay; + +cleanup: + if (shapepix) fz_droppixmap(shapepix); + if (colorpix) fz_droppixmap(colorpix); + return error; +} + +/* + * Dispatch + */ + +static fz_error * +rendernode(fz_renderer *gc, fz_node *node, fz_matrix ctm) +{ + if (!node) + return fz_okay; + + gc->flag = FNONE; + if (gc->over) + gc->flag |= FOVER; + + switch (node->kind) + { + case FZ_NOVER: + return renderover(gc, (fz_overnode*)node, ctm); + case FZ_NMASK: + return rendermask(gc, (fz_masknode*)node, ctm); + case FZ_NTRANSFORM: + return rendertransform(gc, (fz_transformnode*)node, ctm); + case FZ_NCOLOR: + return rendersolid(gc, (fz_solidnode*)node, ctm); + case FZ_NPATH: + return renderpath(gc, (fz_pathnode*)node, ctm); + case FZ_NTEXT: + return rendertext(gc, (fz_textnode*)node, ctm); + case FZ_NIMAGE: + return renderimage(gc, (fz_imagenode*)node, ctm); + case FZ_NSHADE: + return rendershade(gc, (fz_shadenode*)node, ctm); + case FZ_NLINK: + return rendernode(gc, ((fz_linknode*)node)->tree->root, ctm); + case FZ_NBLEND: + return fz_okay; + } + + return fz_okay; +} + +fz_error * +fz_rendertree(fz_pixmap **outp, + fz_renderer *gc, fz_tree *tree, fz_matrix ctm, + fz_irect bbox, int white) +{ + fz_error *error; + + gc->clip = bbox; + gc->over = nil; + + if (gc->maskonly) + error = fz_newpixmapwithrect(&gc->over, bbox, 1); + else + error = fz_newpixmapwithrect(&gc->over, bbox, 4); + if (error) + return error; + + if (white) + memset(gc->over->samples, 0xff, gc->over->w * gc->over->h * gc->over->n); + else + memset(gc->over->samples, 0x00, gc->over->w * gc->over->h * gc->over->n); + +DEBUG("tree %d [%d %d %d %d]\n{\n", +gc->maskonly ? 1 : 4, +bbox.x0, bbox.y0, bbox.x1, bbox.y1); + + error = rendernode(gc, tree->root, ctm); + if (error) + return error; + +DEBUG("}\n"); + + if (gc->dest) + { + blendover(gc, gc->dest, gc->over); + fz_droppixmap(gc->dest); + gc->dest = nil; + } + + *outp = gc->over; + gc->over = nil; + + return fz_okay; +} + +fz_error * +fz_rendertreeover(fz_renderer *gc, fz_pixmap *dest, fz_tree *tree, fz_matrix ctm) +{ + fz_error *error; + + assert(!gc->maskonly); + assert(dest->n == 4); + + gc->clip.x0 = dest->x; + gc->clip.y0 = dest->y; + gc->clip.x1 = dest->x + dest->w; + gc->clip.y1 = dest->y + dest->h; + + gc->over = dest; + + error = rendernode(gc, tree->root, ctm); + if (error) + { + gc->over = nil; + return error; + } + + if (gc->dest) + { + blendover(gc, gc->dest, gc->over); + fz_droppixmap(gc->dest); + gc->dest = nil; + } + + gc->over = nil; + + return fz_okay; +} + diff --git a/fonts/Jamfile b/fonts/Jamfile index 869b4bd7..ac3dee2a 100644 --- a/fonts/Jamfile +++ b/fonts/Jamfile @@ -1,8 +1,11 @@ SubDir TOP fonts ; -SubDir TOP fonts droid ; -GenFile font_cjk.c : hexdump DroidSansFallback.ttf ; -Library libfonts : font_cjk.c ; +if ! ( NOCJK in $(DEFINES) ) +{ + SubDir TOP fonts droid ; + GenFile font_cjk.c : hexdump DroidSansFallback.ttf ; + Library libfonts : font_cjk.c ; +} SubDir TOP fonts ; diff --git a/raster/Jamfile b/raster/Jamfile deleted file mode 100644 index 6c8d2830..00000000 --- a/raster/Jamfile +++ /dev/null @@ -1,21 +0,0 @@ -SubDir TOP raster ; - -Library libraster : - glyphcache.c - pixmap.c - porterduff.c - meshdraw.c - imagedraw.c - imageunpack.c - imagescale.c - pathscan.c - pathfill.c - pathstroke.c - render.c - blendmodes.c - ; - -if $(OSPLAT) = PPC { Library libraster : archppc.c ; } -if $(OSPLAT) = SPARC { Library libraster : archsparc.c ; } -if $(OSPLAT) = X86 { Library libraster : archx86.c ; } - diff --git a/raster/archppc.c b/raster/archppc.c deleted file mode 100644 index 30dbd780..00000000 --- a/raster/archppc.c +++ /dev/null @@ -1,67 +0,0 @@ -/* - * PowerPC specific render optims live here - */ - -#include "fitz-base.h" -#include "fitz-world.h" -#include "fitz-draw.h" - -typedef unsigned char byte; - -#ifdef HAVE_ALTIVEC - -static void srow1ppc(byte *src, byte *dst, int w, int denom) -{ - int x, left; - int sum; - - left = 0; - sum = 0; - - for (x = 0; x < w; x++) - { - sum += *src++; - if (++left == denom) - { - left = 0; - *dst++ = sum / denom; - sum = 0; - } - } - - if (left) - *dst++ = sum / left; -} - -static void scol1ppc(byte *src, byte *dst, int w, int denom) -{ - int x, y; - unsigned char *s; - int sum; - - for (x = 0; x < w; x++) - { - s = src + x; - sum = 0; - for (y = 0; y < denom; y++) - sum += s[y * w]; - *dst++ = sum / denom; - } -} - -#endif /* HAVE_ALTIVEC */ - -#if defined (ARCH_PPC) -void -fz_accelerate(void) -{ -# ifdef HAVE_ALTIVEC - if (fz_cpuflags & HAVE_ALTIVEC) - { - fz_srow1 = srow1ppc; - fz_scol1 = scol1ppc; - } -# endif -} -#endif - diff --git a/raster/archsparc.c b/raster/archsparc.c deleted file mode 100644 index b78e5a4d..00000000 --- a/raster/archsparc.c +++ /dev/null @@ -1,23 +0,0 @@ -/* -SPARC specific render optims live here -*/ -#include "fitz-base.h" -#include "fitz-world.h" -#include "fitz-draw.h" - -#ifdef HAVE_VIS - -#endif - -#if defined (ARCH_SPARC) -void -fz_accelerate(void) -{ -# ifdef HAVE_VIS - if (fz_cpuflags & HAVE_VIS) - { - } -# endif -} -#endif - diff --git a/raster/archx86.c b/raster/archx86.c deleted file mode 100644 index 261b8a16..00000000 --- a/raster/archx86.c +++ /dev/null @@ -1,232 +0,0 @@ -/* - * x86 specific render optims live here - */ - -#include "fitz-base.h" -#include "fitz-world.h" -#include "fitz-draw.h" - -typedef unsigned char byte; - -/* always surround cpu specific code with HAVE_XXX */ -#ifdef HAVE_MMX - -/* -mmmx for gcc >= 3.4 enables the mmx intrinsic functions, icc and VC - shouldn't require anything */ -#include - -static void duff_4i1o4mmx(byte *sp0, int sw, byte *mp0, int mw, byte *dp0, int dw, int w0, int h) -{ - /* - rendering all pages of - x11pdf ~/doc/OpenGL/Presentations/CEDEC2003_Venus_and_Vulcan.pdf - % cumulative self self total - time seconds seconds calls ms/call ms/call name - 30.50 20.04 20.04 261 76.76 76.76 duff_4i1o4 - 21.67 22.02 10.95 221 49.55 49.55 duff_4i1o4mmx - */ - __m64 mzero = _mm_setzero_si64(); - while (h--) - { - byte *sp = sp0; - byte *mp = mp0; - byte *dp = dp0; - - unsigned *s = (unsigned *)sp; - unsigned *d = (unsigned *)dp; - - int w = w0; - - /* TODO: unroll and process two pixels/iteration */ - while (w--) - { - int ts = *s++; - int ma = *mp++ + 1; - int sa = ((ts & 0xff) * ma) >> 8; - int ssa = 256 - sa; - - __m64 d0 = _mm_cvtsi32_si64(*d); - __m64 s0 = _mm_cvtsi32_si64(ts); - - /* 4 x 9 bit alpha value */ - __m64 mma = _mm_set1_pi16(ma); - __m64 mssa = _mm_set1_pi16(ssa); - - /* unpack 0000argb => a0r0g0b0 */ - __m64 d1 = _mm_unpacklo_pi8(d0, mzero); - __m64 s1 = _mm_unpacklo_pi8(s0, mzero); - - /* s1 * ma => a0r0g0b0 */ - __m64 msma = _mm_mullo_pi16(s1, mma); - /* d1 * mssa */ - __m64 mdssa = _mm_mullo_pi16(d1, mssa); - - __m64 res0 = _mm_add_pi16(msma, mdssa); - /* TODO: is it possible to get rid of the shift? */ - __m64 res1 = _mm_srli_pi16(res0, 8); - - /* pack */ - __m64 res2 = _mm_packs_pu16(res1, mzero); - - *d++ = _mm_cvtsi64_si32(res2); - } - - sp0 += sw; - mp0 += mw; - dp0 += dw; - } - - _mm_empty(); -} - -static inline unsigned -getargb(unsigned *s, int w, int h, int u, int v) -{ - if ((u < 0) | (u >= w) | (v < 0) | (v >= h)) return 0; - return s[w * v + u]; -} - -static void img_4o4mmx(FZ_PSRC, FZ_PDST, FZ_PCTM) -{ - /* since mmx does not have an unsigned multiply instruction we use - 17.15 fixed point */ - u0 >>= 1; v0 >>= 1; - fa >>= 1; fb >>= 1; - fc >>= 1; fd >>= 1; - - while (h--) - { - unsigned *s = (unsigned *)src; - unsigned *d = (unsigned *)dst0; - int u = u0; - int v = v0; - int w = w0; - - __m64 mzero = _mm_setzero_si64(); - __m64 m256 = _mm_set1_pi16(256); - __m64 malphamask = _mm_cvtsi32_si64(0xff); - - while (w--) - { - int iu = u >> 15; - int iv = v >> 15; - - int fu = u & 0x7fff; - int fv = v & 0x7fff; - - int atedge = - (iu < 0) | (iu >= (srcw - 1)) | - (iv < 0) | (iv >= (srch - 1)); - - __m64 ms0s1; - __m64 ms2s3; - - if (atedge) - { - unsigned s0, s1, s2, s3; - - /* edge cases use scalar loads */ - s0 = getargb(s, srcw, srch, iu + 0, iv + 0); - s1 = getargb(s, srcw, srch, iu + 1, iv + 0); - s2 = getargb(s, srcw, srch, iu + 0, iv + 1); - s3 = getargb(s, srcw, srch, iu + 1, iv + 1); - - /* move to mmx registers */ - ms0s1 = _mm_set_pi32(s1, s0); - ms2s3 = _mm_set_pi32(s3, s2); - } - else - { - __m64 *m0s = (__m64*)(s + srcw * (iv + 0) + iu); - __m64 *m2s = (__m64*)(s + srcw * (iv + 1) + iu); - - /* faster vector loads for interior */ - ms0s1 = *m0s; - ms2s3 = *m2s; - } - - /* unpack src into 4x16bit vectors */ - __m64 ms0 = _mm_unpacklo_pi8(ms0s1, mzero); - __m64 ms1 = _mm_unpackhi_pi8(ms0s1, mzero); - __m64 ms2 = _mm_unpacklo_pi8(ms2s3, mzero); - __m64 ms3 = _mm_unpackhi_pi8(ms2s3, mzero); - - /* lerp fu */ - - __m64 mfu = _mm_set1_pi16(fu); - - /* t2 = (s1 - s0) * fu + s0 */ - __m64 t0 = _mm_sub_pi16(ms1, ms0); - __m64 t1 = _mm_mulhi_pi16(t0, mfu); - t1 = _mm_adds_pi16(t1, t1); - __m64 t2 = _mm_add_pi16(t1, ms0); - - /* t3 = (s3 - s2) * fu + s2 */ - __m64 t3 = _mm_sub_pi16(ms3, ms2); - __m64 t4 = _mm_mulhi_pi16(t3, mfu); - t4 = _mm_adds_pi16(t4, t4); - __m64 t5 = _mm_add_pi16(t4, ms2); - - /* lerp fv */ - - __m64 mfv = _mm_set1_pi16(fv); - - /* t8 = (t5 - t2) * fv + t2 */ - __m64 t6 = _mm_sub_pi16(t5, t2); - __m64 t7 = _mm_mulhi_pi16(t6, mfv); - t7 = _mm_adds_pi16(t7, t7); - __m64 t8 = _mm_add_pi16(t7, t2); - - /* load and prepare dst */ - __m64 d0 = _mm_cvtsi32_si64(*d); - - __m64 d1 = _mm_unpacklo_pi8(d0, mzero); - - /* get src alpha */ - - /* splat alpha */ - __m64 a0001 = _mm_and_si64(malphamask, t8); - __m64 a0011 = _mm_unpacklo_pi16(a0001, a0001); - __m64 a1111 = _mm_unpacklo_pi16(a0011, a0011); - - /* 255+1 - sa */ - __m64 sna = _mm_sub_pi16(m256, a1111); - - /* blend src with dst */ - __m64 d2 = _mm_mullo_pi16(d1, sna); - __m64 d3 = _mm_srli_pi16(d2, 8); - __m64 d4 = _mm_add_pi16(t8, d3); - - /* pack and store new dst */ - __m64 d5 = _mm_packs_pu16(d4, mzero); - - *d++ = _mm_cvtsi64_si32(d5); - - u += fa; - v += fb; - } - - dst0 += dstw; - u0 += fc; - v0 += fd; - } - - _mm_empty(); -} - -#endif /* HAVE_MMX */ - -#if defined (ARCH_X86) || defined(ARCH_X86_64) -void -fz_accelerate(void) -{ -# ifdef HAVE_MMX - if (fz_cpuflags & HAVE_MMX) - { - fz_duff_4i1o4 = duff_4i1o4mmx; - fz_img_4o4 = img_4o4mmx; - } -# endif -} -#endif - diff --git a/raster/blendmodes.c b/raster/blendmodes.c deleted file mode 100644 index f3ba8ac5..00000000 --- a/raster/blendmodes.c +++ /dev/null @@ -1,213 +0,0 @@ -#include "fitz-base.h" -#include "fitz-world.h" -#include "fitz-draw.h" - -typedef unsigned char byte; - -/* -PDF 1.4 blend modes, except Normal and Multiply which are Over and In respectively. -Only the actual blend routines are here, not the node rendering logic which lives in render.c. -These are slow. -*/ - - -/* These functions apply to a single component, 0-255 range typically */ - -static int -fz_screen_byte(int bd, int s) -{ - return bd + s - fz_mul255(bd, s); -} - - -static int -fz_hardlight_byte(int bd, int s) -{ - int s2 = s << 1; - if (s <= 127) - return fz_mul255(bd, s2); - else - return fz_screen_byte(bd, s2); -} - - -static int -fz_overlay_byte(int bd, int s) -{ - return fz_hardlight_byte(s, bd); // note swapped order -} - - -static int -fz_darken_byte(int bd, int s) -{ - return MIN(bd, s); -} - - -static int -fz_lighten_byte(int bd, int s) -{ - return MAX(bd, s); -} - - -static int -fz_colordodge_byte(int bd, int s) -{ - if (s < 255) - return MIN(255, 255 * bd / (255 - s)); - else - return 255; -} - - -static int -fz_colorburn_byte(int bd, int s) -{ - if (s > 0) - return 255 - MIN(255, 255 * (255 - bd) / s); - else - return 0; -} - - -static int -fz_softlight_byte(int bd, int s) -{ - /* review this */ - if (s < 128) { - return bd - fz_mul255(fz_mul255((255 - (s<<1)), bd), 255 - bd); - } - else { - int dbd; - if (bd < 64) - dbd = fz_mul255(fz_mul255((bd << 4) - 12, bd) + 4, bd); - else - dbd = (int)sqrtf(255.0f * bd); - return bd + fz_mul255(((s<<1) - 255), (dbd - bd)); - } -} - - -static int -fz_difference_byte(int bd, int s) -{ - return ABS(bd - s); -} - - -static int -fz_exclusion_byte(int bd, int s) -{ - return bd + s - (fz_mul255(bd, s)<<1); -} - - -/* Non-separable blend modes */ - - -static int -lum(int r, int g, int b) -{ - /* 0.3, 0.59, 0.11 in 16.16 fixed point */ - return (19662 * r + 38666 * g + 7208 * b) >> 16; -} - - -static void -clipcolor(int r, int g, int b, int *dr, int *dg, int *db) -{ - int l = lum(r, g, b); - int n = MIN(MIN(r, g), b); - int x = MAX(MAX(r, g), b); - if (n < 0) { - *dr = l + 255 * (r - l) / (l - n); - *dg = l + 255 * (g - l) / (l - n); - *db = l + 255 * (b - l) / (l - n); - } - else { - *dr = l + 255 * (255 - l) / (x - l); - *dg = l + 255 * (255 - l) / (x - l); - *db = l + 255 * (255 - l) / (x - l); - } -} - - -static void -setlum(int r, int g, int b, int l, int *dr, int *dg, int *db) -{ - int d = 255 - lum(r, g, b); - clipcolor(r + d, g + d, b + d, dr, dg, db); -} - - -static int -sat(int r, int g, int b) -{ - return MAX(MAX(r, g), b) - MIN(MIN(r, g), b); -} - - -static void -setsat(int r, int g, int b, int s, int *dr, int *dg, int *db) -{ - int *m[3] = { &r, &g, &b }; /* min, med, max */ - int *t; -#define SWAP(a, b) (t = a, a = b, b = t) - if (*m[0] > *m[1]) - SWAP(m[0], m[1]); - if (*m[0] > *m[2]) - SWAP(m[0], m[2]); - if (*m[1] > *m[2]) - SWAP(m[1], m[2]); - - if (*m[2] > *m[0]) { - *m[1] = (*m[1] - *m[0]) * s / (*m[2] - *m[0]); - *m[2] = s; - } - else { - *m[1] = 0; - *m[2] = 0; - } - *dr = r; - *dg = g; - *db = b; -} - - -static void -fz_hue_rgb(int *bdr, int *bdg, int *bdb, int sr, int sg, int sb) -{ - int tr, tg, tb; - setsat(sr, sg, sb, sat(*bdr, *bdg, *bdb), &tr, &tg, &tb); - setlum(tr, tg, tb, lum(*bdr, *bdg, *bdb), bdr, bdg, bdb); -} - - -static void -fz_saturation_rgb(int *bdr, int *bdg, int *bdb, int sr, int sg, int sb) -{ - int tr, tg, tb; - setsat(*bdr, *bdg, *bdb, sat(sr, sg, sb), &tr, &tg, &tb); - setlum(tr, tg, tb, lum(*bdr, *bdg, *bdb), bdr, bdg, bdb); -} - - -static void -fz_color_rgb(int *bdr, int *bdg, int *bdb, int sr, int sg, int sb) -{ - setlum(sr, sg, sb, lum(*bdr, *bdg, *bdb), bdr, bdg, bdb); -} - - -static void -fz_luminosity_rgb(int *bdr, int *bdg, int *bdb, int sr, int sg, int sb) -{ - setlum(*bdr, *bdg, *bdb, lum(sr, sg, sb), bdr, bdg, bdb); -} - - -//fz_separable_blend(, fz_blendkind mode) -//{ -//} diff --git a/raster/glyphcache.c b/raster/glyphcache.c deleted file mode 100644 index fe03524e..00000000 --- a/raster/glyphcache.c +++ /dev/null @@ -1,406 +0,0 @@ -#include "fitz-base.h" -#include "fitz-world.h" -#include "fitz-draw.h" - -typedef struct fz_hash_s fz_hash; -typedef struct fz_key_s fz_key; -typedef struct fz_val_s fz_val; - -struct fz_glyphcache_s -{ - int slots; - int size; - fz_hash *hash; - fz_val *lru; - unsigned char *buffer; - int load; - int used; -}; - -struct fz_key_s -{ - void *fid; - int a, b; - int c, d; - unsigned short cid; - unsigned char e, f; -}; - -struct fz_hash_s -{ - fz_key key; - fz_val *val; -}; - -struct fz_val_s -{ - fz_hash *ent; - unsigned char *samples; - short w, h, x, y; - int uses; -}; - -static unsigned int hashkey(fz_key *key) -{ - unsigned char *s = (unsigned char*)key; - unsigned int hash = 0; - unsigned int i; - for (i = 0; i < sizeof(fz_key); i++) - { - hash += s[i]; - hash += (hash << 10); - hash ^= (hash >> 6); - } - hash += (hash << 3); - hash ^= (hash >> 11); - hash += (hash << 15); - return hash; -} - -fz_error * -fz_newglyphcache(fz_glyphcache **arenap, int slots, int size) -{ - fz_glyphcache *arena; - - arena = *arenap = fz_malloc(sizeof(fz_glyphcache)); - if (!arena) - return fz_outofmem; - - arena->slots = slots; - arena->size = size; - - arena->hash = nil; - arena->lru = nil; - arena->buffer = nil; - - arena->hash = fz_malloc(sizeof(fz_hash) * slots); - if (!arena->hash) - goto cleanup; - - arena->lru = fz_malloc(sizeof(fz_val) * slots); - if (!arena->lru) - goto cleanup; - - arena->buffer = fz_malloc(size); - if (!arena->buffer) - goto cleanup; - - memset(arena->hash, 0, sizeof(fz_hash) * slots); - memset(arena->lru, 0, sizeof(fz_val) * slots); - memset(arena->buffer, 0, size); - arena->load = 0; - arena->used = 0; - - return fz_okay; - -cleanup: - fz_free(arena->hash); - fz_free(arena->lru); - fz_free(arena->buffer); - fz_free(arena); - return fz_outofmem; -} - -void -fz_dropglyphcache(fz_glyphcache *arena) -{ - fz_free(arena->hash); - fz_free(arena->lru); - fz_free(arena->buffer); - fz_free(arena); -} - -static int hokay = 0; -static int hcoll = 0; -static int hdist = 0; -static int coos = 0; -static int covf = 0; - -static int ghits = 0; -static int gmisses = 0; - -static fz_val * -hashfind(fz_glyphcache *arena, fz_key *key) -{ - fz_hash *tab = arena->hash; - int pos = hashkey(key) % arena->slots; - - while (1) - { - if (!tab[pos].val) - return nil; - - if (memcmp(key, &tab[pos].key, sizeof (fz_key)) == 0) - return tab[pos].val; - - pos = pos + 1; - if (pos == arena->slots) - pos = 0; - } -} - -static void -hashinsert(fz_glyphcache *arena, fz_key *key, fz_val *val) -{ - fz_hash *tab = arena->hash; - int pos = hashkey(key) % arena->slots; -int didcoll = 0; - - while (1) - { - if (!tab[pos].val) - { - tab[pos].key = *key; - tab[pos].val = val; - tab[pos].val->ent = &tab[pos]; -if (didcoll) hcoll ++; else hokay ++; hdist += didcoll; - return; - } - - pos = pos + 1; - if (pos == arena->slots) - pos = 0; -didcoll ++; - } -} - -/* -static void -hashremove(fz_glyphcache *arena, fz_key *key) -{ - fz_hash *tab = arena->hash; - unsigned int pos = hashkey(key) % arena->slots; - unsigned int hole; - unsigned int look; - unsigned int code; - - while (1) - { - if (!tab[pos].val) - return; // boo hoo! tried to remove non-existant key - - if (memcmp(key, &tab[pos].key, sizeof (fz_key)) == 0) - { - tab[pos].val = nil; - - hole = pos; - look = hole + 1; - if (look == arena->slots) - look = 0; - - while (tab[look].val) - { - code = (hashkey(&tab[look].key) % arena->slots); - if ((code <= hole && hole < look) || - (look < code && code <= hole) || - (hole < look && look < code)) - { - tab[hole] = tab[look]; - tab[hole].val->ent = &tab[hole]; - tab[look].val = nil; - hole = look; - } - - look = look + 1; - if (look == arena->slots) - look = 0; - } - - return; - } - - pos = pos + 1; - if (pos == arena->slots) - pos = 0; - } -} -*/ - -void -fz_debugglyphcache(fz_glyphcache *arena) -{ - printf("cache load %d / %d (%d / %d bytes)\n", - arena->load, arena->slots, arena->used, arena->size); - printf("no-colliders: %d colliders: %d\n", hokay, hcoll); - printf("avg dist: %d / %d: %g\n", hdist, hcoll, (double)hdist / hcoll); - printf("out-of-space evicts: %d\n", coos); - printf("out-of-hash evicts: %d\n", covf); - printf("hits = %d misses = %d ratio = %g\n", ghits, gmisses, (float)ghits / (ghits + gmisses)); -/* - int i; - for (i = 0; i < arena->slots; i++) - { - if (!arena->hash[i].val) - printf("glyph % 4d: empty\n", i); - else { - fz_key *k = &arena->hash[i].key; - fz_val *b = arena->hash[i].val; - printf("glyph % 4d: %p %d [%g %g %g %g + %d %d] " - "-> [%dx%d %d,%d]\n", i, - k->fid, k->cid, - k->a / 65536.0, - k->b / 65536.0, - k->c / 65536.0, - k->d / 65536.0, - k->e, k->f, - b->w, b->h, b->x, b->y); - } - } - - for (i = 0; i < arena->load; i++) - printf("lru %04d: glyph %d (%d)\n", i, - arena->lru[i].ent - arena->hash, arena->lru[i].uses); -*/ -} - -static void -bubble(fz_glyphcache *arena, int i) -{ - fz_val tmp; - - if (i == 0 || arena->load < 2) - return; - - tmp = arena->lru[i - 1]; - arena->lru[i - 1] = arena->lru[i]; - arena->lru[i] = tmp; - - arena->lru[i - 1].ent->val = &arena->lru[i - 1]; - arena->lru[i].ent->val = &arena->lru[i]; -} - -/* -static void -evictlast(fz_glyphcache *arena) -{ - fz_val *lru = arena->lru; - unsigned char *s, *e; - int i, k; - fz_key key; - - if (arena->load == 0) - return; - - k = arena->load - 1; - s = lru[k].samples; - e = s + lru[k].w * lru[k].h; - - // pack buffer to fill hole - memmove(s, e, arena->buffer + arena->used - e); - memset(arena->buffer + arena->used - (e - s), 0, e - s); - arena->used -= e - s; - - // update lru pointers - for (i = 0; i < k; i++) // XXX this is DOG slow! XXX - if (lru[i].samples >= e) - lru[i].samples -= e - s; - - // remove hash entry - key = lru[k].ent->key; - hashremove(arena, &key); - - arena->load --; -} -*/ - -static void -evictall(fz_glyphcache *arena) -{ - memset(arena->hash, 0, sizeof(fz_hash) * arena->slots); - memset(arena->lru, 0, sizeof(fz_val) * arena->slots); - memset(arena->buffer, 0, arena->size); - arena->load = 0; - arena->used = 0; -} - -fz_error * -fz_renderglyph(fz_glyphcache *arena, fz_glyph *glyph, fz_font *font, int cid, fz_matrix ctm) -{ - fz_error *error; - fz_key key; - fz_val *val; - int size; - - key.fid = font; - key.cid = cid; - key.a = ctm.a * 65536; - key.b = ctm.b * 65536; - key.c = ctm.c * 65536; - key.d = ctm.d * 65536; - key.e = (ctm.e - fz_floor(ctm.e)) * 256; - key.f = (ctm.f - fz_floor(ctm.f)) * 256; - - val = hashfind(arena, &key); - if (val) - { - val->uses ++; - glyph->w = val->w; - glyph->h = val->h; - glyph->x = val->x; - glyph->y = val->y; - glyph->samples = val->samples; - - bubble(arena, val - arena->lru); - - ghits++; - - return fz_okay; - } - - gmisses++; - - ctm.e = fz_floor(ctm.e) + key.e / 256.0; - ctm.f = fz_floor(ctm.f) + key.f / 256.0; - - if (font->ftface) - { - error = fz_renderftglyph(glyph, font, cid, ctm); - if (error) - return error; - } - else if (font->t3procs) - { - error = fz_rendert3glyph(glyph, font, cid, ctm); - if (error) - return error; - } - else - { - return fz_throw("uninitialized font structure"); - } - - size = glyph->w * glyph->h; - - if (size > arena->size / 6) - return fz_okay; - - while (arena->load > arena->slots * 75 / 100) - { - covf ++; - evictall(arena); - } - - while (arena->used + size >= arena->size) - { - coos ++; - evictall(arena); - } - - val = &arena->lru[arena->load++]; - val->uses = 0; - val->w = glyph->w; - val->h = glyph->h; - val->x = glyph->x; - val->y = glyph->y; - val->samples = arena->buffer + arena->used; - - arena->used += size; - - memcpy(val->samples, glyph->samples, glyph->w * glyph->h); - glyph->samples = val->samples; - - hashinsert(arena, &key, val); - - return fz_okay; -} - diff --git a/raster/imagedraw.c b/raster/imagedraw.c deleted file mode 100644 index 1ad74bf7..00000000 --- a/raster/imagedraw.c +++ /dev/null @@ -1,242 +0,0 @@ -#include "fitz-base.h" -#include "fitz-world.h" -#include "fitz-draw.h" - -typedef unsigned char byte; - -#define lerp(a,b,t) (a + (((b - a) * t) >> 16)) - -static inline byte getcomp(byte *s, int w, int h, int u, int v, int n, int k) -{ - if (u < 0 || u >= w) return 0; - if (v < 0 || v >= h) return 0; - return s[(w * v + u) * n + k]; -} - -static inline int samplecomp(byte *s, int w, int h, int u, int v, int n, int k) -{ - int ui = u >> 16; - int vi = v >> 16; - int ud = u & 0xFFFF; - int vd = v & 0xFFFF; - int a = getcomp(s, w, h, ui, vi, n, k); - int b = getcomp(s, w, h, ui+1, vi, n, k); - int c = getcomp(s, w, h, ui, vi+1, n, k); - int d = getcomp(s, w, h, ui+1, vi+1, n, k); - int ab = lerp(a, b, ud); - int cd = lerp(c, d, ud); - return lerp(ab, cd, vd); -} - -static inline byte getmask(byte *s, int w, int h, int u, int v) -{ - if (u < 0 || u >= w) return 0; - if (v < 0 || v >= h) return 0; - return s[w * v + u]; -} - -static inline int samplemask(byte *s, int w, int h, int u, int v) -{ - int ui = u >> 16; - int vi = v >> 16; - int ud = u & 0xFFFF; - int vd = v & 0xFFFF; - int a = getmask(s, w, h, ui, vi); - int b = getmask(s, w, h, ui+1, vi); - int c = getmask(s, w, h, ui, vi+1); - int d = getmask(s, w, h, ui+1, vi+1); - int ab = lerp(a, b, ud); - int cd = lerp(c, d, ud); - return lerp(ab, cd, vd); -} - -static inline void lerpargb(byte *dst, byte *a, byte *b, int t) -{ - dst[0] = lerp(a[0], b[0], t); - dst[1] = lerp(a[1], b[1], t); - dst[2] = lerp(a[2], b[2], t); - dst[3] = lerp(a[3], b[3], t); -} - -static inline byte *getargb(byte *s, int w, int h, int u, int v) -{ - static byte zero[4] = { 0, 0, 0, 0 }; - if (u < 0 || u >= w) return zero; - if (v < 0 || v >= h) return zero; - return s + ((w * v + u) << 2); -} - -static inline void sampleargb(byte *s, int w, int h, int u, int v, byte *abcd) -{ - byte ab[4]; - byte cd[4]; - int ui = u >> 16; - int vi = v >> 16; - int ud = u & 0xFFFF; - int vd = v & 0xFFFF; - byte *a = getargb(s, w, h, ui, vi); - byte *b = getargb(s, w, h, ui+1, vi); - byte *c = getargb(s, w, h, ui, vi+1); - byte *d = getargb(s, w, h, ui+1, vi+1); - lerpargb(ab, a, b, ud); - lerpargb(cd, c, d, ud); - lerpargb(abcd, ab, cd, vd); -} - -static void img_ncn(FZ_PSRC, int srcn, FZ_PDST, FZ_PCTM) -{ - int k; - while (h--) - { - byte *dstp = dst0; - int u = u0; - int v = v0; - int w = w0; - while (w--) - { - for (k = 0; k < srcn; k++) - { - dstp[k] = samplecomp(src, srcw, srch, u, v, srcn, k); - dstp += srcn; - u += fa; - v += fb; - } - } - dst0 += dstw; - u0 += fc; - v0 += fd; - } -} - -static void img_1c1(FZ_PSRC, FZ_PDST, FZ_PCTM) -{ - while (h--) - { - byte *dstp = dst0; - int u = u0; - int v = v0; - int w = w0; - while (w--) - { - dstp[0] = samplemask(src, srcw, srch, u, v); - dstp ++; - u += fa; - v += fb; - } - dst0 += dstw; - u0 += fc; - v0 += fd; - } -} - -static void img_4c4(FZ_PSRC, FZ_PDST, FZ_PCTM) -{ - while (h--) - { - byte *dstp = dst0; - int u = u0; - int v = v0; - int w = w0; - while (w--) - { - sampleargb(src, srcw, srch, u, v, dstp); - dstp += 4; - u += fa; - v += fb; - } - dst0 += dstw; - u0 += fc; - v0 += fd; - } -} - -static void img_1o1(FZ_PSRC, FZ_PDST, FZ_PCTM) -{ - byte srca; - while (h--) - { - byte *dstp = dst0; - int u = u0; - int v = v0; - int w = w0; - while (w--) - { - srca = samplemask(src, srcw, srch, u, v); - dstp[0] = srca + fz_mul255(dstp[0], 255 - srca); - dstp ++; - u += fa; - v += fb; - } - dst0 += dstw; - u0 += fc; - v0 += fd; - } -} - -static void img_4o4(FZ_PSRC, FZ_PDST, FZ_PCTM) -{ - byte argb[4]; - byte ssa; - while (h--) - { - byte *dstp = dst0; - int u = u0; - int v = v0; - int w = w0; - while (w--) - { - sampleargb(src, srcw, srch, u, v, argb); - ssa = 255 - argb[0]; - dstp[0] = argb[0] + fz_mul255(dstp[0], ssa); - dstp[1] = argb[1] + fz_mul255(dstp[1], ssa); - dstp[2] = argb[2] + fz_mul255(dstp[2], ssa); - dstp[3] = argb[3] + fz_mul255(dstp[3], ssa); - dstp += 4; - u += fa; - v += fb; - } - dst0 += dstw; - u0 += fc; - v0 += fd; - } -} - -static void img_w4i1o4(byte *argb, FZ_PSRC, FZ_PDST, FZ_PCTM) -{ - byte alpha = argb[0]; - byte r = argb[4]; - byte g = argb[5]; - byte b = argb[6]; - byte cov; - byte ca; - while (h--) - { - byte *dstp = dst0; - int u = u0; - int v = v0; - int w = w0; - while (w--) - { - cov = samplemask(src, srcw, srch, u, v); - ca = fz_mul255(cov, alpha); - dstp[0] = ca + fz_mul255(dstp[0], 255 - ca); - dstp[1] = fz_mul255((short)r - dstp[1], ca) + dstp[1]; - dstp[2] = fz_mul255((short)g - dstp[2], ca) + dstp[2]; - dstp[3] = fz_mul255((short)b - dstp[3], ca) + dstp[3]; - dstp += 4; - u += fa; - v += fb; - } - dst0 += dstw; - u0 += fc; - v0 += fd; - } -} - -void (*fz_img_ncn)(FZ_PSRC, int sn, FZ_PDST, FZ_PCTM) = img_ncn; -void (*fz_img_1c1)(FZ_PSRC, FZ_PDST, FZ_PCTM) = img_1c1; -void (*fz_img_4c4)(FZ_PSRC, FZ_PDST, FZ_PCTM) = img_4c4; -void (*fz_img_1o1)(FZ_PSRC, FZ_PDST, FZ_PCTM) = img_1o1; -void (*fz_img_4o4)(FZ_PSRC, FZ_PDST, FZ_PCTM) = img_4o4; -void (*fz_img_w4i1o4)(byte*,FZ_PSRC,FZ_PDST,FZ_PCTM) = img_w4i1o4; - diff --git a/raster/imagescale.c b/raster/imagescale.c deleted file mode 100644 index f25d4d5a..00000000 --- a/raster/imagescale.c +++ /dev/null @@ -1,358 +0,0 @@ -#include "fitz-base.h" -#include "fitz-world.h" -#include "fitz-draw.h" - -typedef unsigned char byte; - -static inline void srown(byte * restrict src, byte * restrict dst, int w, int denom, int n) -{ - int invdenom = (1<<16) / denom; - int x, left, k; - unsigned sum[FZ_MAXCOLORS]; - - left = 0; - for (k = 0; k < n; k++) - sum[k] = 0; - - for (x = 0; x < w; x++) - { - for (k = 0; k < n; k++) - sum[k] += src[x * n + k]; - if (++left == denom) - { - left = 0; - for (k = 0; k < n; k++) - { - dst[k] = (sum[k] * invdenom + (1<<15)) >> 16; - sum[k] = 0; - } - dst += n; - } - } - - /* left overs */ - if (left) - for (k = 0; k < n; k++) - dst[k] = sum[k] / left; -} - -/* special-case common 1-5 components - the compiler optimizes this */ -static inline void srowc(byte * restrict src, byte * restrict dst, int w, int denom, int n) -{ - int invdenom = (1<<16) / denom; - int x, left; - unsigned sum1 = 0; - unsigned sum2 = 0; - unsigned sum3 = 0; - unsigned sum4 = 0; - unsigned sum5 = 0; - - assert(n <= 5); - - left = 0; - - for (x = 0; x < w; x++) - { - sum1 += src[x * n + 0]; - /* the compiler eliminates these if-tests */ - if (n >= 2) - sum2 += src[x * n + 1]; - if (n >= 3) - sum3 += src[x * n + 2]; - if (n >= 4) - sum4 += src[x * n + 3]; - if (n >= 5) - sum5 += src[x * n + 4]; - - if (++left == denom) - { - left = 0; - - dst[0] = (sum1 * invdenom + (1<<15)) >> 16; - sum1 = 0; - if (n >= 2) { - dst[1] = (sum2 * invdenom + (1<<15)) >> 16; - sum2 = 0; - } - if (n >= 3) { - dst[2] = (sum3 * invdenom + (1<<15)) >> 16; - sum3 = 0; - } - if (n >= 4) { - dst[3] = (sum4 * invdenom + (1<<15)) >> 16; - sum4 = 0; - } - if (n >= 5) { - dst[4] = (sum5 * invdenom + (1<<15)) >> 16; - sum5 = 0; - } - - - dst += n; - } - } - - /* left overs */ - if (left) { - dst[0] = sum1 / left; - if (n >=2) - dst[1] = sum2 / left; - if (n >=3) - dst[2] = sum3 / left; - if (n >=4) - dst[3] = sum4 / left; - if (n >=5) - dst[4] = sum5 / left; - } -} - -static void srow1(byte *src, byte *dst, int w, int denom) -{ - srowc(src, dst, w, denom, 1); -} - -static void srow2(byte *src, byte *dst, int w, int denom) -{ - srowc(src, dst, w, denom, 2); -} - -static void srow4(byte *src, byte *dst, int w, int denom) -{ - srowc(src, dst, w, denom, 4); -} - -static void srow5(byte *src, byte *dst, int w, int denom) -{ - srowc(src, dst, w, denom, 5); -} - -static inline void scoln(byte * restrict src, byte * restrict dst, int w, int denom, int n) -{ - int invdenom = (1<<16) / denom; - int x, y, k; - byte *s; - int sum[FZ_MAXCOLORS]; - - for (x = 0; x < w; x++) - { - s = src + (x * n); - for (k = 0; k < n; k++) - sum[k] = 0; - for (y = 0; y < denom; y++) - for (k = 0; k < n; k++) - sum[k] += s[y * w * n + k]; - for (k = 0; k < n; k++) - dst[k] = (sum[k] * invdenom + (1<<15)) >> 16; - dst += n; - } -} - -static void scol1(byte *src, byte *dst, int w, int denom) -{ - scoln(src, dst, w, denom, 1); -} - -static void scol2(byte *src, byte *dst, int w, int denom) -{ - scoln(src, dst, w, denom, 2); -} - -static void scol4(byte *src, byte *dst, int w, int denom) -{ - scoln(src, dst, w, denom, 4); -} - -static void scol5(byte *src, byte *dst, int w, int denom) -{ - scoln(src, dst, w, denom, 5); -} - -void (*fz_srown)(byte *src, byte *dst, int w, int denom, int n) = srown; -void (*fz_srow1)(byte *src, byte *dst, int w, int denom) = srow1; -void (*fz_srow2)(byte *src, byte *dst, int w, int denom) = srow2; -void (*fz_srow4)(byte *src, byte *dst, int w, int denom) = srow4; -void (*fz_srow5)(byte *src, byte *dst, int w, int denom) = srow5; - -void (*fz_scoln)(byte *src, byte *dst, int w, int denom, int n) = scoln; -void (*fz_scol1)(byte *src, byte *dst, int w, int denom) = scol1; -void (*fz_scol2)(byte *src, byte *dst, int w, int denom) = scol2; -void (*fz_scol4)(byte *src, byte *dst, int w, int denom) = scol4; -void (*fz_scol5)(byte *src, byte *dst, int w, int denom) = scol5; - -fz_error * -fz_newscaledpixmap(fz_pixmap **dstp, int w, int h, int n, int xdenom, int ydenom) -{ - int ow = (w + xdenom - 1) / xdenom; - int oh = (h + ydenom - 1) / ydenom; - return fz_newpixmap(dstp, 0, 0, ow, oh, n); -} - -/* TODO: refactor */ -fz_error * -fz_scalepixmaptile(fz_pixmap *dst, int xoffs, int yoffs, fz_pixmap *src, int xdenom, int ydenom) -{ - unsigned char *buf; - unsigned char *dstsamples; - int y, iy, oy; - int ow, oh, n; - int remaining; - - void (*srowx)(byte *src, byte *dst, int w, int denom) = nil; - void (*scolx)(byte *src, byte *dst, int w, int denom) = nil; - - ow = (src->w + xdenom - 1) / xdenom; - oh = (src->h + ydenom - 1) / ydenom; - xoffs /= xdenom; - yoffs /= ydenom; - n = src->n; - - assert(xoffs == 0); /* don't handle stride properly yet */ - assert(dst->n == n); - assert(dst->w >= xoffs + ow && dst->h >= yoffs + oh); - - buf = fz_malloc(ow * n * ydenom); - if (!buf) - return fz_outofmem; - - switch (n) - { - case 1: srowx = fz_srow1; scolx = fz_scol1; break; - case 2: srowx = fz_srow2; scolx = fz_scol2; break; - case 4: srowx = fz_srow4; scolx = fz_scol4; break; - case 5: srowx = fz_srow5; scolx = fz_scol5; break; - } - - dstsamples = dst->samples + (yoffs * dst->w + xoffs)*dst->n; - if (srowx && scolx) - { - for (y = 0, oy = 0; y < (src->h / ydenom) * ydenom; y += ydenom, oy++) - { - for (iy = 0; iy < ydenom; iy++) - srowx(src->samples + (y + iy) * src->w * n, - buf + iy * ow * n, - src->w, xdenom); - scolx(buf, dstsamples + oy * dst->w * n, ow, ydenom); - } - - remaining = src->h - y; - if (remaining) - { - for (iy = 0; iy < remaining; iy++) - srowx(src->samples + (y + iy) * src->w * n, - buf + iy * ow * n, - src->w, xdenom); - scolx(buf, dstsamples + oy * dst->w * n, ow, ydenom); - } - } - - else - { - for (y = 0, oy = 0; y < (src->h / ydenom) * ydenom; y += ydenom, oy++) - { - for (iy = 0; iy < ydenom; iy++) - fz_srown(src->samples + (y + iy) * src->w * n, - buf + iy * ow * n, - src->w, xdenom, n); - fz_scoln(buf, dstsamples + oy * dst->w * n, ow, ydenom, n); - } - - remaining = src->h - y; - if (remaining) - { - for (iy = 0; iy < remaining; iy++) - fz_srown(src->samples + (y + iy) * src->w * n, - buf + iy * ow * n, - src->w, xdenom, n); - fz_scoln(buf, dstsamples + oy * dst->w * n, ow, ydenom, n); - } - } - - fz_free(buf); - return fz_okay; -} - -fz_error * -fz_scalepixmap(fz_pixmap **dstp, fz_pixmap *src, int xdenom, int ydenom) -{ - fz_error *error; - fz_pixmap *dst; - unsigned char *buf; - int y, iy, oy; - int ow, oh, n; - int remaining; - - void (*srowx)(byte *src, byte *dst, int w, int denom) = nil; - void (*scolx)(byte *src, byte *dst, int w, int denom) = nil; - - ow = (src->w + xdenom - 1) / xdenom; - oh = (src->h + ydenom - 1) / ydenom; - n = src->n; - - buf = fz_malloc(ow * n * ydenom); - if (!buf) - return fz_outofmem; - - error = fz_newpixmap(&dst, 0, 0, ow, oh, src->n); - if (error) - { - fz_free(buf); - return error; - } - - switch (n) - { - case 1: srowx = fz_srow1; scolx = fz_scol1; break; - case 2: srowx = fz_srow2; scolx = fz_scol2; break; - case 4: srowx = fz_srow4; scolx = fz_scol4; break; - case 5: srowx = fz_srow5; scolx = fz_scol5; break; - } - - if (srowx && scolx) - { - for (y = 0, oy = 0; y < (src->h / ydenom) * ydenom; y += ydenom, oy++) - { - for (iy = 0; iy < ydenom; iy++) - srowx(src->samples + (y + iy) * src->w * n, - buf + iy * ow * n, - src->w, xdenom); - scolx(buf, dst->samples + oy * dst->w * n, dst->w, ydenom); - } - - remaining = src->h - y; - if (remaining) - { - for (iy = 0; iy < remaining; iy++) - srowx(src->samples + (y + iy) * src->w * n, - buf + iy * ow * n, - src->w, xdenom); - scolx(buf, dst->samples + oy * dst->w * n, dst->w, ydenom); - } - } - - else - { - for (y = 0, oy = 0; y < (src->h / ydenom) * ydenom; y += ydenom, oy++) - { - for (iy = 0; iy < ydenom; iy++) - fz_srown(src->samples + (y + iy) * src->w * n, - buf + iy * ow * n, - src->w, xdenom, n); - fz_scoln(buf, dst->samples + oy * dst->w * n, dst->w, ydenom, n); - } - - remaining = src->h - y; - if (remaining) - { - for (iy = 0; iy < remaining; iy++) - fz_srown(src->samples + (y + iy) * src->w * n, - buf + iy * ow * n, - src->w, xdenom, n); - fz_scoln(buf, dst->samples + oy * dst->w * n, dst->w, ydenom, n); - } - } - - fz_free(buf); - *dstp = dst; - return fz_okay; -} - diff --git a/raster/imageunpack.c b/raster/imageunpack.c deleted file mode 100644 index a07d4f16..00000000 --- a/raster/imageunpack.c +++ /dev/null @@ -1,233 +0,0 @@ -#include "fitz-base.h" -#include "fitz-world.h" -#include "fitz-draw.h" - -typedef unsigned char byte; - -/* - * Apply decode parameters - */ - -static void decodetile(fz_pixmap *pix, int skip, float *decode) -{ - int min[FZ_MAXCOLORS]; - int max[FZ_MAXCOLORS]; - int sub[FZ_MAXCOLORS]; - int needed = 0; - int n = pix->n; - byte *p = pix->samples; - int wh = pix->w * pix->h; - int i; - int justinvert = 1; - - min[0] = 0; - max[0] = 255; - sub[0] = 255; - - for (i = skip; i < n; i++) - { - min[i] = decode[(i - skip) * 2] * 255; - max[i] = decode[(i - skip) * 2 + 1] * 255; - sub[i] = max[i] - min[i]; - needed |= (min[i] != 0) | (max[i] != 255); - justinvert &= min[i] == 255 && max[i] == 0 && sub[i] == -255; - } - - if (!needed) - return; - - switch (n) { - case 1: - while (wh--) - { - p[0] = min[0] + fz_mul255(sub[0], p[0]); - p ++; - } - break; - case 2: - if (justinvert) { - unsigned *wp = (unsigned *)p; - - if ((((unsigned)wp) & 3) == 0) { - int hwh = wh / 2; - wh = wh - 2 * hwh; - while(hwh--) { - unsigned in = *wp; -#if BYTE_ORDER == LITTLE_ENDIAN - unsigned out = in ^ 0xff00ff00; -#else - unsigned out = in ^ 0x00ff00ff; -#endif - *wp++ = out; - } - p = (byte *)wp; - } - if (wh--) { - p[0] = p[0]; - p[1] = 255 - p[1]; - p += 2; - } - } - else - while (wh--) - { - p[0] = min[0] + fz_mul255(sub[0], p[0]); - p[1] = min[1] + fz_mul255(sub[1], p[1]); - p += 2; - } - break; - default: - while (wh--) - { - for (i = 0; i < n; i++) - p[i] = min[i] + fz_mul255(sub[i], p[i]); - p += n; - } - } -} - -/* - * Unpack image samples and optionally pad pixels with opaque alpha - */ - -#define tbit(buf,x) ((buf[x >> 3] >> ( 7 - (x & 7) ) ) & 1 ) * 255 -#define ttwo(buf,x) ((buf[x >> 2] >> ( ( 3 - (x & 3) ) << 1 ) ) & 3 ) * 85 -#define tnib(buf,x) ((buf[x >> 1] >> ( ( 1 - (x & 1) ) << 2 ) ) & 15 ) * 17 -#define toct(buf,x) (buf[x]) - -static byte t1pad0[256][8]; -static byte t1pad1[256][16]; - -static void init1() -{ - static int inited = 0; - byte bits[1]; - int i, k, x; - - if (inited) - return; - - for (i = 0; i < 256; i++) - { - bits[0] = i; - for (k = 0; k < 8; k++) - { - x = tbit(bits, k); - t1pad0[i][k] = x; - t1pad1[i][k * 2 + 0] = 255; - t1pad1[i][k * 2 + 1] = x; - } - } - - inited = 1; -} - -static void loadtile1(byte * restrict src, int sw, byte * restrict dst, int dw, int w, int h, int pad) -{ - byte *sp; - byte *dp; - int x; - - init1(); - - if (pad == 0) - { - int w3 = w >> 3; - while (h--) - { - sp = src; - dp = dst; - for (x = 0; x < w3; x++) - { - memcpy(dp, t1pad0[*sp++], 8); - dp += 8; - } - x = x << 3; - if (x < w) - memcpy(dp, t1pad0[*sp], w - x); - src += sw; - dst += dw; - } - } - - else if (pad == 1) - { - int w3 = w >> 3; - while (h--) - { - sp = src; - dp = dst; - for (x = 0; x < w3; x++) - { - memcpy(dp, t1pad1[*sp++], 16); - dp += 16; - } - x = x << 3; - if (x < w) - memcpy(dp, t1pad1[*sp], (w - x) << 1); - src += sw; - dst += dw; - } - } - - else - { - while (h--) - { - dp = dst; - for (x = 0; x < w; x++) - { - if ((x % pad) == 0) - *dp++ = 255; - *dp++ = tbit(src, x); - } - src += sw; - dst += dw; - } - } -} - -#define TILE(getf) \ -{ \ - int x; \ - if (!pad) \ - while (h--) \ - { \ - for (x = 0; x < w; x++) \ - dst[x] = getf(src, x); \ - src += sw; \ - dst += dw; \ - } \ - else { \ - int tpad; \ - while (h--) \ - { \ - byte *dp = dst; \ - tpad = 0; \ - for (x = 0; x < w; x++) \ - { \ - if (!tpad--) { \ - tpad = pad-1; \ - *dp++ = 255; \ - } \ - *dp++ = getf(src, x); \ - } \ - src += sw; \ - dst += dw; \ - } \ - } \ -} - -static void loadtile2(byte * restrict src, int sw, byte * restrict dst, int dw, int w, int h, int pad) - TILE(ttwo) -static void loadtile4(byte * restrict src, int sw, byte * restrict dst, int dw, int w, int h, int pad) - TILE(tnib) -static void loadtile8(byte * restrict src, int sw, byte * restrict dst, int dw, int w, int h, int pad) - TILE(toct) - -void (*fz_decodetile)(fz_pixmap *pix, int skip, float *decode) = decodetile; -void (*fz_loadtile1)(byte*, int sw, byte*, int dw, int w, int h, int pad) = loadtile1; -void (*fz_loadtile2)(byte*, int sw, byte*, int dw, int w, int h, int pad) = loadtile2; -void (*fz_loadtile4)(byte*, int sw, byte*, int dw, int w, int h, int pad) = loadtile4; -void (*fz_loadtile8)(byte*, int sw, byte*, int dw, int w, int h, int pad) = loadtile8; - diff --git a/raster/meshdraw.c b/raster/meshdraw.c deleted file mode 100644 index abdcaaa1..00000000 --- a/raster/meshdraw.c +++ /dev/null @@ -1,408 +0,0 @@ -#include "fitz-base.h" -#include "fitz-world.h" -#include "fitz-draw.h" - -/* - * polygon clipping - */ - -enum { IN, OUT, ENTER, LEAVE }; -enum { MAXV = 3 + 4 }; -enum { MAXN = 2 + FZ_MAXCOLORS }; - -static int clipx(float val, int ismax, float *v1, float *v2, int n) -{ - float t; - int i; - int v1o = ismax ? v1[0] > val : v1[0] < val; - int v2o = ismax ? v2[0] > val : v2[0] < val; - if (v1o + v2o == 0) - return IN; - if (v1o + v2o == 2) - return OUT; - if (v2o) - { - t = (val - v1[0]) / (v2[0] - v1[0]); - v2[0] = val; - v2[1] = v1[1] + t * (v2[1] - v1[1]); - for (i = 2; i < n; i++) - v2[i] = v1[i] + t * (v2[i] - v1[i]); - return LEAVE; - } - else - { - t = (val - v2[0]) / (v1[0] - v2[0]); - v1[0] = val; - v1[1] = v2[1] + t * (v1[1] - v2[1]); - for (i = 2; i < n; i++) - v1[i] = v2[i] + t * (v1[i] - v2[i]); - return ENTER; - } -} - -static int clipy(float val, int ismax, float *v1, float *v2, int n) -{ - float t; - int i; - int v1o = ismax ? v1[1] > val : v1[1] < val; - int v2o = ismax ? v2[1] > val : v2[1] < val; - if (v1o + v2o == 0) - return IN; - if (v1o + v2o == 2) - return OUT; - if (v2o) - { - t = (val - v1[1]) / (v2[1] - v1[1]); - v2[0] = v1[0] + t * (v2[0] - v1[0]); - v2[1] = val; - for (i = 2; i < n; i++) - v2[i] = v1[i] + t * (v2[i] - v1[i]); - return LEAVE; - } - else - { - t = (val - v2[1]) / (v1[1] - v2[1]); - v1[0] = v2[0] + t * (v1[0] - v2[0]); - v1[1] = val; - for (i = 2; i < n; i++) - v1[i] = v2[i] + t * (v1[i] - v2[i]); - return ENTER; - } -} - -static inline void copyvert(float *dst, float *src, int n) -{ - while (n--) - *dst++ = *src++; -} - -static int clippoly(float src[MAXV][MAXN], - float dst[MAXV][MAXN], int len, int n, - float val, int isy, int ismax) -{ - float cv1[MAXN]; - float cv2[MAXN]; - int v1, v2, cp; - int r; - - v1 = len - 1; - cp = 0; - - for (v2 = 0; v2 < len; v2++) - { - copyvert(cv1, src[v1], n); - copyvert(cv2, src[v2], n); - - if (isy) - r = clipy(val, ismax, cv1, cv2, n); - else - r = clipx(val, ismax, cv1, cv2, n); - - switch (r) - { - case IN: - copyvert(dst[cp++], cv2, n); - break; - case OUT: - break; - case LEAVE: - copyvert(dst[cp++], cv2, n); - break; - case ENTER: - copyvert(dst[cp++], cv1, n); - copyvert(dst[cp++], cv2, n); - break; - } - v1 = v2; - } - - return cp; -} - -/* - * gouraud shaded polygon scan conversion - */ - -static inline void -drawscan(fz_pixmap *pix, int y, int x1, int x2, int *v1, int *v2, int n) -{ - unsigned char *p = pix->samples + ((y - pix->y) * pix->w + (x1 - pix->x)) * pix->n; - int v[FZ_MAXCOLORS]; - int dv[FZ_MAXCOLORS]; - int w = x2 - x1; - int k; - - assert(w >= 0); - assert(y >= pix->y); - assert(y < pix->y + pix->h); - assert(x1 >= pix->x); - assert(x2 <= pix->x + pix->w); - - if (w == 0) - return; - - for (k = 0; k < n; k++) - { - v[k] = v1[k]; - dv[k] = (v2[k] - v1[k]) / w; - } - - while (w--) - { - *p++ = 255; - for (k = 0; k < n; k++) - { - *p++ = v[k] >> 16; - v[k] += dv[k]; - } - } -} - -static inline int -findnext(int gel[MAXV][MAXN], int len, int a, int *s, int *e, int d) -{ - int b; - - while (1) - { - b = a + d; - if (b == len) - b = 0; - if (b == -1) - b = len - 1; - - if (gel[b][1] == gel[a][1]) - { - a = b; - continue; - } - - if (gel[b][1] > gel[a][1]) - { - *s = a; - *e = b; - return 0; - } - - return 1; - } -} - -static inline void -loadedge(int gel[MAXV][MAXN], int s, int e, int *ael, int *del, int n) -{ - int swp, k, dy; - - if (gel[s][1] > gel[s][1]) - { - swp = s; s = e; e = swp; - } - - dy = gel[e][1] - gel[s][1]; - - ael[0] = gel[s][0]; - del[0] = (gel[e][0] - gel[s][0]) / dy; - for (k = 2; k < n; k++) - { - ael[k] = gel[s][k]; - del[k] = (gel[e][k] - gel[s][k]) / dy; - } -} - -static inline void -stepedge(int *ael, int *del, int n) -{ - int k; - ael[0] += del[0]; - for (k = 2; k < n; k++) - ael[k] += del[k]; -} - -void -fz_drawtriangle(fz_pixmap *pix, float *av, float *bv, float *cv, int n) -{ - float poly[MAXV][MAXN]; - float temp[MAXV][MAXN]; - float cx0 = pix->x; - float cy0 = pix->y; - float cx1 = pix->x + pix->w; - float cy1 = pix->y + pix->h; - - int gel[MAXV][MAXN]; - int ael[2][MAXN]; - int del[2][MAXN]; - int y, s0, s1, e0, e1; - int top, bot, len; - - int i, k; - - copyvert(poly[0], av, n); - copyvert(poly[1], bv, n); - copyvert(poly[2], cv, n); - - len = clippoly(poly, temp, 3, n, cx0, 0, 0); - len = clippoly(temp, poly, len, n, cx1, 0, 1); - len = clippoly(poly, temp, len, n, cy0, 1, 0); - len = clippoly(temp, poly, len, n, cy1, 1, 1); - - if (len < 3) - return; - - for (i = 0; i < len; i++) - { - gel[i][0] = fz_floor(poly[i][0] + 0.5) * 65536; /* trunc and fix */ - gel[i][1] = fz_floor(poly[i][1] + 0.5); /* y is not fixpoint */ - for (k = 2; k < n; k++) - gel[i][k] = poly[i][k] * 65536; /* fix with precision */ - } - - top = bot = 0; - for (i = 0; i < len; i++) - { - if (gel[i][1] < gel[top][1]) - top = i; - if (gel[i][1] > gel[bot][1]) - bot = i; - } - - if (gel[bot][1] - gel[top][1] == 0) - return; - - y = gel[top][1]; - - if (findnext(gel, len, top, &s0, &e0, 1)) - return; - if (findnext(gel, len, top, &s1, &e1, -1)) - return; - - loadedge(gel, s0, e0, ael[0], del[0], n); - loadedge(gel, s1, e1, ael[1], del[1], n); - - while (1) - { - int x0 = ael[0][0] >> 16; - int x1 = ael[1][0] >> 16; - - if (ael[0][0] < ael[1][0]) - drawscan(pix, y, x0, x1, ael[0]+2, ael[1]+2, n-2); - else - drawscan(pix, y, x1, x0, ael[1]+2, ael[0]+2, n-2); - - stepedge(ael[0], del[0], n); - stepedge(ael[1], del[1], n); - y ++; - - if (y >= gel[e0][1]) - { - if (findnext(gel, len, e0, &s0, &e0, 1)) - return; - loadedge(gel, s0, e0, ael[0], del[0], n); - } - - if (y >= gel[e1][1]) - { - if (findnext(gel, len, e1, &s1, &e1, -1)) - return; - loadedge(gel, s1, e1, ael[1], del[1], n); - } - } -} - -/* - * mesh drawing - */ - -fz_error * -fz_rendershade(fz_shade *shade, fz_matrix ctm, fz_colorspace *destcs, fz_pixmap *dest) -{ - unsigned char clut[256][3]; - unsigned char *s, *d; - fz_error *error; - fz_pixmap *temp; - float rgb[3]; - float tri[3][MAXN]; - fz_point p; - int i, j, k, n; - - assert(dest->n == 4); - - ctm = fz_concat(shade->matrix, ctm); - - if (shade->usefunction) - { - n = 3; - error = fz_newpixmap(&temp, dest->x, dest->y, dest->w, dest->h, 2); - if (error) - return error; - } - else if (shade->cs != destcs) - { - n = 2 + shade->cs->n; - error = fz_newpixmap(&temp, dest->x, dest->y, dest->w, dest->h, - shade->cs->n + 1); - if (error) - return error; - } - else - { - n = 2 + shade->cs->n; - temp = dest; - } - - fz_clearpixmap(temp); - - for (i = 0; i < shade->meshlen; i++) - { - for (k = 0; k < 3; k++) - { - p.x = shade->mesh[(i * 3 + k) * n + 0]; - p.y = shade->mesh[(i * 3 + k) * n + 1]; - p = fz_transformpoint(ctm, p); - if (isnan(p.y) || isnan(p.x)) // How is this happening? - goto baddata; - tri[k][0] = p.x; - tri[k][1] = p.y; - for (j = 2; j < n; j++) - tri[k][j] = shade->mesh[( i * 3 + k) * n + j] * 255; - } - fz_drawtriangle(temp, tri[0], tri[1], tri[2], n); - baddata: - ; - } - - if (shade->usefunction) - { - for (i = 0; i < 256; i++) - { - fz_convertcolor(shade->cs, shade->function[i], destcs, rgb); - clut[i][0] = rgb[0] * 255; - clut[i][1] = rgb[1] * 255; - clut[i][2] = rgb[2] * 255; - } - - n = temp->w * temp->h; - s = temp->samples; - d = dest->samples; - - while (n--) - { - d[0] = s[0]; - d[1] = fz_mul255(s[0], clut[s[1]][0]); - d[2] = fz_mul255(s[0], clut[s[1]][1]); - d[3] = fz_mul255(s[0], clut[s[1]][2]); - s += 2; - d += 4; - } - - fz_droppixmap(temp); - } - - else if (shade->cs != destcs) - { - fz_convertpixmap(shade->cs, temp, destcs, dest); - fz_droppixmap(temp); - } - - return fz_okay; -} - diff --git a/raster/pathfill.c b/raster/pathfill.c deleted file mode 100644 index 3040e6a3..00000000 --- a/raster/pathfill.c +++ /dev/null @@ -1,134 +0,0 @@ -#include "fitz-base.h" -#include "fitz-world.h" -#include "fitz-draw.h" - -static fz_error * -line(fz_gel *gel, fz_matrix *ctm, float x0, float y0, float x1, float y1) -{ - float tx0 = ctm->a * x0 + ctm->c * y0 + ctm->e; - float ty0 = ctm->b * x0 + ctm->d * y0 + ctm->f; - float tx1 = ctm->a * x1 + ctm->c * y1 + ctm->e; - float ty1 = ctm->b * x1 + ctm->d * y1 + ctm->f; - return fz_insertgel(gel, tx0, ty0, tx1, ty1); -} - -static fz_error * -bezier(fz_gel *gel, fz_matrix *ctm, float flatness, - float xa, float ya, - float xb, float yb, - float xc, float yc, - float xd, float yd) -{ - fz_error *error; - float dmax; - float xab, yab; - float xbc, ybc; - float xcd, ycd; - float xabc, yabc; - float xbcd, ybcd; - float xabcd, yabcd; - - /* termination check */ - dmax = ABS(xa - xb); - dmax = MAX(dmax, ABS(ya - yb)); - dmax = MAX(dmax, ABS(xd - xc)); - dmax = MAX(dmax, ABS(yd - yc)); - if (dmax < flatness) - return line(gel, ctm, xa, ya, xd, yd); - - xab = xa + xb; - yab = ya + yb; - xbc = xb + xc; - ybc = yb + yc; - xcd = xc + xd; - ycd = yc + yd; - - xabc = xab + xbc; - yabc = yab + ybc; - xbcd = xbc + xcd; - ybcd = ybc + ycd; - - xabcd = xabc + xbcd; - yabcd = yabc + ybcd; - - xab *= 0.5f; yab *= 0.5f; - xbc *= 0.5f; ybc *= 0.5f; - xcd *= 0.5f; ycd *= 0.5f; - - xabc *= 0.25f; yabc *= 0.25f; - xbcd *= 0.25f; ybcd *= 0.25f; - - xabcd *= 0.125f; yabcd *= 0.125f; - - error = bezier(gel, ctm, flatness, xa, ya, xab, yab, xabc, yabc, xabcd, yabcd); - if (error) - return error; - return bezier(gel, ctm, flatness, xabcd, yabcd, xbcd, ybcd, xcd, ycd, xd, yd); -} - -fz_error * -fz_fillpath(fz_gel *gel, fz_pathnode *path, fz_matrix ctm, float flatness) -{ - fz_error *error; - float x1, y1, x2, y2, x3, y3; - float cx = 0; - float cy = 0; - float bx = 0; - float by = 0; - int i = 0; - - while (i < path->len) - { - switch (path->els[i++].k) - { - case FZ_MOVETO: - x1 = path->els[i++].v; - y1 = path->els[i++].v; - cx = bx = x1; - cy = by = y1; - break; - - case FZ_LINETO: - x1 = path->els[i++].v; - y1 = path->els[i++].v; - error = line(gel, &ctm, cx, cy, x1, y1); - if (error) - return error; - cx = x1; - cy = y1; - break; - - case FZ_CURVETO: - x1 = path->els[i++].v; - y1 = path->els[i++].v; - x2 = path->els[i++].v; - y2 = path->els[i++].v; - x3 = path->els[i++].v; - y3 = path->els[i++].v; - error = bezier(gel, &ctm, flatness, cx, cy, x1, y1, x2, y2, x3, y3); - if (error) - return error; - cx = x3; - cy = y3; - break; - - case FZ_CLOSEPATH: - error = line(gel, &ctm, cx, cy, bx, by); - if (error) - return error; - cx = bx; - cy = by; - break; - } - } - - if (i && (cx != bx || cy != by)) - { - error = line(gel, &ctm, cx, cy, bx, by); - if (error) - return error; - } - - return fz_okay; -} - diff --git a/raster/pathscan.c b/raster/pathscan.c deleted file mode 100644 index 0ea46502..00000000 --- a/raster/pathscan.c +++ /dev/null @@ -1,531 +0,0 @@ -#include "fitz-base.h" -#include "fitz-world.h" -#include "fitz-draw.h" - -enum { HSCALE = 17, VSCALE = 15, SF = 1 }; - -/* - * Global Edge List -- list of straight path segments for scan conversion - * - * Stepping along the edges is with bresenham's line algorithm. - * - * See Mike Abrash -- Graphics Programming Black Book (notably chapter 40) - */ - -fz_error * -fz_newgel(fz_gel **gelp) -{ - fz_gel *gel; - - gel = *gelp = fz_malloc(sizeof(fz_gel)); - if (!gel) - return fz_outofmem; - - gel->edges = nil; - - gel->cap = 512; - gel->len = 0; - gel->edges = fz_malloc(sizeof(fz_edge) * gel->cap); - if (!gel->edges) { - fz_free(gel); - return fz_outofmem; - } - - gel->clip.x0 = gel->clip.y0 = INT_MAX; - gel->clip.x1 = gel->clip.y1 = INT_MIN; - - gel->bbox.x0 = gel->bbox.y0 = INT_MAX; - gel->bbox.x1 = gel->bbox.y1 = INT_MIN; - - return fz_okay; -} - -void -fz_resetgel(fz_gel *gel, fz_irect clip) -{ - if (fz_isinfiniterect(clip)) - { - gel->clip.x0 = gel->clip.y0 = INT_MAX; - gel->clip.x1 = gel->clip.y1 = INT_MIN; - } - else { - gel->clip.x0 = clip.x0 * HSCALE; - gel->clip.x1 = clip.x1 * HSCALE; - gel->clip.y0 = clip.y0 * VSCALE; - gel->clip.y1 = clip.y1 * VSCALE; - } - - gel->bbox.x0 = gel->bbox.y0 = INT_MAX; - gel->bbox.x1 = gel->bbox.y1 = INT_MIN; - - gel->len = 0; -} - -void -fz_dropgel(fz_gel *gel) -{ - fz_free(gel->edges); - fz_free(gel); -} - -fz_irect -fz_boundgel(fz_gel *gel) -{ - fz_irect bbox; - bbox.x0 = fz_idiv(gel->bbox.x0, HSCALE); - bbox.y0 = fz_idiv(gel->bbox.y0, VSCALE); - bbox.x1 = fz_idiv(gel->bbox.x1, HSCALE) + 1; - bbox.y1 = fz_idiv(gel->bbox.y1, VSCALE) + 1; - return bbox; -} - -enum { INSIDE, OUTSIDE, LEAVE, ENTER }; - -#define cliplerpy(v,m,x0,y0,x1,y1,t) cliplerpx(v,m,y0,x0,y1,x1,t) - -static int -cliplerpx(int val, int m, int x0, int y0, int x1, int y1, int *out) -{ - int v0out = m ? x0 > val : x0 < val; - int v1out = m ? x1 > val : x1 < val; - - if (v0out + v1out == 0) - return INSIDE; - - if (v0out + v1out == 2) - return OUTSIDE; - - if (v1out) - { - *out = y0 + (y1 - y0) * (val - x0) / (x1 - x0); - return LEAVE; - } - - else - { - *out = y1 + (y0 - y1) * (val - x1) / (x0 - x1); - return ENTER; - } -} - -fz_error * -fz_insertgel(fz_gel *gel, float fx0, float fy0, float fx1, float fy1) -{ - fz_edge *edge; - int dx, dy; - int winding; - int width; - int tmp; - int v; - int d; - - int x0 = fz_floor(fx0 * HSCALE); - int y0 = fz_floor(fy0 * VSCALE); - int x1 = fz_floor(fx1 * HSCALE); - int y1 = fz_floor(fy1 * VSCALE); - - d = cliplerpy(gel->clip.y0, 0, x0, y0, x1, y1, &v); - if (d == OUTSIDE) return fz_okay; - if (d == LEAVE) { y1 = gel->clip.y0; x1 = v; } - if (d == ENTER) { y0 = gel->clip.y0; x0 = v; } - - d = cliplerpy(gel->clip.y1, 1, x0, y0, x1, y1, &v); - if (d == OUTSIDE) return fz_okay; - if (d == LEAVE) { y1 = gel->clip.y1; x1 = v; } - if (d == ENTER) { y0 = gel->clip.y1; x0 = v; } - - if (y0 == y1) - return fz_okay; - - if (y0 > y1) { - winding = -1; - tmp = x0; x0 = x1; x1 = tmp; - tmp = y0; y0 = y1; y1 = tmp; - } - else - winding = 1; - - if (x0 < gel->bbox.x0) gel->bbox.x0 = x0; - if (x0 > gel->bbox.x1) gel->bbox.x1 = x0; - if (x1 < gel->bbox.x0) gel->bbox.x0 = x1; - if (x1 > gel->bbox.x1) gel->bbox.x1 = x1; - - if (y0 < gel->bbox.y0) gel->bbox.y0 = y0; - if (y1 > gel->bbox.y1) gel->bbox.y1 = y1; - - if (gel->len + 1 == gel->cap) { - int newcap = gel->cap + 512; - fz_edge *newedges = fz_realloc(gel->edges, sizeof(fz_edge) * newcap); - if (!newedges) - return fz_outofmem; - gel->cap = newcap; - gel->edges = newedges; - } - - edge = &gel->edges[gel->len++]; - - dy = y1 - y0; - dx = x1 - x0; - width = dx < 0 ? -dx : dx; - - edge->xdir = dx > 0 ? 1 : -1; - edge->ydir = winding; - edge->x = x0; - edge->y = y0; - edge->h = dy; - edge->adjdown = dy; - - /* initial error term going l->r and r->l */ - if (dx >= 0) - edge->e = 0; - else - edge->e = -dy + 1; - - /* y-major edge */ - if (dy >= width) { - edge->xmove = 0; - edge->adjup = width; - } - - /* x-major edge */ - else { - edge->xmove = (width / dy) * edge->xdir; - edge->adjup = width % dy; - } - - return fz_okay; -} - -void -fz_sortgel(fz_gel *gel) -{ - fz_edge *a = gel->edges; - int n = gel->len; - - int h, i, k; - fz_edge t; - - h = 1; - if (n < 14) { - h = 1; - } - else { - while (h < n) - h = 3 * h + 1; - h /= 3; - h /= 3; - } - - while (h > 0) - { - for (i = 0; i < n; i++) { - t = a[i]; - k = i - h; - /* TODO: sort on y major, x minor */ - while (k >= 0 && a[k].y > t.y) { - a[k + h] = a[k]; - k -= h; - } - a[k + h] = t; - } - - h /= 3; - } -} - -/* - * Active Edge List -- keep track of active edges while sweeping - */ - -fz_error * -fz_newael(fz_ael **aelp) -{ - fz_ael *ael; - - ael = *aelp = fz_malloc(sizeof(fz_ael)); - if (!ael) - return fz_outofmem; - - ael->cap = 64; - ael->len = 0; - ael->edges = fz_malloc(sizeof(fz_edge*) * ael->cap); - if (!ael->edges) { - fz_free(ael); - return fz_outofmem; - } - - return fz_okay; -} - -void -fz_dropael(fz_ael *ael) -{ - fz_free(ael->edges); - fz_free(ael); -} - -static inline void -sortael(fz_edge **a, int n) -{ - int h, i, k; - fz_edge *t; - - h = 1; - if (n < 14) { - h = 1; - } - else { - while (h < n) - h = 3 * h + 1; - h /= 3; - h /= 3; - } - - while (h > 0) - { - for (i = 0; i < n; i++) { - t = a[i]; - k = i - h; - while (k >= 0 && a[k]->x > t->x) { - a[k + h] = a[k]; - k -= h; - } - a[k + h] = t; - } - - h /= 3; - } -} - -static fz_error * -insertael(fz_ael *ael, fz_gel *gel, int y, int *e) -{ - /* insert edges that start here */ - while (*e < gel->len && gel->edges[*e].y == y) { - if (ael->len + 1 == ael->cap) { - int newcap = ael->cap + 64; - fz_edge **newedges = fz_realloc(ael->edges, sizeof(fz_edge*) * newcap); - if (!newedges) - return fz_outofmem; - ael->edges = newedges; - ael->cap = newcap; - } - ael->edges[ael->len++] = &gel->edges[(*e)++]; - } - - /* shell-sort the edges by increasing x */ - sortael(ael->edges, ael->len); - - return fz_okay; -} - -static void -advanceael(fz_ael *ael) -{ - fz_edge *edge; - int i = 0; - - while (i < ael->len) - { - edge = ael->edges[i]; - - edge->h --; - - /* terminator! */ - if (edge->h == 0) { - ael->edges[i] = ael->edges[--ael->len]; - } - - else { - edge->x += edge->xmove; - edge->e += edge->adjup; - if (edge->e > 0) { - edge->x += edge->xdir; - edge->e -= edge->adjdown; - } - i ++; - } - } -} - -/* - * Scan convert - */ - -static inline void -addspan(unsigned char *list, int x0, int x1, int xofs) -{ - int x0pix, x0sub; - int x1pix, x1sub; - - if (x0 == x1) - return; - - /* x between 0 and width of bbox */ - x0 -= xofs; - x1 -= xofs; - - x0pix = x0 / HSCALE; - x0sub = x0 % HSCALE; - x1pix = x1 / HSCALE; - x1sub = x1 % HSCALE; - - if (x0pix == x1pix) - { - list[x0pix] += x1sub - x0sub; - list[x0pix+1] += x0sub - x1sub; - } - - else - { - list[x0pix] += HSCALE - x0sub; - list[x0pix+1] += x0sub; - list[x1pix] += x1sub - HSCALE; - list[x1pix+1] += -x1sub; - } -} - -static inline void -nonzerowinding(fz_ael *ael, unsigned char *list, int xofs) -{ - int winding = 0; - int x = 0; - int i; - for (i = 0; i < ael->len; i++) - { - if (!winding && (winding + ael->edges[i]->ydir)) - x = ael->edges[i]->x; - if (winding && !(winding + ael->edges[i]->ydir)) - addspan(list, x, ael->edges[i]->x, xofs); - winding += ael->edges[i]->ydir; - } -} - -static inline void -evenodd(fz_ael *ael, unsigned char *list, int xofs) -{ - int even = 0; - int x = 0; - int i; - for (i = 0; i < ael->len; i++) - { - if (!even) - x = ael->edges[i]->x; - else - addspan(list, x, ael->edges[i]->x, xofs); - even = !even; - } -} - -static inline void toalpha(unsigned char *list, int n) -{ - int d = 0; - while (n--) - { - d += *list; - *list++ = d; - } -} - -static inline void blit(fz_pixmap *pix, int x, int y, - unsigned char *list, int skipx, int len, - unsigned char *argb, int over) -{ - unsigned char *dst; - unsigned char cov; - - dst = pix->samples + ( (y - pix->y) * pix->w + (x - pix->x) ) * pix->n; - cov = 0; - - while (skipx--) - { - cov += *list; - *list = 0; - ++list; - } - - if (argb) - fz_path_w4i1o4(argb, list, cov, len, dst); - else if (over) - fz_path_1o1(list, cov, len, dst); - else - fz_path_1c1(list, cov, len, dst); -} - -fz_error * -fz_scanconvert(fz_gel *gel, fz_ael *ael, int eofill, fz_irect clip, - fz_pixmap *pix, unsigned char *argb, int over) -{ - fz_error *error; - unsigned char *deltas; - int y, e; - int yd, yc; - - int xmin = fz_idiv(gel->bbox.x0, HSCALE); - int xmax = fz_idiv(gel->bbox.x1, HSCALE) + 1; - - int xofs = xmin * HSCALE; - - int skipx = clip.x0 - xmin; - int clipn = clip.x1 - clip.x0; - - assert(clip.x0 >= xmin); - assert(clip.x1 <= xmax); - - if (gel->len == 0) - return fz_okay; - - deltas = fz_malloc(xmax - xmin + 1); - if (!deltas) - return fz_outofmem; - - memset(deltas, 0, xmax - xmin + 1); - - e = 0; - y = gel->edges[0].y; - yc = fz_idiv(y, VSCALE); - yd = yc; - - while (ael->len > 0 || e < gel->len) - { - yc = fz_idiv(y, VSCALE); - if (yc != yd) - { - if (yd >= clip.y0 && yd < clip.y1) - { - blit(pix, xmin + skipx, yd, deltas, skipx, clipn, argb, over); - } - } - yd = yc; - - error = insertael(ael, gel, y, &e); - if (error) { - fz_free(deltas); - return error; - } - - if (yd >= clip.y0 && yd < clip.y1) - { - if (eofill) - evenodd(ael, deltas, xofs); - else - nonzerowinding(ael, deltas, xofs); - } - - advanceael(ael); - - if (ael->len > 0) - y ++; - else if (e < gel->len) - y = gel->edges[e].y; - } - - if (yd >= clip.y0 && yd < clip.y1) - { - blit(pix, xmin + skipx, yd, deltas, skipx, clipn, argb, over); - } - - fz_free(deltas); - return fz_okay; -} - diff --git a/raster/pathstroke.c b/raster/pathstroke.c deleted file mode 100644 index d68f38ed..00000000 --- a/raster/pathstroke.c +++ /dev/null @@ -1,737 +0,0 @@ -#include "fitz-base.h" -#include "fitz-world.h" -#include "fitz-draw.h" - -enum { BUTT = 0, ROUND = 1, SQUARE = 2, MITER = 0, BEVEL = 2 }; - -struct sctx -{ - fz_gel *gel; - fz_matrix *ctm; - float flatness; - - int linecap; - int linejoin; - float linewidth; - float miterlimit; - fz_point beg[2]; - fz_point seg[2]; - int sn, bn; - int dot; - - fz_dash *dash; - int toggle; - int offset; - float phase; - fz_point cur; -}; - -static fz_error * -line(struct sctx *s, float x0, float y0, float x1, float y1) -{ - float tx0 = s->ctm->a * x0 + s->ctm->c * y0 + s->ctm->e; - float ty0 = s->ctm->b * x0 + s->ctm->d * y0 + s->ctm->f; - float tx1 = s->ctm->a * x1 + s->ctm->c * y1 + s->ctm->e; - float ty1 = s->ctm->b * x1 + s->ctm->d * y1 + s->ctm->f; - return fz_insertgel(s->gel, tx0, ty0, tx1, ty1); -} - -static fz_error * -arc(struct sctx *s, - float xc, float yc, - float x0, float y0, - float x1, float y1) -{ - fz_error *error; - float th0, th1, r; - float theta; - float ox, oy, nx, ny; - int n, i; - - r = fabs(s->linewidth); - theta = 2 * M_SQRT2 * sqrt(s->flatness / r); - th0 = atan2(y0, x0); - th1 = atan2(y1, x1); - - if (r > 0) - { - if (th0 < th1) - th0 += M_PI * 2; - n = ceil((th0 - th1) / theta); - } - else - { - if (th1 < th0) - th1 += M_PI * 2; - n = ceil((th1 - th0) / theta); - } - - ox = x0; - oy = y0; - for (i = 1; i < n; i++) - { - theta = th0 + (th1 - th0) * i / n; - nx = cos(theta) * r; - ny = sin(theta) * r; - error = line(s, xc + ox, yc + oy, xc + nx, yc + ny); - if (error) return error; - ox = nx; - oy = ny; - } - - error = line(s, xc + ox, yc + oy, xc + x1, yc + y1); - if (error) return error; - - return fz_okay; -} - -static fz_error * -linestroke(struct sctx *s, fz_point a, fz_point b) -{ - fz_error *error; - - float dx = b.x - a.x; - float dy = b.y - a.y; - float scale = s->linewidth / sqrt(dx * dx + dy * dy); - float dlx = dy * scale; - float dly = -dx * scale; - - error = line(s, a.x - dlx, a.y - dly, b.x - dlx, b.y - dly); - if (error) return error; - - error = line(s, b.x + dlx, b.y + dly, a.x + dlx, a.y + dly); - if (error) return error; - - return fz_okay; -} - -static fz_error * -linejoin(struct sctx *s, fz_point a, fz_point b, fz_point c) -{ - fz_error *error; - float miterlimit = s->miterlimit; - float linewidth = s->linewidth; - int linejoin = s->linejoin; - float dx0, dy0; - float dx1, dy1; - float dlx0, dly0; - float dlx1, dly1; - float dmx, dmy; - float dmr2; - float scale; - float cross; - - dx0 = b.x - a.x; - dy0 = b.y - a.y; - - dx1 = c.x - b.x; - dy1 = c.y - b.y; - - if (dx0 * dx0 + dy0 * dy0 < FLT_EPSILON) - return fz_okay; - if (dx1 * dx1 + dy1 * dy1 < FLT_EPSILON) - return fz_okay; - - scale = linewidth / sqrt(dx0 * dx0 + dy0 * dy0); - dlx0 = dy0 * scale; - dly0 = -dx0 * scale; - - scale = linewidth / sqrt(dx1 * dx1 + dy1 * dy1); - dlx1 = dy1 * scale; - dly1 = -dx1 * scale; - - cross = dx1 * dy0 - dx0 * dy1; - - dmx = (dlx0 + dlx1) * 0.5; - dmy = (dly0 + dly1) * 0.5; - dmr2 = dmx * dmx + dmy * dmy; - - if (cross * cross < FLT_EPSILON && dx0 * dx1 + dy0 * dy1 >= 0) - linejoin = BEVEL; - - if (linejoin == MITER) - if (dmr2 * miterlimit * miterlimit < linewidth * linewidth) - linejoin = BEVEL; - - if (linejoin == BEVEL) - { - error = line(s, b.x - dlx0, b.y - dly0, b.x - dlx1, b.y - dly1); - if (error) return error; - error = line(s, b.x + dlx1, b.y + dly1, b.x + dlx0, b.y + dly0); - if (error) return error; - } - - if (linejoin == MITER) - { - scale = linewidth * linewidth / dmr2; - dmx *= scale; - dmy *= scale; - - if (cross < 0) - { - error = line(s, b.x - dlx0, b.y - dly0, b.x - dlx1, b.y - dly1); - if (error) return error; - error = line(s, b.x + dlx1, b.y + dly1, b.x + dmx, b.y + dmy); - if (error) return error; - error = line(s, b.x + dmx, b.y + dmy, b.x + dlx0, b.y + dly0); - if (error) return error; - } - else - { - error = line(s, b.x + dlx1, b.y + dly1, b.x + dlx0, b.y + dly0); - if (error) return error; - error = line(s, b.x - dlx0, b.y - dly0, b.x - dmx, b.y - dmy); - if (error) return error; - error = line(s, b.x - dmx, b.y - dmy, b.x - dlx1, b.y - dly1); - if (error) return error; - } - } - - if (linejoin == ROUND) - { - if (cross < 0) - { - error = line(s, b.x - dlx0, b.y - dly0, b.x - dlx1, b.y - dly1); - if (error) return error; - error = arc(s, b.x, b.y, dlx1, dly1, dlx0, dly0); - if (error) return error; - } - else - { - error = line(s, b.x + dlx1, b.y + dly1, b.x + dlx0, b.y + dly0); - if (error) return error; - error = arc(s, b.x, b.y, -dlx0, -dly0, -dlx1, -dly1); - if (error) return error; - } - } - - return fz_okay; -} - -static fz_error * -linecap(struct sctx *s, fz_point a, fz_point b) -{ - fz_error *error; - float flatness = s->flatness; - float linewidth = s->linewidth; - int linecap = s->linecap; - - float dx = b.x - a.x; - float dy = b.y - a.y; - - float scale = linewidth / sqrt(dx * dx + dy * dy); - float dlx = dy * scale; - float dly = -dx * scale; - - if (linecap == BUTT) - return line(s, b.x - dlx, b.y - dly, b.x + dlx, b.y + dly); - - if (linecap == ROUND) - { - int i; - int n = ceil(M_PI / (2.0 * M_SQRT2 * sqrt(flatness / linewidth))); - float ox = b.x - dlx; - float oy = b.y - dly; - for (i = 1; i < n; i++) - { - float theta = M_PI * i / n; - float cth = cos(theta); - float sth = sin(theta); - float nx = b.x - dlx * cth - dly * sth; - float ny = b.y - dly * cth + dlx * sth; - error = line(s, ox, oy, nx, ny); - if (error) return error; - ox = nx; - oy = ny; - } - error = line(s, ox, oy, b.x + dlx, b.y + dly); - if (error) return error; - } - - if (linecap == SQUARE) - { - error = line(s, b.x - dlx, b.y - dly, - b.x - dlx - dly, - b.y - dly + dlx); - if (error) return error; - error = line(s, b.x - dlx - dly, - b.y - dly + dlx, - b.x + dlx - dly, - b.y + dly + dlx); - if (error) return error; - error = line(s, b.x + dlx - dly, - b.y + dly + dlx, - b.x + dlx, b.y + dly); - if (error) return error; - } - - return fz_okay; -} - -static fz_error * -linedot(struct sctx *s, fz_point a) -{ - fz_error *error; - float flatness = s->flatness; - float linewidth = s->linewidth; - int n = ceil(M_PI / (M_SQRT2 * sqrt(flatness / linewidth))); - float ox = a.x - linewidth; - float oy = a.y; - int i; - for (i = 1; i < n; i++) - { - float theta = M_PI * 2 * i / n; - float cth = cos(theta); - float sth = sin(theta); - float nx = a.x - cth * linewidth; - float ny = a.y + sth * linewidth; - error = line(s, ox, oy, nx, ny); - if (error) return error; - ox = nx; - oy = ny; - } - error = line(s, ox, oy, a.x - linewidth, a.y); - if (error) return error; - return fz_okay; -} - -static fz_error * -strokeflush(struct sctx *s) -{ - fz_error *error; - - if (s->sn == 2) - { - error = linecap(s, s->beg[1], s->beg[0]); - if (error) return error; - error = linecap(s, s->seg[0], s->seg[1]); - if (error) return error; - } - else if (s->dot) - { - error = linedot(s, s->beg[0]); - if (error) return error; - } - - s->dot = 0; - - return fz_okay; -} - -static fz_error * -strokemoveto(struct sctx *s, fz_point cur) -{ - fz_error *error; - - error = strokeflush(s); - if (error) return error; - - s->seg[0] = cur; - s->beg[0] = cur; - s->sn = 1; - s->bn = 1; - - return fz_okay; -} - -static fz_error * -strokelineto(struct sctx *s, fz_point cur) -{ - fz_error *error; - - float dx = cur.x - s->seg[s->sn-1].x; - float dy = cur.y - s->seg[s->sn-1].y; - - if (dx * dx + dy * dy < s->flatness * s->flatness * 0.25) - { - s->dot = 1; - return fz_okay; - } - - error = linestroke(s, s->seg[s->sn-1], cur); - if (error) return error; - - if (s->sn == 2) - { - error = linejoin(s, s->seg[0], s->seg[1], cur); - if (error) return error; - - s->seg[0] = s->seg[1]; - s->seg[1] = cur; - } - - if (s->sn == 1) - s->seg[s->sn++] = cur; - if (s->bn == 1) - s->beg[s->bn++] = cur; - - return fz_okay; -} - -static fz_error * -strokeclosepath(struct sctx *s) -{ - fz_error *error; - - if (s->sn == 2) - { - error = strokelineto(s, s->beg[0]); - if (error) return error; - - if (s->seg[1].x == s->beg[0].x && s->seg[1].y == s->beg[0].y) - error = linejoin(s, s->seg[0], s->beg[0], s->beg[1]); - else - error = linejoin(s, s->seg[1], s->beg[0], s->beg[1]); - if (error) return error; - } - - else if (s->dot) - { - error = linedot(s, s->beg[0]); - if (error) return error; - } - - s->bn = 0; - s->sn = 0; - s->dot = 0; - - return fz_okay; -} - -static fz_error * -strokebezier(struct sctx *s, - float xa, float ya, - float xb, float yb, - float xc, float yc, - float xd, float yd) -{ - fz_error *error; - float dmax; - float xab, yab; - float xbc, ybc; - float xcd, ycd; - float xabc, yabc; - float xbcd, ybcd; - float xabcd, yabcd; - - /* termination check */ - dmax = ABS(xa - xb); - dmax = MAX(dmax, ABS(ya - yb)); - dmax = MAX(dmax, ABS(xd - xc)); - dmax = MAX(dmax, ABS(yd - yc)); - if (dmax < s->flatness) { - fz_point p; - p.x = xd; - p.y = yd; - return strokelineto(s, p); - } - - xab = xa + xb; - yab = ya + yb; - xbc = xb + xc; - ybc = yb + yc; - xcd = xc + xd; - ycd = yc + yd; - - xabc = xab + xbc; - yabc = yab + ybc; - xbcd = xbc + xcd; - ybcd = ybc + ycd; - - xabcd = xabc + xbcd; - yabcd = yabc + ybcd; - - xab *= 0.5f; yab *= 0.5f; - xbc *= 0.5f; ybc *= 0.5f; - xcd *= 0.5f; ycd *= 0.5f; - - xabc *= 0.25f; yabc *= 0.25f; - xbcd *= 0.25f; ybcd *= 0.25f; - - xabcd *= 0.125f; yabcd *= 0.125f; - - error = strokebezier(s, xa, ya, xab, yab, xabc, yabc, xabcd, yabcd); - if (error) - return error; - - return strokebezier(s, xabcd, yabcd, xbcd, ybcd, xcd, ycd, xd, yd); -} - -fz_error * -fz_strokepath(fz_gel *gel, fz_pathnode *path, fz_matrix ctm, float flatness, float linewidth) -{ - fz_error *error; - struct sctx s; - fz_point p0, p1, p2, p3; - int i; - - s.gel = gel; - s.ctm = &ctm; - s.flatness = flatness; - - s.linecap = path->linecap; - s.linejoin = path->linejoin; - s.linewidth = linewidth * 0.5; /* hairlines use a different value from the path value */ - s.miterlimit = path->miterlimit; - s.sn = 0; - s.bn = 0; - s.dot = 0; - - i = 0; - - if (path->len > 0 && path->els[0].k != FZ_MOVETO) - return fz_throw("path must begin with moveto"); - - p0.x = p0.y = 0; /* FZ_MOVETO guarantees p0 to be set, silence compiler */ - - while (i < path->len) - { - switch (path->els[i++].k) - { - case FZ_MOVETO: - p1.x = path->els[i++].v; - p1.y = path->els[i++].v; - error = strokemoveto(&s, p1); - if (error) - return error; - p0 = p1; - break; - - case FZ_LINETO: - p1.x = path->els[i++].v; - p1.y = path->els[i++].v; - error = strokelineto(&s, p1); - if (error) - return error; - p0 = p1; - break; - - case FZ_CURVETO: - p1.x = path->els[i++].v; - p1.y = path->els[i++].v; - p2.x = path->els[i++].v; - p2.y = path->els[i++].v; - p3.x = path->els[i++].v; - p3.y = path->els[i++].v; - error = strokebezier(&s, p0.x, p0.y, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y); - if (error) - return error; - p0 = p3; - break; - - case FZ_CLOSEPATH: - error = strokeclosepath(&s); - if (error) - return error; - break; - } - } - - return strokeflush(&s); -} - -static fz_error * -dashmoveto(struct sctx *s, fz_point a) -{ - s->toggle = 1; - s->offset = 0; - s->phase = s->dash->phase; - - while (s->phase >= s->dash->array[s->offset]) - { - s->toggle = !s->toggle; - s->phase -= s->dash->array[s->offset]; - s->offset ++; - if (s->offset == s->dash->len) - s->offset = 0; - } - - s->cur = a; - - if (s->toggle) - return strokemoveto(s, a); - - return fz_okay; -} - -static fz_error * -dashlineto(struct sctx *s, fz_point b) -{ - fz_error *error; - float dx, dy; - float total, used, ratio; - fz_point a; - fz_point m; - - a = s->cur; - dx = b.x - a.x; - dy = b.y - a.y; - total = sqrt(dx * dx + dy * dy); - used = 0; - - while (total - used > s->dash->array[s->offset] - s->phase) - { - used += s->dash->array[s->offset] - s->phase; - ratio = used / total; - m.x = a.x + ratio * dx; - m.y = a.y + ratio * dy; - - if (s->toggle) - error = strokelineto(s, m); - else - error = strokemoveto(s, m); - if (error) - return error; - - s->toggle = !s->toggle; - s->phase = 0; - s->offset ++; - if (s->offset == s->dash->len) - s->offset = 0; - } - - s->phase += total - used; - - s->cur = b; - - if (s->toggle) - return strokelineto(s, b); - - return fz_okay; -} - -static fz_error * -dashbezier(struct sctx *s, - float xa, float ya, - float xb, float yb, - float xc, float yc, - float xd, float yd) -{ - fz_error *error; - float dmax; - float xab, yab; - float xbc, ybc; - float xcd, ycd; - float xabc, yabc; - float xbcd, ybcd; - float xabcd, yabcd; - - /* termination check */ - dmax = ABS(xa - xb); - dmax = MAX(dmax, ABS(ya - yb)); - dmax = MAX(dmax, ABS(xd - xc)); - dmax = MAX(dmax, ABS(yd - yc)); - if (dmax < s->flatness) { - fz_point p; - p.x = xd; - p.y = yd; - return dashlineto(s, p); - } - - xab = xa + xb; - yab = ya + yb; - xbc = xb + xc; - ybc = yb + yc; - xcd = xc + xd; - ycd = yc + yd; - - xabc = xab + xbc; - yabc = yab + ybc; - xbcd = xbc + xcd; - ybcd = ybc + ycd; - - xabcd = xabc + xbcd; - yabcd = yabc + ybcd; - - xab *= 0.5f; yab *= 0.5f; - xbc *= 0.5f; ybc *= 0.5f; - xcd *= 0.5f; ycd *= 0.5f; - - xabc *= 0.25f; yabc *= 0.25f; - xbcd *= 0.25f; ybcd *= 0.25f; - - xabcd *= 0.125f; yabcd *= 0.125f; - - error = dashbezier(s, xa, ya, xab, yab, xabc, yabc, xabcd, yabcd); - if (error) return error; - return dashbezier(s, xabcd, yabcd, xbcd, ybcd, xcd, ycd, xd, yd); -} - -fz_error * -fz_dashpath(fz_gel *gel, fz_pathnode *path, fz_matrix ctm, float flatness, float linewidth) -{ - fz_error *error; - struct sctx s; - fz_point p0, p1, p2, p3, beg; - int i; - - s.gel = gel; - s.ctm = &ctm; - s.flatness = flatness; - - s.linecap = path->linecap; - s.linejoin = path->linejoin; - s.linewidth = linewidth * 0.5; - s.miterlimit = path->miterlimit; - s.sn = 0; - s.bn = 0; - s.dot = 0; - - s.dash = path->dash; - s.toggle = 0; - s.offset = 0; - s.phase = 0; - - i = 0; - - if (path->len > 0 && path->els[0].k != FZ_MOVETO) - return fz_throw("path must begin with moveto"); - - p0.x = p0.y = 0; /* FZ_MOVETO guarantees p0 to be set, silence compiler */ - - while (i < path->len) - { - switch (path->els[i++].k) - { - case FZ_MOVETO: - p1.x = path->els[i++].v; - p1.y = path->els[i++].v; - error = dashmoveto(&s, p1); - if (error) - return error; - beg = p0 = p1; - break; - - case FZ_LINETO: - p1.x = path->els[i++].v; - p1.y = path->els[i++].v; - error = dashlineto(&s, p1); - if (error) - return error; - p0 = p1; - break; - - case FZ_CURVETO: - p1.x = path->els[i++].v; - p1.y = path->els[i++].v; - p2.x = path->els[i++].v; - p2.y = path->els[i++].v; - p3.x = path->els[i++].v; - p3.y = path->els[i++].v; - error = dashbezier(&s, p0.x, p0.y, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y); - if (error) - return error; - p0 = p3; - break; - - case FZ_CLOSEPATH: - error = dashlineto(&s, beg); - if (error) - return error; - break; - } - } - - return strokeflush(&s); -} - diff --git a/raster/pixmap.c b/raster/pixmap.c deleted file mode 100644 index 077009f8..00000000 --- a/raster/pixmap.c +++ /dev/null @@ -1,188 +0,0 @@ -#include "fitz-base.h" -#include "fitz-world.h" -#include "fitz-draw.h" - -fz_error * -fz_newpixmap(fz_pixmap **pixp, int x, int y, int w, int h, int n) -{ - fz_pixmap *pix; - - pix = *pixp = fz_malloc(sizeof(fz_pixmap)); - if (!pix) - return fz_outofmem; - - pix->x = x; - pix->y = y; - pix->w = w; - pix->h = h; - pix->n = n; - - pix->samples = fz_malloc(pix->w * pix->h * pix->n * sizeof(fz_sample)); - if (!pix->samples) { - fz_free(pix); - return fz_outofmem; - } - - return fz_okay; -} - -fz_error * -fz_newpixmapwithrect(fz_pixmap **pixp, fz_irect r, int n) -{ - return fz_newpixmap(pixp, - r.x0, r.y0, - r.x1 - r.x0, - r.y1 - r.y0, n); -} - -fz_error * -fz_newpixmapcopy(fz_pixmap **pixp, fz_pixmap *old) -{ - fz_error *error; - error = fz_newpixmap(pixp, old->x, old->y, old->w, old->h, old->n); - if (error) - return error; - memcpy((*pixp)->samples, old->samples, old->w * old->h * old->n); - return fz_okay; -} - -void -fz_droppixmap(fz_pixmap *pix) -{ - fz_free(pix->samples); - fz_free(pix); -} - -void -fz_clearpixmap(fz_pixmap *pix) -{ - memset(pix->samples, 0, pix->w * pix->h * pix->n * sizeof(fz_sample)); -} - -void -fz_gammapixmap(fz_pixmap *pix, float gamma) -{ - unsigned char table[256]; - int n = pix->w * pix->h * pix->n; - unsigned char *p = pix->samples; - int i; - for (i = 0; i < 256; i++) - table[i] = CLAMP(pow(i / 255.0, gamma) * 255.0, 0, 255); - while (n--) - { - *p = table[*p]; - p++; - } -} - -void -fz_debugpixmap(fz_pixmap *pix, char *prefix) -{ - static int counter = 0; - char colorname[40]; - char alphaname[40]; - FILE *color = NULL; - FILE *alpha = NULL; - int x, y; - - sprintf(alphaname, "%s-%04d-alpha.pgm", prefix, counter); - alpha = fopen(alphaname, "wb"); - if (!alpha) - goto cleanup; - - if (pix->n > 1) - { - if (pix->n > 2) - sprintf(colorname, "%s-%04d-color.ppm", prefix, counter); - else - sprintf(colorname, "%s-%04d-color.pgm", prefix, counter); - - color = fopen(colorname, "wb"); - if (!color) - goto cleanup; - } - - counter ++; - - if (pix->n == 5) - { - fprintf(alpha, "P5\n%d %d\n255\n", pix->w, pix->h); - fprintf(color, "P6\n%d %d\n255\n", pix->w, pix->h); - - for (y = 0; y < pix->h; y++) - { - for (x = 0; x < pix->w; x++) - { - int a = pix->samples[x * pix->n + y * pix->w * pix->n + 0]; - int cc = pix->samples[x * pix->n + y * pix->w * pix->n + 1]; - int mm = pix->samples[x * pix->n + y * pix->w * pix->n + 2]; - int yy = pix->samples[x * pix->n + y * pix->w * pix->n + 3]; - int kk = pix->samples[x * pix->n + y * pix->w * pix->n + 4]; - int r = 255 - MIN(cc + kk, 255); - int g = 255 - MIN(mm + kk, 255); - int b = 255 - MIN(yy + kk, 255); - fputc(a, alpha); - fputc(r, color); - fputc(g, color); - fputc(b, color); - } - } - } - - else if (pix->n == 4) - { - fprintf(alpha, "P5\n%d %d\n255\n", pix->w, pix->h); - fprintf(color, "P6\n%d %d\n255\n", pix->w, pix->h); - - for (y = 0; y < pix->h; y++) - { - for (x = 0; x < pix->w; x++) - { - int a = pix->samples[x * pix->n + y * pix->w * pix->n + 0]; - int r = pix->samples[x * pix->n + y * pix->w * pix->n + 1]; - int g = pix->samples[x * pix->n + y * pix->w * pix->n + 2]; - int b = pix->samples[x * pix->n + y * pix->w * pix->n + 3]; - fputc(a, alpha); - fputc(r, color); - fputc(g, color); - fputc(b, color); - } - } - } - - else if (pix->n == 2) - { - fprintf(alpha, "P5\n%d %d\n255\n", pix->w, pix->h); - fprintf(color, "P5\n%d %d\n255\n", pix->w, pix->h); - - for (y = 0; y < pix->h; y++) - { - for (x = 0; x < pix->w; x++) - { - int a = pix->samples[x * pix->n + y * pix->w * pix->n + 0]; - int g = pix->samples[x * pix->n + y * pix->w * pix->n + 1]; - fputc(a, alpha); - fputc(g, color); - } - } - } - - else if (pix->n == 1) - { - fprintf(alpha, "P5\n%d %d\n255\n", pix->w, pix->h); - - for (y = 0; y < pix->h; y++) - { - for (x = 0; x < pix->w; x++) - { - int g = pix->samples[x * pix->n + y * pix->w * pix->n + 0]; - fputc(g, alpha); - } - } - } - -cleanup: - if (alpha) fclose(alpha); - if (color) fclose(color); -} - diff --git a/raster/porterduff.c b/raster/porterduff.c deleted file mode 100644 index 8f2b9862..00000000 --- a/raster/porterduff.c +++ /dev/null @@ -1,361 +0,0 @@ -#include "fitz-base.h" -#include "fitz-world.h" -#include "fitz-draw.h" - -typedef unsigned char byte; - -/* - * Blend pixmap regions - */ - -/* dst = src over dst */ -static void -duff_non(byte * restrict sp0, int sw, int sn, byte * restrict dp0, int dw, int w0, int h) -{ - int k; - while (h--) - { - byte *sp = sp0; - byte *dp = dp0; - int w = w0; - while (w--) - { - byte sa = sp[0]; - byte ssa = 255 - sa; - for (k = 0; k < sn; k++) - { - dp[k] = sp[k] + fz_mul255(dp[k], ssa); - } - sp += sn; - dp += sn; - } - sp0 += sw; - dp0 += dw; - } -} - -/* dst = src in msk */ -static void -duff_nimcn(byte * restrict sp0, int sw, int sn, byte * restrict mp0, int mw, int mn, byte * restrict dp0, int dw, int w0, int h) -{ - int k; - while (h--) - { - byte *sp = sp0; - byte *mp = mp0; - byte *dp = dp0; - int w = w0; - while (w--) - { - byte ma = mp[0]; - for (k = 0; k < sn; k++) - dp[k] = fz_mul255(sp[k], ma); - sp += sn; - mp += mn; - dp += sn; - } - sp0 += sw; - mp0 += mw; - dp0 += dw; - } -} - -/* dst = src in msk over dst */ -static void -duff_nimon(byte * restrict sp0, int sw, int sn, byte * restrict mp0, int mw, int mn, byte * restrict dp0, int dw, int w0, int h) -{ - int k; - while (h--) - { - byte *sp = sp0; - byte *mp = mp0; - byte *dp = dp0; - int w = w0; - while (w--) - { - /* TODO: validate this */ - byte ma = mp[0]; - byte sa = fz_mul255(sp[0], ma); - byte ssa = 255 - sa; - for (k = 0; k < sn; k++) - { - dp[k] = fz_mul255(sp[k], ma) + fz_mul255(dp[k], ssa); - } - sp += sn; - mp += mn; - dp += sn; - } - sp0 += sw; - mp0 += mw; - dp0 += dw; - } -} - -static void duff_1o1(byte * restrict sp0, int sw, byte * restrict dp0, int dw, int w0, int h) -{ - /* duff_non(sp0, sw, 1, dp0, dw, w0, h); */ - while (h--) - { - byte *sp = sp0; - byte *dp = dp0; - int w = w0; - while (w--) - { - dp[0] = sp[0] + fz_mul255(dp[0], 255 - sp[0]); - sp ++; - dp ++; - } - sp0 += sw; - dp0 += dw; - } -} - -static void duff_4o4(byte *sp0, int sw, byte *dp0, int dw, int w0, int h) -{ - /* duff_non(sp0, sw, 4, dp0, dw, w0, h); */ - while (h--) - { - byte *sp = sp0; - byte *dp = dp0; - int w = w0; - while (w--) - { - byte ssa = 255 - sp[0]; - dp[0] = sp[0] + fz_mul255(dp[0], ssa); - dp[1] = sp[1] + fz_mul255(dp[1], ssa); - dp[2] = sp[2] + fz_mul255(dp[2], ssa); - dp[3] = sp[3] + fz_mul255(dp[3], ssa); - sp += 4; - dp += 4; - } - sp0 += sw; - dp0 += dw; - } -} - -static void duff_1i1c1(byte * restrict sp0, int sw, byte * restrict mp0, int mw, byte * restrict dp0, int dw, int w0, int h) -{ - /* duff_nimcn(sp0, sw, 1, mp0, mw, 1, dp0, dw, w0, h); */ - while (h--) - { - byte *sp = sp0; - byte *mp = mp0; - byte *dp = dp0; - int w = w0; - while (w--) - { - dp[0] = fz_mul255(sp[0], mp[0]); - sp ++; - mp ++; - dp ++; - } - sp0 += sw; - mp0 += mw; - dp0 += dw; - } -} - -static void duff_4i1c4(byte * restrict sp0, int sw, byte * restrict mp0, int mw, byte * restrict dp0, int dw, int w0, int h) -{ - /* duff_nimcn(sp0, sw, 4, mp0, mw, 1, dp0, dw, w0, h); */ - while (h--) - { - byte *sp = sp0; - byte *mp = mp0; - byte *dp = dp0; - int w = w0; - while (w--) - { - byte ma = mp[0]; - dp[0] = fz_mul255(sp[0], ma); - dp[1] = fz_mul255(sp[1], ma); - dp[2] = fz_mul255(sp[2], ma); - dp[3] = fz_mul255(sp[3], ma); - sp += 4; - mp += 1; - dp += 4; - } - sp0 += sw; - mp0 += mw; - dp0 += dw; - } -} - -static void duff_1i1o1(byte * restrict sp0, int sw, byte * restrict mp0, int mw, byte * restrict dp0, int dw, int w0, int h) -{ - /* duff_nimon(sp0, sw, 1, mp0, mw, 1, dp0, dw, w0, h); */ - while (h--) - { - byte *sp = sp0; - byte *mp = mp0; - byte *dp = dp0; - int w = w0; - while (w--) - { - byte ma = mp[0]; - byte sa = fz_mul255(sp[0], ma); - byte ssa = 255 - sa; - dp[0] = fz_mul255(sp[0], ma) + fz_mul255(dp[0], ssa); - sp ++; - mp ++; - dp ++; - } - sp0 += sw; - mp0 += mw; - dp0 += dw; - } -} - -static void duff_4i1o4(byte * restrict sp0, int sw, byte * restrict mp0, int mw, byte * restrict dp0, int dw, int w0, int h) -{ - /* duff_nimon(sp0, sw, 4, mp0, mw, 1, dp0, dw, w0, h); */ - while (h--) - { - byte *sp = sp0; - byte *mp = mp0; - byte *dp = dp0; - int w = w0; - while (w--) - { - byte ma = mp[0]; - byte sa = fz_mul255(sp[0], ma); - byte ssa = 255 - sa; - dp[0] = fz_mul255(sp[0], ma) + fz_mul255(dp[0], ssa); - dp[1] = fz_mul255(sp[1], ma) + fz_mul255(dp[1], ssa); - dp[2] = fz_mul255(sp[2], ma) + fz_mul255(dp[2], ssa); - dp[3] = fz_mul255(sp[3], ma) + fz_mul255(dp[3], ssa); - sp += 4; - mp += 1; - dp += 4; - } - sp0 += sw; - mp0 += mw; - dp0 += dw; - } -} - -/* - * Path and text masks - */ - -static void path_1c1(byte * restrict src, byte cov, int len, byte * restrict dst) -{ - while (len--) - { - cov += *src; *src = 0; src++; - *dst++ = cov; - } -} - -static void path_1o1(byte * restrict src, byte cov, int len, byte * restrict dst) -{ - while (len--) - { - cov += *src; *src = 0; src++; - dst[0] = cov + fz_mul255(dst[0], 255 - cov); - dst++; - } -} - -// With 4 In 1 Over 4 -static void path_w4i1o4(byte * restrict argb, byte * restrict src, byte cov, int len, byte * restrict dst) -{ - byte alpha = argb[0]; - byte r = argb[4]; - byte g = argb[5]; - byte b = argb[6]; - while (len--) - { - byte ca; - cov += *src; *src = 0; src++; - ca = fz_mul255(cov, alpha); - dst[0] = ca + fz_mul255(dst[0], 255 - ca); - dst[1] = fz_mul255((short)r - dst[1], ca) + dst[1]; - dst[2] = fz_mul255((short)g - dst[2], ca) + dst[2]; - dst[3] = fz_mul255((short)b - dst[3], ca) + dst[3]; - dst += 4; - } -} - -static void text_1c1(byte * restrict src0, int srcw, byte * restrict dst0, int dstw, int w0, int h) -{ - while (h--) - { - byte * restrict src = src0; - byte * restrict dst = dst0; - int w = w0; - while (w--) - { - *dst++ = *src++; - } - src0 += srcw; - dst0 += dstw; - } -} - -static void text_1o1(byte * restrict src0, int srcw, byte * restrict dst0, int dstw, int w0, int h) -{ - while (h--) - { - byte *src = src0; - byte *dst = dst0; - int w = w0; - while (w--) - { - dst[0] = src[0] + fz_mul255(dst[0], 255 - src[0]); - src++; - dst++; - } - src0 += srcw; - dst0 += dstw; - } -} - -static void text_w4i1o4(byte * restrict argb, byte * restrict src0, int srcw, byte * restrict dst0, int dstw, int w0, int h) -{ - unsigned char alpha = argb[0]; - unsigned char r = argb[4]; - unsigned char g = argb[5]; - unsigned char b = argb[6]; - while (h--) - { - byte *src = src0; - byte *dst = dst0; - int w = w0; - while (w--) - { - byte ca = fz_mul255(src[0], alpha); - dst[0] = ca + fz_mul255(dst[0], 255 - ca); - dst[1] = fz_mul255((short)r - dst[1], ca) + dst[1]; - dst[2] = fz_mul255((short)g - dst[2], ca) + dst[2]; - dst[3] = fz_mul255((short)b - dst[3], ca) + dst[3]; - src ++; - dst += 4; - } - src0 += srcw; - dst0 += dstw; - } -} - -/* - * ... and the function pointers - */ - -void (*fz_duff_non)(byte*,int,int,byte*,int,int,int) = duff_non; -void (*fz_duff_nimcn)(byte*,int,int,byte*,int,int,byte*,int,int,int) = duff_nimcn; -void (*fz_duff_nimon)(byte*,int,int,byte*,int,int,byte*,int,int,int) = duff_nimon; -void (*fz_duff_1o1)(byte*,int,byte*,int,int,int) = duff_1o1; -void (*fz_duff_4o4)(byte*,int,byte*,int,int,int) = duff_4o4; -void (*fz_duff_1i1c1)(byte*,int,byte*,int,byte*,int,int,int) = duff_1i1c1; -void (*fz_duff_4i1c4)(byte*,int,byte*,int,byte*,int,int,int) = duff_4i1c4; -void (*fz_duff_1i1o1)(byte*,int,byte*,int,byte*,int,int,int) = duff_1i1o1; -void (*fz_duff_4i1o4)(byte*,int,byte*,int,byte*,int,int,int) = duff_4i1o4; - -void (*fz_path_1c1)(byte*,byte,int,byte*) = path_1c1; -void (*fz_path_1o1)(byte*,byte,int,byte*) = path_1o1; -void (*fz_path_w4i1o4)(byte*,byte*,byte,int,byte*) = path_w4i1o4; - -void (*fz_text_1c1)(byte*,int,byte*,int,int,int) = text_1c1; -void (*fz_text_1o1)(byte*,int,byte*,int,int,int) = text_1o1; -void (*fz_text_w4i1o4)(byte*,byte*,int,byte*,int,int,int) = text_w4i1o4; - diff --git a/raster/render.c b/raster/render.c deleted file mode 100644 index 90ead6a7..00000000 --- a/raster/render.c +++ /dev/null @@ -1,969 +0,0 @@ -#include "fitz-base.h" -#include "fitz-world.h" -#include "fitz-draw.h" - -#ifdef _MSC_VER -#define noDebug printf -#ifndef DEBUG -#define DEBUG -#endif -#else -#define noDEBUG(args...) printf(args) -#ifndef DEBUG -#define DEBUG(args...) -#endif -#endif -#define QUANT(x,a) (((int)((x) * (a))) / (a)) -#define HSUBPIX 5.0 -#define VSUBPIX 5.0 - -#define FNONE 0 -#define FOVER 1 -#define FRGB 4 - -static fz_error *rendernode(fz_renderer *gc, fz_node *node, fz_matrix ctm); - -fz_error * -fz_newrenderer(fz_renderer **gcp, fz_colorspace *pcm, int maskonly, int gcmem) -{ - fz_error *error; - fz_renderer *gc; - - gc = fz_malloc(sizeof(fz_renderer)); - if (!gc) - return fz_outofmem; - - gc->maskonly = maskonly; - gc->model = pcm; - gc->cache = nil; - gc->gel = nil; - gc->ael = nil; - - error = fz_newglyphcache(&gc->cache, gcmem / 24, gcmem); - if (error) - goto cleanup; - - error = fz_newgel(&gc->gel); - if (error) - goto cleanup; - - error = fz_newael(&gc->ael); - if (error) - goto cleanup; - - gc->dest = nil; - gc->over = nil; - gc->argb[0] = 255; - gc->argb[1] = 0; - gc->argb[2] = 0; - gc->argb[3] = 0; - gc->argb[4] = 0; - gc->argb[5] = 0; - gc->argb[6] = 0; - gc->flag = 0; - - *gcp = gc; - return fz_okay; - -cleanup: - if (gc->model) fz_dropcolorspace(gc->model); - if (gc->cache) fz_dropglyphcache(gc->cache); - if (gc->gel) fz_dropgel(gc->gel); - if (gc->ael) fz_dropael(gc->ael); - fz_free(gc); - return error; -} - -void -fz_droprenderer(fz_renderer *gc) -{ - if (gc->dest) fz_droppixmap(gc->dest); - if (gc->over) fz_droppixmap(gc->over); - - if (gc->model) fz_dropcolorspace(gc->model); - if (gc->cache) fz_dropglyphcache(gc->cache); - if (gc->gel) fz_dropgel(gc->gel); - if (gc->ael) fz_dropael(gc->ael); - fz_free(gc); -} - -/* - * Transform - */ - -static fz_error * -rendertransform(fz_renderer *gc, fz_transformnode *transform, fz_matrix ctm) -{ - fz_error *error; -DEBUG("transform [%g %g %g %g %g %g]\n", -transform->m.a, transform->m.b, -transform->m.c, transform->m.d, -transform->m.e, transform->m.f); -DEBUG("{\n"); - ctm = fz_concat(transform->m, ctm); - error = rendernode(gc, transform->super.first, ctm); -DEBUG("}\n"); - return error; -} - -/* - * Color - */ - -static fz_error * -rendersolid(fz_renderer *gc, fz_solidnode *solid, fz_matrix ctm) -{ - fz_error *error; - float rgb[3]; - unsigned char a, r, g, b; - unsigned char *p; - int n; - - if (gc->maskonly) - return fz_throw("assert: mask only renderer"); - if (gc->model->n != 3) - return fz_throw("assert: non-rgb renderer"); - - fz_convertcolor(solid->cs, solid->samples, gc->model, rgb); - gc->argb[0] = solid->a * 255; - gc->argb[1] = rgb[0] * solid->a * 255; - gc->argb[2] = rgb[1] * solid->a * 255; - gc->argb[3] = rgb[2] * solid->a * 255; - gc->argb[4] = rgb[0] * 255; - gc->argb[5] = rgb[1] * 255; - gc->argb[6] = rgb[2] * 255; - -DEBUG("solid %s [%d %d %d %d];\n", solid->cs->name, gc->argb[0], gc->argb[1], gc->argb[2], gc->argb[3]); - - if (gc->flag == FOVER) - { - p = gc->over->samples; - n = gc->over->w * gc->over->h; - } - else - { - error = fz_newpixmapwithrect(&gc->dest, gc->clip, 4); - if (error) - return error; - p = gc->dest->samples; - n = gc->dest->w * gc->dest->h; - } - - a = gc->argb[0]; - r = gc->argb[1]; - g = gc->argb[2]; - b = gc->argb[3]; - if (((unsigned)p & 3)) { - while (n--) - { - p[0] = a; - p[1] = r; - p[2] = g; - p[3] = b; - p += 4; - } - } - else - { - unsigned *pw = (unsigned *)p; -#if BYTE_ORDER == LITTLE_ENDIAN - unsigned argb = a | (r << 8) | (g << 16) | (b << 24); -#else - unsigned argb = (a << 24) | (r << 16) | (g << 8) | b; -#endif - while (n--) - { - *pw++ = argb; - } - } - - return fz_okay; -} - -/* - * Path - */ - -static fz_error * -renderpath(fz_renderer *gc, fz_pathnode *path, fz_matrix ctm) -{ - fz_error *error; - float flatness; - fz_irect gbox; - fz_irect clip; - float expansion = fz_matrixexpansion(ctm); - - flatness = 0.3 / expansion; - if (flatness < 0.1) - flatness = 0.1; - - fz_resetgel(gc->gel, gc->clip); - - if (path->paint == FZ_STROKE) - { - float lw = path->linewidth; - /* Check for hairline */ - if (lw * expansion < 0.1) { - lw = 1.0f / expansion; - } - if (path->dash) - error = fz_dashpath(gc->gel, path, ctm, flatness, lw); - else - error = fz_strokepath(gc->gel, path, ctm, flatness, lw); - } - else - error = fz_fillpath(gc->gel, path, ctm, flatness); - if (error) - return error; - - fz_sortgel(gc->gel); - - gbox = fz_boundgel(gc->gel); - clip = fz_intersectirects(gc->clip, gbox); - - if (fz_isemptyrect(clip)) - return fz_okay; - -DEBUG("path %s;\n", path->paint == FZ_STROKE ? "stroke" : "fill"); - - if (gc->flag & FRGB) - { -DEBUG(" path rgb %d %d %d %d, %d %d %d\n", gc->argb[0], gc->argb[1], gc->argb[2], gc->argb[3], gc->argb[4], gc->argb[5], gc->argb[6]); - return fz_scanconvert(gc->gel, gc->ael, path->paint == FZ_EOFILL, - clip, gc->over, gc->argb, 1); - } - else if (gc->flag & FOVER) - { - return fz_scanconvert(gc->gel, gc->ael, path->paint == FZ_EOFILL, - clip, gc->over, nil, 1); - } - else - { - error = fz_newpixmapwithrect(&gc->dest, clip, 1); - if (error) - return error; - fz_clearpixmap(gc->dest); - return fz_scanconvert(gc->gel, gc->ael, path->paint == FZ_EOFILL, - clip, gc->dest, nil, 0); - } -} - -/* - * Text - */ - -static void drawglyph(fz_renderer *gc, fz_pixmap *dst, fz_glyph *src, int xorig, int yorig) -{ - unsigned char *dp, *sp; - int w, h; - - int dx0 = dst->x; - int dy0 = dst->y; - int dx1 = dst->x + dst->w; - int dy1 = dst->y + dst->h; - - int x0 = xorig + src->x; - int y0 = yorig + src->y; - int x1 = x0 + src->w; - int y1 = y0 + src->h; - - int sx0 = 0; - int sy0 = 0; - int sx1 = src->w; - int sy1 = src->h; - - if (x1 <= dx0 || x0 >= dx1) return; - if (y1 <= dy0 || y0 >= dy1) return; - if (x0 < dx0) { sx0 += dx0 - x0; x0 = dx0; } - if (y0 < dy0) { sy0 += dy0 - y0; y0 = dy0; } - if (x1 > dx1) { sx1 += dx1 - x1; x1 = dx1; } - if (y1 > dy1) { sy1 += dy1 - y1; y1 = dy1; } - - sp = src->samples + (sy0 * src->w + sx0); - dp = dst->samples + ((y0 - dst->y) * dst->w + (x0 - dst->x)) * dst->n; - - w = sx1 - sx0; - h = sy1 - sy0; - - switch (gc->flag) - { - case FNONE: - assert(dst->n == 1); - fz_text_1o1(sp, src->w, dp, dst->w, w, h); - break; - - case FOVER: - assert(dst->n == 1); - fz_text_1o1(sp, src->w, dp, dst->w, w, h); - break; - - case FOVER | FRGB: - assert(dst->n == 4); - fz_text_w4i1o4(gc->argb, sp, src->w, dp, dst->w * 4, w, h); - break; - - default: - assert(!"impossible flag in text span function"); - } -} - -static fz_error * -rendertext(fz_renderer *gc, fz_textnode *text, fz_matrix ctm) -{ - fz_error *error; - fz_irect tbox; - fz_irect clip; - fz_matrix tm, trm; - fz_glyph glyph; - int i, x, y, gid; - - tbox = fz_roundrect(fz_boundnode((fz_node*)text, ctm)); - clip = fz_intersectirects(gc->clip, tbox); - -DEBUG("text %s n=%d [%g %g %g %g];\n", -text->font->name, text->len, -text->trm.a, text->trm.b, text->trm.c, text->trm.d); - - if (fz_isemptyrect(clip)) - return fz_okay; - - if (!(gc->flag & FOVER)) - { - error = fz_newpixmapwithrect(&gc->dest, clip, 1); - if (error) - return error; - fz_clearpixmap(gc->dest); - } - - tm = text->trm; - - for (i = 0; i < text->len; i++) - { - gid = text->els[i].gid; - tm.e = text->els[i].x; - tm.f = text->els[i].y; - trm = fz_concat(tm, ctm); - x = fz_floor(trm.e); - y = fz_floor(trm.f); - trm.e = QUANT(trm.e - fz_floor(trm.e), HSUBPIX); - trm.f = QUANT(trm.f - fz_floor(trm.f), VSUBPIX); - - error = fz_renderglyph(gc->cache, &glyph, text->font, gid, trm); - if (error) - return error; - - if (!(gc->flag & FOVER)) - drawglyph(gc, gc->dest, &glyph, x, y); - else - drawglyph(gc, gc->over, &glyph, x, y); - } - - return fz_okay; -} - -/* - * Image - */ - -static inline void -calcimagescale(fz_matrix ctm, int w, int h, int *odx, int *ody) -{ - float sx, sy; - int dx, dy; - - sx = sqrt(ctm.a * ctm.a + ctm.b * ctm.b); - dx = 1; - while (((w+dx-1)/dx)/sx > 2.0 && (w+dx-1)/dx > 1) - dx++; - - sy = sqrt(ctm.c * ctm.c + ctm.d * ctm.d); - dy = 1; - while (((h+dy-1)/dy)/sy > 2.0 && (h+dy-1)/dy > 1) - dy++; - - *odx = dx; - *ody = dy; -} - -static fz_error * -renderimage(fz_renderer *gc, fz_imagenode *node, fz_matrix ctm) -{ - fz_error *error; - fz_image *image = node->image; - fz_irect bbox; - fz_irect clip; - int dx, dy; - fz_pixmap *tile; - fz_pixmap *temp; - fz_matrix imgmat; - fz_matrix invmat; - int fa, fb, fc, fd; - int u0, v0; - int x0, y0; - int w, h; - int tileheight; - -DEBUG("image %dx%d %d+%d %s\n{\n", image->w, image->h, image->n, image->a, image->cs?image->cs->name:"(nil)"); - - bbox = fz_roundrect(fz_boundnode((fz_node*)node, ctm)); - clip = fz_intersectirects(gc->clip, bbox); - - if (fz_isemptyrect(clip)) - return fz_okay; - if (image->w == 0 || image->h == 0) - return fz_okay; - - calcimagescale(ctm, image->w, image->h, &dx, &dy); - - /* try to fit tile into a typical L2 cachce */ - tileheight = 512 * 1024 / (image->w * (image->n + image->a)); - /* tileheight must be an even multiple of dy, except for last band */ - tileheight = (tileheight + dy - 1) / dy * dy; - - if ((dx != 1 || dy != 1) && image->h > tileheight) { - int y = 0; - - DEBUG(" load image tile size = %dx%d\n", image->w, tileheight); - error = fz_newpixmap(&tile, 0, 0, image->w, - tileheight, image->n + 1); - if (error) - return error; - - error = fz_newscaledpixmap(&temp, image->w, image->h, image->n + 1, dx, dy); - if (error) - goto cleanup; - - do { - if (y + tileheight > image->h) - tileheight = image->h - y; - tile->y = y; - tile->h = tileheight; - DEBUG(" tile xywh=%d %d %d %d sxsy=1/%d 1/%d\n", - 0, y, image->w, tileheight, dx, dy); - error = image->loadtile(image, tile); - if (error) - goto cleanup1; - - error = fz_scalepixmaptile(temp, 0, y, tile, dx, dy); - if (error) - goto cleanup1; - - y += tileheight; - } while (y < image->h); - - fz_droppixmap(tile); - tile = temp; - } - else { - - -DEBUG(" load image\n"); - error = fz_newpixmap(&tile, 0, 0, image->w, image->h, image->n + 1); - if (error) - return error; - - error = image->loadtile(image, tile); - if (error) - goto cleanup; - - if (dx != 1 || dy != 1) - { -DEBUG(" scale image 1/%d 1/%d\n", dx, dy); - error = fz_scalepixmap(&temp, tile, dx, dy); - if (error) - goto cleanup; - fz_droppixmap(tile); - tile = temp; - } - } - - if (image->cs && image->cs != gc->model) - { -DEBUG(" convert from %s to %s\n", image->cs->name, gc->model->name); - error = fz_newpixmap(&temp, tile->x, tile->y, tile->w, tile->h, gc->model->n + 1); - if (error) - goto cleanup; - fz_convertpixmap(image->cs, tile, gc->model, temp); - fz_droppixmap(tile); - tile = temp; - } - - imgmat.a = 1.0 / tile->w; - imgmat.b = 0.0; - imgmat.c = 0.0; - imgmat.d = -1.0 / tile->h; - imgmat.e = 0.0; - imgmat.f = 1.0; - invmat = fz_invertmatrix(fz_concat(imgmat, ctm)); - - w = clip.x1 - clip.x0; - h = clip.y1 - clip.y0; - x0 = clip.x0; - y0 = clip.y0; - u0 = (invmat.a * (x0+0.5) + invmat.c * (y0+0.5) + invmat.e) * 65536; - v0 = (invmat.b * (x0+0.5) + invmat.d * (y0+0.5) + invmat.f) * 65536; - fa = invmat.a * 65536; - fb = invmat.b * 65536; - fc = invmat.c * 65536; - fd = invmat.d * 65536; - -#define PSRC tile->samples, tile->w, tile->h -#define PDST(p) p->samples + ((y0-p->y) * p->w + (x0-p->x)) * p->n, p->w * p->n -#define PCTM u0, v0, fa, fb, fc, fd, w, h - - switch (gc->flag) - { - case FNONE: - { -DEBUG(" fnone %d x %d\n", w, h); - if (image->cs) - error = fz_newpixmapwithrect(&gc->dest, clip, gc->model->n + 1); - else - error = fz_newpixmapwithrect(&gc->dest, clip, 1); - if (error) - goto cleanup; - - if (image->cs) - fz_img_4c4(PSRC, PDST(gc->dest), PCTM); - else - fz_img_1c1(PSRC, PDST(gc->dest), PCTM); - } - break; - - case FOVER: - { -DEBUG(" fover %d x %d\n", w, h); - if (image->cs) - fz_img_4o4(PSRC, PDST(gc->over), PCTM); - else - fz_img_1o1(PSRC, PDST(gc->over), PCTM); - } - break; - - case FOVER | FRGB: -DEBUG(" fover+rgb %d x %d\n", w, h); - fz_img_w4i1o4(gc->argb, PSRC, PDST(gc->over), PCTM); - break; - - default: - assert(!"impossible flag in image span function"); - } - -DEBUG("}\n"); - - fz_droppixmap(tile); - return fz_okay; - -cleanup1: - fz_droppixmap(temp); -cleanup: - fz_droppixmap(tile); - return error; -} - -/* - * Shade - */ - -static fz_error * -rendershade(fz_renderer *gc, fz_shadenode *node, fz_matrix ctm) -{ - fz_error *error; - fz_irect bbox; - - assert(!gc->maskonly); - - DEBUG("shade;\n"); - - bbox = fz_roundrect(fz_boundnode((fz_node*)node, ctm)); - bbox = fz_intersectirects(gc->clip, bbox); - - error = fz_newpixmapwithrect(&gc->dest, bbox, gc->model->n + 1); - if (error) - return error; - - return fz_rendershade(node->shade, ctm, gc->model, gc->dest); -} - -/* - * Over, Mask and Blend - */ - -static void -blendover(fz_renderer *gc, fz_pixmap *src, fz_pixmap *dst) -{ - unsigned char *sp, *dp; - fz_irect sr, dr; - int x, y, w, h; - - sr.x0 = src->x; - sr.y0 = src->y; - sr.x1 = src->x + src->w; - sr.y1 = src->y + src->h; - - dr.x0 = dst->x; - dr.y0 = dst->y; - dr.x1 = dst->x + dst->w; - dr.y1 = dst->y + dst->h; - - dr = fz_intersectirects(sr, dr); - x = dr.x0; - y = dr.y0; - w = dr.x1 - dr.x0; - h = dr.y1 - dr.y0; - - sp = src->samples + ((y - src->y) * src->w + (x - src->x)) * src->n; - dp = dst->samples + ((y - dst->y) * dst->w + (x - dst->x)) * dst->n; - - if (src->n == 1 && dst->n == 1) - fz_duff_1o1(sp, src->w, dp, dst->w, w, h); - else if (src->n == 4 && dst->n == 4) - fz_duff_4o4(sp, src->w * 4, dp, dst->w * 4, w, h); - else if (src->n == dst->n) - fz_duff_non(sp, src->w * src->n, src->n, dp, dst->w * dst->n, w, h); - else - assert(!"blendover src and dst mismatch"); -} - -static void -blendmask(fz_renderer *gc, fz_pixmap *src, fz_pixmap *msk, fz_pixmap *dst, int over) -{ - unsigned char *sp, *dp, *mp; - fz_irect sr, dr, mr; - int x, y, w, h; - - sr.x0 = src->x; - sr.y0 = src->y; - sr.x1 = src->x + src->w; - sr.y1 = src->y + src->h; - - dr.x0 = dst->x; - dr.y0 = dst->y; - dr.x1 = dst->x + dst->w; - dr.y1 = dst->y + dst->h; - - mr.x0 = msk->x; - mr.y0 = msk->y; - mr.x1 = msk->x + msk->w; - mr.y1 = msk->y + msk->h; - - dr = fz_intersectirects(sr, dr); - dr = fz_intersectirects(dr, mr); - x = dr.x0; - y = dr.y0; - w = dr.x1 - dr.x0; - h = dr.y1 - dr.y0; - - sp = src->samples + ((y - src->y) * src->w + (x - src->x)) * src->n; - mp = msk->samples + ((y - msk->y) * msk->w + (x - msk->x)) * msk->n; - dp = dst->samples + ((y - dst->y) * dst->w + (x - dst->x)) * dst->n; - - if (over) - { - if (src->n == 1 && msk->n == 1 && dst->n == 1) - fz_duff_1i1o1(sp, src->w, mp, msk->w, dp, dst->w, w, h); - else if (src->n == 4 && msk->n == 1 && dst->n == 4) - fz_duff_4i1o4(sp, src->w * 4, mp, msk->w, dp, dst->w * 4, w, h); - else if (src->n == dst->n) - fz_duff_nimon(sp, src->w * src->n, src->n, mp, msk->w * msk->n, msk->n, dp, dst->w * dst->n, w, h); - else - assert(!"blendmaskover src and msk and dst mismatch"); - } - else - { - if (src->n == 1 && msk->n == 1 && dst->n == 1) - fz_duff_1i1c1(sp, src->w, mp, msk->w, dp, dst->w, w, h); - else if (src->n == 4 && msk->n == 1 && dst->n == 4) - fz_duff_4i1c4(sp, src->w * 4, mp, msk->w, dp, dst->w * 4, w, h); - else if (src->n == dst->n) - fz_duff_nimcn(sp, src->w * src->n, src->n, mp, msk->w * msk->n, msk->n, dp, dst->w * dst->n, w, h); - else - assert(!"blendmask src and msk and dst mismatch"); - } -} - -static fz_error * -renderover(fz_renderer *gc, fz_overnode *over, fz_matrix ctm) -{ - fz_error *error; - fz_node *child; - int cluster = 0; - - if (!gc->over) - { -DEBUG("over cluster %d\n{\n", gc->maskonly ? 1 : 4); - cluster = 1; - if (gc->maskonly) - error = fz_newpixmapwithrect(&gc->over, gc->clip, 1); - else - error = fz_newpixmapwithrect(&gc->over, gc->clip, 4); - if (error) - return error; - fz_clearpixmap(gc->over); - } -else DEBUG("over\n{\n"); - - for (child = over->super.first; child; child = child->next) - { - error = rendernode(gc, child, ctm); - if (error) - return error; - if (gc->dest) - { - blendover(gc, gc->dest, gc->over); - fz_droppixmap(gc->dest); - gc->dest = nil; - } - } - - if (cluster) - { - gc->dest = gc->over; - gc->over = nil; - } - -DEBUG("}\n"); - - return fz_okay; -} - -static fz_error * -rendermask(fz_renderer *gc, fz_masknode *mask, fz_matrix ctm) -{ - fz_error *error; - int oldmaskonly; - fz_pixmap *oldover; - fz_irect oldclip; - fz_irect bbox; - fz_irect clip; - fz_pixmap *shapepix = nil; - fz_pixmap *colorpix = nil; - fz_node *shape; - fz_node *color; - float rgb[3]; - - shape = mask->super.first; - color = shape->next; - - /* special case black voodo */ - if (gc->flag & FOVER) - { - if (fz_issolidnode(color)) - { - fz_solidnode *solid = (fz_solidnode*)color; - - fz_convertcolor(solid->cs, solid->samples, gc->model, rgb); - gc->argb[0] = solid->a * 255; - gc->argb[1] = rgb[0] * solid->a * 255; - gc->argb[2] = rgb[1] * solid->a * 255; - gc->argb[3] = rgb[2] * solid->a * 255; - gc->argb[4] = rgb[0] * 255; - gc->argb[5] = rgb[1] * 255; - gc->argb[6] = rgb[2] * 255; - gc->flag |= FRGB; - - /* we know these can handle the FRGB shortcut */ - if (fz_ispathnode(shape)) - return renderpath(gc, (fz_pathnode*)shape, ctm); - if (fz_istextnode(shape)) - return rendertext(gc, (fz_textnode*)shape, ctm); - if (fz_isimagenode(shape)) - return renderimage(gc, (fz_imagenode*)shape, ctm); - } - } - - oldclip = gc->clip; - oldover = gc->over; - - bbox = fz_roundrect(fz_boundnode(shape, ctm)); - clip = fz_intersectirects(bbox, gc->clip); - bbox = fz_roundrect(fz_boundnode(color, ctm)); - clip = fz_intersectirects(bbox, clip); - - if (fz_isemptyrect(clip)) - return fz_okay; - -DEBUG("mask [%d %d %d %d]\n{\n", clip.x0, clip.y0, clip.x1, clip.y1); - -{ -fz_irect sbox = fz_roundrect(fz_boundnode(shape, ctm)); -fz_irect cbox = fz_roundrect(fz_boundnode(color, ctm)); -if (cbox.x0 >= sbox.x0 && cbox.x1 <= sbox.x1) -if (cbox.y0 >= sbox.y0 && cbox.y1 <= sbox.y1) -DEBUG("potentially useless mask\n"); -} - - gc->clip = clip; - gc->over = nil; - - oldmaskonly = gc->maskonly; - gc->maskonly = 1; - - error = rendernode(gc, shape, ctm); - if (error) - goto cleanup; - shapepix = gc->dest; - gc->dest = nil; - - gc->maskonly = oldmaskonly; - - error = rendernode(gc, color, ctm); - if (error) - goto cleanup; - colorpix = gc->dest; - gc->dest = nil; - - gc->clip = oldclip; - gc->over = oldover; - - if (shapepix && colorpix) - { - if (gc->over) - { - blendmask(gc, colorpix, shapepix, gc->over, 1); - } - else - { - clip.x0 = MAX(colorpix->x, shapepix->x); - clip.y0 = MAX(colorpix->y, shapepix->y); - clip.x1 = MIN(colorpix->x+colorpix->w, shapepix->x+shapepix->w); - clip.y1 = MIN(colorpix->y+colorpix->h, shapepix->y+shapepix->h); - error = fz_newpixmapwithrect(&gc->dest, clip, colorpix->n); - if (error) - goto cleanup; - blendmask(gc, colorpix, shapepix, gc->dest, 0); - } - } - -DEBUG("}\n"); - - if (shapepix) fz_droppixmap(shapepix); - if (colorpix) fz_droppixmap(colorpix); - return fz_okay; - -cleanup: - if (shapepix) fz_droppixmap(shapepix); - if (colorpix) fz_droppixmap(colorpix); - return error; -} - -/* - * Dispatch - */ - -static fz_error * -rendernode(fz_renderer *gc, fz_node *node, fz_matrix ctm) -{ - if (!node) - return fz_okay; - - gc->flag = FNONE; - if (gc->over) - gc->flag |= FOVER; - - switch (node->kind) - { - case FZ_NOVER: - return renderover(gc, (fz_overnode*)node, ctm); - case FZ_NMASK: - return rendermask(gc, (fz_masknode*)node, ctm); - case FZ_NTRANSFORM: - return rendertransform(gc, (fz_transformnode*)node, ctm); - case FZ_NCOLOR: - return rendersolid(gc, (fz_solidnode*)node, ctm); - case FZ_NPATH: - return renderpath(gc, (fz_pathnode*)node, ctm); - case FZ_NTEXT: - return rendertext(gc, (fz_textnode*)node, ctm); - case FZ_NIMAGE: - return renderimage(gc, (fz_imagenode*)node, ctm); - case FZ_NSHADE: - return rendershade(gc, (fz_shadenode*)node, ctm); - case FZ_NLINK: - return rendernode(gc, ((fz_linknode*)node)->tree->root, ctm); - case FZ_NBLEND: - return fz_okay; - } - - return fz_okay; -} - -fz_error * -fz_rendertree(fz_pixmap **outp, - fz_renderer *gc, fz_tree *tree, fz_matrix ctm, - fz_irect bbox, int white) -{ - fz_error *error; - - gc->clip = bbox; - gc->over = nil; - - if (gc->maskonly) - error = fz_newpixmapwithrect(&gc->over, bbox, 1); - else - error = fz_newpixmapwithrect(&gc->over, bbox, 4); - if (error) - return error; - - if (white) - memset(gc->over->samples, 0xff, gc->over->w * gc->over->h * gc->over->n); - else - memset(gc->over->samples, 0x00, gc->over->w * gc->over->h * gc->over->n); - -DEBUG("tree %d [%d %d %d %d]\n{\n", -gc->maskonly ? 1 : 4, -bbox.x0, bbox.y0, bbox.x1, bbox.y1); - - error = rendernode(gc, tree->root, ctm); - if (error) - return error; - -DEBUG("}\n"); - - if (gc->dest) - { - blendover(gc, gc->dest, gc->over); - fz_droppixmap(gc->dest); - gc->dest = nil; - } - - *outp = gc->over; - gc->over = nil; - - return fz_okay; -} - -fz_error * -fz_rendertreeover(fz_renderer *gc, fz_pixmap *dest, fz_tree *tree, fz_matrix ctm) -{ - fz_error *error; - - assert(!gc->maskonly); - assert(dest->n == 4); - - gc->clip.x0 = dest->x; - gc->clip.y0 = dest->y; - gc->clip.x1 = dest->x + dest->w; - gc->clip.y1 = dest->y + dest->h; - - gc->over = dest; - - error = rendernode(gc, tree->root, ctm); - if (error) - { - gc->over = nil; - return error; - } - - if (gc->dest) - { - blendover(gc, gc->dest, gc->over); - fz_droppixmap(gc->dest); - gc->dest = nil; - } - - gc->over = nil; - - return fz_okay; -} - diff --git a/stream/Jamfile b/stream/Jamfile deleted file mode 100644 index 65c08b75..00000000 --- a/stream/Jamfile +++ /dev/null @@ -1,47 +0,0 @@ -SubDir TOP stream ; - -Library libstream : - - crypt_arc4.c - crypt_crc32.c - crypt_md5.c - - obj_array.c - obj_dict.c - obj_parse.c - obj_print.c - obj_simple.c - - stm_buffer.c - stm_filter.c - stm_open.c - stm_read.c - stm_write.c - stm_misc.c - - filt_pipeline.c - filt_arc4.c - filt_null.c - - filt_a85d.c - filt_a85e.c - filt_ahxd.c - filt_ahxe.c - filt_dctd.c - filt_dcte.c - filt_faxd.c - filt_faxdtab.c - filt_faxe.c - filt_faxetab.c - filt_flate.c - filt_lzwd.c - filt_lzwe.c - filt_predict.c - filt_rld.c - filt_rle.c - - ; - -if $(HAVE_JASPER) { Library libstream : filt_jpxd.c ; } -if $(HAVE_JBIG2DEC) { Library libstream : filt_jbig2d.c ; } - diff --git a/stream/crypt_arc4.c b/stream/crypt_arc4.c deleted file mode 100644 index fc4d487c..00000000 --- a/stream/crypt_arc4.c +++ /dev/null @@ -1,100 +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 "fitz-base.h" -#include "fitz-stream.h" - -void -fz_arc4init(fz_arc4 *arc4, const unsigned char *key, const 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; - } - } -} - -unsigned char -fz_arc4next(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_arc4encrypt(fz_arc4 *arc4, unsigned char *dest, const unsigned char *src, const unsigned len) -{ - unsigned int i; - for (i = 0; i < len; i++) - { - unsigned char x; - x = fz_arc4next(arc4); - dest[i] = src[i] ^ x; - } -} - diff --git a/stream/crypt_crc32.c b/stream/crypt_crc32.c deleted file mode 100644 index dded733e..00000000 --- a/stream/crypt_crc32.c +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Compute the CRC-32 of a data buffer - */ - -#include "fitz-base.h" -#include "fitz-stream.h" - -static const unsigned long crctab[256] = -{ - 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, - 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, - 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, - 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, - 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, - 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, - 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, - 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, - 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, - 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, - 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, - 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, - 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, - 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, - 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, - 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, - 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, - 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, - 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, - 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, - 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, - 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, - 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, - 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, - 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, - 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, - 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, - 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, - 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, - 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, - 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, - 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, - 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, - 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, - 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, - 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, - 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, - 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, - 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, - 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, - 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, - 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, - 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, - 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, - 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, - 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, - 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, - 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, - 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, - 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, - 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, - 0x2d02ef8dL -}; - -#define DO1(buf) crc = crctab[((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8); -#define DO2(buf) DO1(buf); DO1(buf); -#define DO4(buf) DO2(buf); DO2(buf); -#define DO8(buf) DO4(buf); DO4(buf); - -unsigned long -fz_crc32(unsigned long crc, unsigned char *buf, int len) -{ - if (buf == nil) - return 0L; - crc = crc ^ 0xffffffffL; - while (len >= 8) - { - DO8(buf); - len -= 8; - } - if (len) - { - do { DO1(buf); } while (--len); - } - return crc ^ 0xffffffffL; -} - diff --git a/stream/crypt_md5.c b/stream/crypt_md5.c deleted file mode 100644 index 8f665329..00000000 --- a/stream/crypt_md5.c +++ /dev/null @@ -1,274 +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 "fitz-base.h" -#include "fitz-stream.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 long *, const unsigned); -static void decode(unsigned long *, const unsigned char *, const unsigned); -static void transform(unsigned long 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 long)(ac); \ - (a) = ROTATE ((a), (s)); \ - (a) += (b); \ - } -#define GG(a, b, c, d, x, s, ac) { \ - (a) += G ((b), (c), (d)) + (x) + (unsigned long)(ac); \ - (a) = ROTATE ((a), (s)); \ - (a) += (b); \ - } -#define HH(a, b, c, d, x, s, ac) { \ - (a) += H ((b), (c), (d)) + (x) + (unsigned long)(ac); \ - (a) = ROTATE ((a), (s)); \ - (a) += (b); \ - } -#define II(a, b, c, d, x, s, ac) { \ - (a) += I ((b), (c), (d)) + (x) + (unsigned long)(ac); \ - (a) = ROTATE ((a), (s)); \ - (a) += (b); \ - } - -static void encode(unsigned char *output, const unsigned long *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 long *output, const unsigned char *input, const unsigned len) -{ - unsigned i, j; - - for (i = 0, j = 0; j < len; i++, j += 4) - { - output[i] = ((unsigned long)input[j]) | - (((unsigned long)input[j+1]) << 8) | - (((unsigned long)input[j+2]) << 16) | - (((unsigned long)input[j+3]) << 24); - } -} - -static void transform(unsigned long state[4], const unsigned char block[64]) -{ - unsigned long a = state[0]; - unsigned long b = state[1]; - unsigned long c = state[2]; - unsigned long d = state[3]; - unsigned long 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, 0x2441453); /* 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, 0x4881d05); /* 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_md5init(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_md5update(fz_md5 *context, const unsigned char *input, const 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 long) inlen << 3; - if (context->count[0] < (unsigned long) inlen << 3) - context->count[1] ++; - context->count[1] += (unsigned long) 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_md5final(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_md5update(context, padding, padlen); - - /* Append length (before padding) */ - fz_md5update(context, bits, 8); - - /* Store state in digest */ - encode(digest, context->state, 16); - - /* Zeroize sensitive information */ - memset(context, 0, sizeof(fz_md5)); -} - diff --git a/stream/filt_a85d.c b/stream/filt_a85d.c deleted file mode 100644 index 19ba9e9a..00000000 --- a/stream/filt_a85d.c +++ /dev/null @@ -1,128 +0,0 @@ -#include "fitz-base.h" -#include "fitz-stream.h" - -typedef struct fz_a85d_s fz_a85d; - -struct fz_a85d_s -{ - fz_filter super; - unsigned long word; - int count; -}; - -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; -} - -fz_error * -fz_newa85d(fz_filter **fp, fz_obj *params) -{ - FZ_NEWFILTER(fz_a85d, f, a85d); - f->word = 0; - f->count = 0; - return fz_okay; -} - -void -fz_dropa85d(fz_filter *f) -{ -} - -fz_error * -fz_processa85d(fz_filter *filter, fz_buffer *in, fz_buffer *out) -{ - fz_a85d *f = (fz_a85d*)filter; - int c; - - while (1) - { - if (in->rp == in->wp) - return fz_ioneedin; - - c = *in->rp++; - - if (c >= '!' && c <= 'u') { - if (f->count == 4) { - if (out->wp + 4 > out->ep) { - in->rp --; - return fz_ioneedout; - } - - f->word = f->word * 85 + (c - '!'); - - *out->wp++ = (f->word >> 24) & 0xff; - *out->wp++ = (f->word >> 16) & 0xff; - *out->wp++ = (f->word >> 8) & 0xff; - *out->wp++ = (f->word) & 0xff; - - f->word = 0; - f->count = 0; - } - else { - f->word = f->word * 85 + (c - '!'); - f->count ++; - } - } - - else if (c == 'z' && f->count == 0) { - if (out->wp + 4 > out->ep) { - in->rp --; - return fz_ioneedout; - } - *out->wp++ = 0; - *out->wp++ = 0; - *out->wp++ = 0; - *out->wp++ = 0; - } - - else if (c == '~') { - if (in->rp == in->wp) { - in->rp --; - return fz_ioneedin; - } - - c = *in->rp++; - - if (c != '>') { - return fz_throw("bad eod marker in a85d"); - } - - if (out->wp + f->count - 1 > out->ep) { - in->rp -= 2; - return fz_ioneedout; - } - - switch (f->count) { - case 0: - break; - case 1: - return fz_throw("partial final byte in a85d"); - case 2: - f->word = f->word * (85L * 85 * 85) + 0xffffffL; - goto o1; - case 3: - f->word = f->word * (85L * 85) + 0xffffL; - goto o2; - case 4: - f->word = f->word * 85 + 0xffL; - *(out->wp+2) = f->word >> 8; -o2: *(out->wp+1) = f->word >> 16; -o1: *(out->wp+0) = f->word >> 24; - out->wp += f->count - 1; - break; - } - return fz_iodone; - } - - else if (!iswhite(c)) { - return fz_throw("bad data in a85d: '%c'", c); - } - } -} - diff --git a/stream/filt_a85e.c b/stream/filt_a85e.c deleted file mode 100644 index 386d8bb3..00000000 --- a/stream/filt_a85e.c +++ /dev/null @@ -1,126 +0,0 @@ -#include "fitz-base.h" -#include "fitz-stream.h" - -typedef struct fz_a85e_s fz_a85e; - -struct fz_a85e_s -{ - fz_filter super; - int c; -}; - -fz_error * -fz_newa85e(fz_filter **fp, fz_obj *params) -{ - FZ_NEWFILTER(fz_a85e, f, a85e); - f->c = 0; - return fz_okay; -} - -void -fz_dropa85e(fz_filter *f) -{ -} - -fz_error * -fz_processa85e(fz_filter *filter, fz_buffer *in, fz_buffer *out) -{ - fz_a85e *f = (fz_a85e*)filter; - unsigned long word; - int count; - int n; - - n = 0; - - while (1) - { - if (f->c >= 70) { - if (out->wp + 1 > out->ep) - return fz_ioneedout; - *out->wp++ = '\n'; - f->c = 0; - n ++; - } - - if (in->rp + 4 <= in->wp) - { - word = (in->rp[0] << 24) | - (in->rp[1] << 16) | - (in->rp[2] << 8) | - (in->rp[3]); - if (word == 0) { - if (out->wp + 1 > out->ep) - return fz_ioneedout; - *out->wp++ = 'z'; - f->c ++; - n ++; - } - else { - unsigned long v1, v2, v3, v4; - - if (out->wp + 5 > out->ep) - return fz_ioneedout; - - v4 = word / 85; - v3 = v4 / 85; - v2 = v3 / 85; - v1 = v2 / 85; - - *out->wp++ = (v1 % 85) + '!'; - *out->wp++ = (v2 % 85) + '!'; - *out->wp++ = (v3 % 85) + '!'; - *out->wp++ = (v4 % 85) + '!'; - *out->wp++ = (word % 85) + '!'; - f->c += 5; - n += 5; - } - in->rp += 4; - } - - else if (in->eof) - { - unsigned long divisor; - - if (in->rp == in->wp) - goto needinput; /* handle clean eof here */ - - count = in->wp - in->rp; - - if (out->wp + count + 3 > out->ep) - return fz_ioneedout; - - word = 0; - switch (count) { - case 3: word |= in->rp[2] << 8; - case 2: word |= in->rp[1] << 16; - case 1: word |= in->rp[0] << 24; - } - in->rp += count; - - divisor = 85L * 85 * 85 * 85; - while (count-- >= 0) { - *out->wp++ = ((word / divisor) % 85) + '!'; - divisor /= 85; - } - - *out->wp++ = '~'; - *out->wp++ = '>'; - return fz_iodone; - } - - else { - goto needinput; - } - } - -needinput: - if (in->eof) { - if (out->wp + 2 > out->ep) - return fz_ioneedout; - *out->wp++ = '~'; - *out->wp++ = '>'; - return fz_iodone; - } - return fz_ioneedin; -} - diff --git a/stream/filt_ahxd.c b/stream/filt_ahxd.c deleted file mode 100644 index 0feb10c2..00000000 --- a/stream/filt_ahxd.c +++ /dev/null @@ -1,112 +0,0 @@ -#include "fitz-base.h" -#include "fitz-stream.h" - -typedef struct fz_ahxd_s fz_ahxd; - -struct fz_ahxd_s -{ - fz_filter super; - int odd; - int a; -}; - -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 fromhex(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; -} - -fz_error * -fz_newahxd(fz_filter **fp, fz_obj *params) -{ - FZ_NEWFILTER(fz_ahxd, f, ahxd); - f->odd = 0; - f->a = 0; - return fz_okay; -} - -void -fz_dropahxd(fz_filter *f) -{ -} - -fz_error * -fz_processahxd(fz_filter *filter, fz_buffer *in, fz_buffer *out) -{ - fz_ahxd *f = (fz_ahxd*)filter; - int b, c; - - while (1) - { - if (in->rp == in->wp) - return fz_ioneedin; - - if (out->wp == out->ep) - return fz_ioneedout; - - c = *in->rp++; - - if (ishex(c)) { - if (!f->odd) { - f->a = fromhex(c); - f->odd = 1; - } - else { - b = fromhex(c); - *out->wp++ = (f->a << 4) | b; - f->odd = 0; - } - } - - else if (c == '>') { - if (f->odd) - *out->wp++ = (f->a << 4); - return fz_iodone; - } - - else if (!iswhite(c)) { - return fz_throw("bad data in ahxd: '%c'", c); - } - } -} - -void -fz_pushbackahxd(fz_filter *filter, fz_buffer *in, fz_buffer *out, int n) -{ - int k; - - assert(filter->process == fz_processahxd); - assert(out->wp - n >= out->rp); - - k = 0; - while (k < n * 2) { - in->rp --; - if (ishex(*in->rp)) - k ++; - } - - out->wp -= n; -} - diff --git a/stream/filt_ahxe.c b/stream/filt_ahxe.c deleted file mode 100644 index 0fc727c3..00000000 --- a/stream/filt_ahxe.c +++ /dev/null @@ -1,64 +0,0 @@ -#include "fitz-base.h" -#include "fitz-stream.h" - -typedef struct fz_ahxe_s fz_ahxe; - -struct fz_ahxe_s -{ - fz_filter super; - int c; -}; - -static const char tohex[16] = "0123456789ABCDEF"; - -fz_error * -fz_newahxe(fz_filter **fp, fz_obj *params) -{ - FZ_NEWFILTER(fz_ahxe, f, ahxe); - f->c = 0; - return fz_okay; -} - -void -fz_dropahxe(fz_filter *f) -{ -} - -fz_error * -fz_processahxe(fz_filter *filter, fz_buffer *in, fz_buffer *out) -{ - fz_ahxe *f = (fz_ahxe*)filter; - int a, b, c; - - while (1) - { - if (in->rp == in->wp) - goto needinput; - - if (out->wp + 2 >= out->ep) /* can write 3 bytes from 1 */ - return fz_ioneedout; - - c = *in->rp++; - a = tohex[(c >> 4) & 0x0f]; - b = tohex[c & 0x0f]; - - *out->wp++ = a; - *out->wp++ = b; - - f->c += 2; - if (f->c == 60) { - *out->wp++ = '\n'; - f->c = 0; - } - } - -needinput: - if (in->eof) { - if (out->wp == out->ep) - return fz_ioneedout; - *out->wp++ = '>'; - return fz_iodone; - } - return fz_ioneedin; -} - diff --git a/stream/filt_arc4.c b/stream/filt_arc4.c deleted file mode 100644 index af038599..00000000 --- a/stream/filt_arc4.c +++ /dev/null @@ -1,47 +0,0 @@ -#include "fitz-base.h" -#include "fitz-stream.h" - -typedef struct fz_arc4c_s fz_arc4c; - -struct fz_arc4c_s -{ - fz_filter super; - fz_arc4 arc4; -}; - -fz_error * -fz_newarc4filter(fz_filter **fp, unsigned char *key, unsigned keylen) -{ - FZ_NEWFILTER(fz_arc4c, f, arc4filter); - fz_arc4init(&f->arc4, key, keylen); - return fz_okay; -} - -void -fz_droparc4filter(fz_filter *f) -{ -} - -fz_error * -fz_processarc4filter(fz_filter *filter, fz_buffer *in, fz_buffer *out) -{ - fz_arc4c *f = (fz_arc4c*)filter; - int n; - - while (1) - { - if (in->rp + 1 > in->wp) { - if (in->eof) - return fz_iodone; - return fz_ioneedin; - } - if (out->wp + 1 > out->ep) - return fz_ioneedout; - - n = MIN(in->wp - in->rp, out->ep - out->wp); - fz_arc4encrypt(&f->arc4, out->wp, in->rp, n); - in->rp += n; - out->wp += n; - } -} - diff --git a/stream/filt_dctc.h b/stream/filt_dctc.h deleted file mode 100644 index 72f61ef2..00000000 --- a/stream/filt_dctc.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Extend libjpegs error handler to use setjmp/longjmp - */ - -#include - -#include - -struct myerrmgr -{ - struct jpeg_error_mgr super; - jmp_buf jb; - char msg[JMSG_LENGTH_MAX]; -}; - -static void myerrexit(j_common_ptr cinfo) -{ - struct myerrmgr *err = (struct myerrmgr *)cinfo->err; - char msgbuf[JMSG_LENGTH_MAX]; - err->super.format_message(cinfo, msgbuf); - strlcpy(err->msg, msgbuf, sizeof err->msg); - longjmp(err->jb, 1); -} - -static void myoutmess(j_common_ptr cinfo) -{ - struct myerrmgr *err = (struct myerrmgr *)cinfo->err; - char msgbuf[JMSG_LENGTH_MAX]; - err->super.format_message(cinfo, msgbuf); - fz_warn("jpeg error: %s", msgbuf); -} - -static void myiniterr(struct myerrmgr *err) -{ - jpeg_std_error(&err->super); - err->super.error_exit = myerrexit; - err->super.output_message = myoutmess; -} - diff --git a/stream/filt_dctd.c b/stream/filt_dctd.c deleted file mode 100644 index 3425b8e5..00000000 --- a/stream/filt_dctd.c +++ /dev/null @@ -1,232 +0,0 @@ -#include "fitz-base.h" -#include "fitz-stream.h" - -#include "filt_dctc.h" - -typedef struct fz_dctd_s fz_dctd; - -struct mysrcmgr -{ - struct jpeg_source_mgr super; - fz_buffer *buf; - int skip; -}; - -struct fz_dctd_s -{ - fz_filter super; - struct jpeg_decompress_struct cinfo; - struct mysrcmgr src; - struct myerrmgr err; - int colortransform; - int stage; -}; - -static void myinitsource(j_decompress_ptr cinfo) { /* empty */ } -static boolean myfillinput(j_decompress_ptr cinfo) { return FALSE; } -static void mytermsource(j_decompress_ptr cinfo) { /* empty */ } - -static void myskipinput(j_decompress_ptr cinfo, long n) -{ - struct mysrcmgr *src = (struct mysrcmgr *)cinfo->src; - fz_buffer *in = src->buf; - - assert(src->skip == 0); - - in->rp = in->wp - src->super.bytes_in_buffer; - - if (in->rp + n > in->wp) { - src->skip = (in->rp + n) - in->wp; - in->rp = in->wp; - } - else { - src->skip = 0; - in->rp += n; - } - - src->super.bytes_in_buffer = in->wp - in->rp; - src->super.next_input_byte = in->rp; -} - -fz_error * -fz_newdctd(fz_filter **fp, fz_obj *params) -{ - fz_error *err; - fz_obj *obj; - int colortransform; - - FZ_NEWFILTER(fz_dctd, d, dctd); - - colortransform = -1; /* "unset" */ - - if (params) - { - obj = fz_dictgets(params, "ColorTransform"); - if (obj) - colortransform = fz_toint(obj); - } - - d->colortransform = colortransform; - d->stage = 0; - - /* setup error callback first thing */ - myiniterr(&d->err); - d->cinfo.err = (struct jpeg_error_mgr*) &d->err; - - if (setjmp(d->err.jb)) { - err = fz_throw("cannot decode jpeg: %s", d->err.msg); - fz_free(d); - return err; - } - - /* create decompression object. this zeroes cinfo except for err. */ - jpeg_create_decompress(&d->cinfo); - - /* prepare source manager */ - d->cinfo.src = (struct jpeg_source_mgr *)&d->src; - d->src.super.init_source = myinitsource; - d->src.super.fill_input_buffer = myfillinput; - d->src.super.skip_input_data = myskipinput; - d->src.super.resync_to_restart = jpeg_resync_to_restart; - d->src.super.term_source = mytermsource; - - d->src.super.bytes_in_buffer = 0; - d->src.super.next_input_byte = nil; - d->src.skip = 0; - - /* speed up jpeg decoding a bit */ - d->cinfo.dct_method = JDCT_FASTEST; - d->cinfo.do_fancy_upsampling = FALSE; - - return fz_okay; -} - -void -fz_dropdctd(fz_filter *filter) -{ - fz_dctd *d = (fz_dctd*)filter; - if (setjmp(d->err.jb)) { - fz_warn("jpeg error: jpeg_destroy_decompress: %s", d->err.msg); - return; - } - jpeg_destroy_decompress(&d->cinfo); -} - -fz_error * -fz_processdctd(fz_filter *filter, fz_buffer *in, fz_buffer *out) -{ - fz_dctd *d = (fz_dctd*)filter; - boolean b; - int i; - int stride; - JSAMPROW scanlines[1]; - - d->src.buf = in; - - /* skip any bytes left over from myskipinput() */ - if (d->src.skip > 0) { - if (in->rp + d->src.skip > in->wp) { - d->src.skip = (in->rp + d->src.skip) - in->wp; - in->rp = in->wp; - goto needinput; - } - else { - in->rp += d->src.skip; - d->src.skip = 0; - } - } - - d->src.super.bytes_in_buffer = in->wp - in->rp; - d->src.super.next_input_byte = in->rp; - - if (setjmp(d->err.jb)) - { - return fz_throw("cannot decode jpeg: %s", d->err.msg); - } - - switch (d->stage) - { - case 0: - i = jpeg_read_header(&d->cinfo, TRUE); - if (i == JPEG_SUSPENDED) - goto needinput; - - /* default value if ColorTransform is not set */ - if (d->colortransform == -1) - { - if (d->cinfo.num_components == 3) - d->colortransform = 1; - else - d->colortransform = 0; - } - - if (d->cinfo.saw_Adobe_marker) - d->colortransform = d->cinfo.Adobe_transform; - - /* Guess the input colorspace, and set output colorspace accordingly */ - switch (d->cinfo.num_components) - { - case 3: - if (d->colortransform) - d->cinfo.jpeg_color_space = JCS_YCbCr; - else - d->cinfo.jpeg_color_space = JCS_RGB; - break; - case 4: - if (d->colortransform) - d->cinfo.jpeg_color_space = JCS_YCCK; - else - d->cinfo.jpeg_color_space = JCS_CMYK; - break; - } - - /* fall through */ - d->stage = 1; - - case 1: - b = jpeg_start_decompress(&d->cinfo); - if (b == FALSE) - goto needinput; - - /* fall through */ - d->stage = 2; - - case 2: - stride = d->cinfo.output_width * d->cinfo.output_components; - - while (d->cinfo.output_scanline < d->cinfo.output_height) - { - if (out->wp + stride > out->ep) - goto needoutput; - - scanlines[0] = out->wp; - - i = jpeg_read_scanlines(&d->cinfo, scanlines, 1); - - if (i == 0) - goto needinput; - - out->wp += stride; - } - - /* fall through */ - d->stage = 3; - - case 3: - b = jpeg_finish_decompress(&d->cinfo); - if (b == FALSE) - goto needinput; - d->stage = 4; - in->rp = in->wp - d->src.super.bytes_in_buffer; - return fz_iodone; - } - -needinput: - in->rp = in->wp - d->src.super.bytes_in_buffer; - return fz_ioneedin; - -needoutput: - in->rp = in->wp - d->src.super.bytes_in_buffer; - return fz_ioneedout; -} - diff --git a/stream/filt_dcte.c b/stream/filt_dcte.c deleted file mode 100644 index 5380c6b1..00000000 --- a/stream/filt_dcte.c +++ /dev/null @@ -1,254 +0,0 @@ -#include "fitz-base.h" -#include "fitz-stream.h" - -#include "filt_dctc.h" - -typedef struct fz_dcte_s fz_dcte; - -struct mydstmgr -{ - struct jpeg_destination_mgr super; - fz_buffer *buf; -}; - -struct fz_dcte_s -{ - fz_filter super; - - struct jpeg_compress_struct cinfo; - struct mydstmgr dst; - struct myerrmgr err; - int stage; - - int columns; - int rows; - int colors; -}; - -static void myinitdest(j_compress_ptr cinfo) { /* empty */ } -static boolean myemptybuf(j_compress_ptr cinfo) { return FALSE; } -static void mytermdest(j_compress_ptr cinfo) { /* empty */ } - -fz_error * -fz_newdcte(fz_filter **fp, fz_obj *params) -{ - fz_error *err; - fz_obj *obj; - int i; - - FZ_NEWFILTER(fz_dcte, e, dcte); - - e->stage = 0; - - obj = fz_dictgets(params, "Columns"); - if (!obj) { fz_free(e); return fz_throw("missing Columns parameter"); } - e->columns = fz_toint(obj); - - obj = fz_dictgets(params, "Rows"); - if (!obj) { fz_free(e); return fz_throw("missing Rows parameter"); } - e->rows = fz_toint(obj); - - obj = fz_dictgets(params, "Colors"); - if (!obj) { fz_free(e); return fz_throw("missing Colors parameter"); } - e->colors = fz_toint(obj); - - /* setup error callback first thing */ - myiniterr(&e->err); - e->cinfo.err = (struct jpeg_error_mgr*) &e->err; - - if (setjmp(e->err.jb)) - { - err = fz_throw("cannot encode jpeg: %s", e->err.msg); - fz_free(e); - return err; - } - - jpeg_create_compress(&e->cinfo); - - /* prepare destination manager */ - e->cinfo.dest = (struct jpeg_destination_mgr *) &e->dst; - e->dst.super.init_destination = myinitdest; - e->dst.super.empty_output_buffer = myemptybuf; - e->dst.super.term_destination = mytermdest; - - e->dst.super.next_output_byte = nil; - e->dst.super.free_in_buffer = 0; - - /* prepare required encoding options */ - e->cinfo.image_width = e->columns; - e->cinfo.image_height = e->rows; - e->cinfo.input_components = e->colors; - - switch (e->colors) { - case 1: e->cinfo.in_color_space = JCS_GRAYSCALE; break; - case 3: e->cinfo.in_color_space = JCS_RGB; break; - case 4: e->cinfo.in_color_space = JCS_CMYK; break; - default: e->cinfo.in_color_space = JCS_UNKNOWN; break; - } - - jpeg_set_defaults(&e->cinfo); - - /* FIXME check this */ - obj = fz_dictgets(params, "ColorTransform"); - if (obj) { - int colortransform = fz_toint(obj); - if (e->colors == 3 && !colortransform) - jpeg_set_colorspace(&e->cinfo, JCS_RGB); - if (e->colors == 4 && colortransform) - jpeg_set_colorspace(&e->cinfo, JCS_YCCK); - if (e->colors == 4 && !colortransform) - jpeg_set_colorspace(&e->cinfo, JCS_CMYK); - } - - obj = fz_dictgets(params, "HSamples"); - if (obj && fz_isarray(obj)) { - fz_obj *o; - for (i = 0; i < e->colors; i++) { - o = fz_arrayget(obj, i); - e->cinfo.comp_info[i].h_samp_factor = fz_toint(o); - } - } - - obj = fz_dictgets(params, "VSamples"); - if (obj && fz_isarray(obj)) { - fz_obj *o; - for (i = 0; i < e->colors; i++) { - o = fz_arrayget(obj, i); - e->cinfo.comp_info[i].v_samp_factor = fz_toint(o); - } - } - - /* TODO: quant-tables and huffman-tables */ - - return fz_okay; -} - -void -fz_dropdcte(fz_filter *filter) -{ - fz_dcte *e = (fz_dcte*)filter; - - if (setjmp(e->err.jb)) { - fz_warn("jpeg error: jpeg_destroy_compress: %s", e->err.msg); - return; - } - - jpeg_destroy_compress(&e->cinfo); -} - -/* Adobe says zigzag order. IJG > v6a says natural order. */ -#if JPEG_LIB_VERSION >= 61 -#define unzigzag(x) unzigzagorder[x] -/* zigzag array position of n'th element of natural array order */ -static const unsigned char unzigzagorder[] = -{ - 0, 1, 5, 6, 14, 15, 27, 28, - 2, 4, 7, 13, 16, 26, 29, 42, - 3, 8, 12, 17, 25, 30, 41, 43, - 9, 11, 18, 24, 31, 40, 44, 53, - 10, 19, 23, 32, 39, 45, 52, 54, - 20, 22, 33, 38, 46, 51, 55, 60, - 21, 34, 37, 47, 50, 56, 59, 61, - 35, 36, 48, 49, 57, 58, 62, 63 -}; -#else -#define unzigzag(x) (x) -#endif - -fz_error * -fz_setquanttables(fz_dcte *e, unsigned int **qtables, int qfactor) -{ - int i, j; - unsigned int table[64]; - - if (setjmp(e->err.jb)) { - return fz_throw("jpeg error: jpeg_add_quant_table: %s", e->err.msg); - } - - /* TODO: check for duplicate tables */ - - for (i = 0; i < e->colors; i++) { - for (j = 0; j < 64; j++) { - table[j] = unzigzag(qtables[i][j]); - } - jpeg_add_quant_table(&e->cinfo, i, table, qfactor, TRUE); - e->cinfo.comp_info[i].quant_tbl_no = i; - } - - return fz_okay; -} - -fz_error * -fz_processdcte(fz_filter *filter, fz_buffer *in, fz_buffer *out) -{ - fz_dcte *e = (fz_dcte*)filter; - JSAMPROW scanline[1]; - int stride; - int i; - - e->dst.buf = out; - e->dst.super.free_in_buffer = out->ep - out->wp; - e->dst.super.next_output_byte = out->wp; - - if (setjmp(e->err.jb)) - { - return fz_throw("cannot encode jpeg: %s", e->err.msg); - } - - switch (e->stage) - { - case 0: - /* must have enough space for markers, typically 600 bytes or so */ - if (out->wp + 1024 > out->ep) - goto needoutput; - - jpeg_start_compress(&e->cinfo, TRUE); - - /* TODO: write Adobe ColorTransform marker */ - - /* fall through */ - e->stage = 1; - - case 1: - stride = e->columns * e->colors; - - while (e->cinfo.next_scanline < e->cinfo.image_height) - { - if (in->rp + stride > in->wp) - goto needinput; - - scanline[0] = in->rp; - - i = jpeg_write_scanlines(&e->cinfo, scanline, 1); - - if (i == 0) - goto needoutput; - - in->rp += stride; - } - - /* fall through */ - e->stage = 2; - - case 2: - /* must have enough space for end markers */ - if (out->wp + 100 > out->ep) - goto needoutput; - - /* finish compress cannot suspend! */ - jpeg_finish_compress(&e->cinfo); - - e->stage = 3; - out->wp = out->ep - e->dst.super.free_in_buffer; - return fz_iodone; - } - -needinput: - out->wp = out->ep - e->dst.super.free_in_buffer; - return fz_ioneedin; - -needoutput: - out->wp = out->ep - e->dst.super.free_in_buffer; - return fz_ioneedout; -} - diff --git a/stream/filt_faxc.h b/stream/filt_faxc.h deleted file mode 100644 index f11334be..00000000 --- a/stream/filt_faxc.h +++ /dev/null @@ -1,125 +0,0 @@ -/* common bit magic */ - -static inline void -printbits(FILE *f, int code, int nbits) -{ - int n, b; - for (n = nbits - 1; n >= 0; n--) - { - b = (code >> n) & 1; - fprintf(f, "%c", b ? '1' : '0'); - } -} - -static inline int -getbit(const unsigned char *buf, int x) -{ - return ( buf[x >> 3] >> ( 7 - (x & 7) ) ) & 1; -} - -static inline void -printline(FILE *f, unsigned char *line, int w) -{ - int i; - for (i = 0; i < w; i++) - fprintf(f, "%c", getbit(line, i) ? '#' : '.'); - fprintf(f, "\n"); -} - -static inline int -getrun(const unsigned char *line, int x, int w, int c) -{ - int z; - int b; - - if (x < 0) - x = 0; - - z = x; - while (z < w) - { - b = getbit(line, z); - if (c != b) - break; - z ++; - } - - return z - x; -} - -static inline int -findchanging(const unsigned char *line, int x, int w) -{ - int a, b; - - if (line == 0) - return w; - - if (x == -1) - { - a = 0; - x = 0; - } - else - { - a = getbit(line, x); - x++; - } - - while (x < w) - { - b = getbit(line, x); - if (a != b) - break; - x++; - } - - return x; -} - -static inline int -findchangingcolor(const unsigned char *line, int x, int w, int color) -{ - if (line == 0) - return w; - - x = findchanging(line, x, w); - - if (x < w && getbit(line, x) != color) - x = findchanging(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; - - 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]; - } -} - diff --git a/stream/filt_faxd.c b/stream/filt_faxd.c deleted file mode 100644 index 3eaf5f3b..00000000 --- a/stream/filt_faxd.c +++ /dev/null @@ -1,470 +0,0 @@ -#include "fitz-base.h" -#include "fitz-stream.h" - -#include "filt_faxd.h" -#include "filt_faxc.h" - -typedef enum fax_stage_e -{ - SNORMAL, /* neutral state, waiting for any code */ - SMAKEUP, /* got a 1d makeup code, waiting for terminating code */ - SEOL, /* at eol, needs output buffer space */ - SH1, SH2 /* in H part 1 and 2 (both makeup and terminating codes) */ -} fax_stage_e; - -/* TODO: uncompressed */ - -typedef struct fz_faxd_s fz_faxd; - -struct fz_faxd_s -{ - fz_filter super; - - int k; - int endofline; - int encodedbytealign; - int columns; - int rows; - int endofblock; - int blackis1; - - int stride; - int ridx; - - int bidx; - unsigned int word; - - fax_stage_e stage; - - int a, c, dim, eolc; - unsigned char *ref; - unsigned char *dst; -}; - -fz_error * -fz_newfaxd(fz_filter **fp, fz_obj *params) -{ - fz_obj *obj; - - FZ_NEWFILTER(fz_faxd, fax, faxd); - - fax->ref = nil; - fax->dst = nil; - - fax->k = 0; - fax->endofline = 0; - fax->encodedbytealign = 0; - fax->columns = 1728; - fax->rows = 0; - fax->endofblock = 1; - fax->blackis1 = 0; - - obj = fz_dictgets(params, "K"); - if (obj) fax->k = fz_toint(obj); - - obj = fz_dictgets(params, "EndOfLine"); - if (obj) fax->endofline = fz_tobool(obj); - - obj = fz_dictgets(params, "EncodedByteAlign"); - if (obj) fax->encodedbytealign = fz_tobool(obj); - - obj = fz_dictgets(params, "Columns"); - if (obj) fax->columns = fz_toint(obj); - - obj = fz_dictgets(params, "Rows"); - if (obj) fax->rows = fz_toint(obj); - - obj = fz_dictgets(params, "EndOfBlock"); - if (obj) fax->endofblock = fz_tobool(obj); - - obj = fz_dictgets(params, "BlackIs1"); - if (obj) fax->blackis1 = fz_tobool(obj); - - fax->stride = ((fax->columns - 1) >> 3) + 1; - fax->ridx = 0; - fax->bidx = 32; - fax->word = 0; - - fax->stage = SNORMAL; - fax->a = -1; - fax->c = 0; - fax->dim = fax->k < 0 ? 2 : 1; - fax->eolc = 0; - - fax->ref = fz_malloc(fax->stride); - if (!fax->ref) - { - fz_free(fax); - return fz_throw("outofmem: scanline buffer one"); - } - - fax->dst = fz_malloc(fax->stride); - if (!fax->dst) - { - fz_free(fax); - fz_free(fax->ref); - return fz_throw("outofmem: scanline buffer two"); - } - - memset(fax->ref, 0, fax->stride); - memset(fax->dst, 0, fax->stride); - - return fz_okay; -} - -void -fz_dropfaxd(fz_filter *p) -{ - fz_faxd *fax = (fz_faxd*) p; - fz_free(fax->ref); - fz_free(fax->dst); -} - -static inline void eatbits(fz_faxd *fax, int nbits) -{ - fax->word <<= nbits; - fax->bidx += nbits; -} - -static inline fz_error * fillbits(fz_faxd *fax, fz_buffer *in) -{ - while (fax->bidx >= 8) - { - if (in->rp + 1 > in->wp) - return fz_ioneedin; - fax->bidx -= 8; - fax->word |= *in->rp << fax->bidx; - in->rp ++; - } - return fz_okay; -} - -static int -getcode(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; - } - - eatbits(fax, nbits); - - return val; -} - -/* decode one 1d code */ -static fz_error * -dec1d(fz_faxd *fax) -{ - int code; - - if (fax->a == -1) - fax->a = 0; - - if (fax->c) - code = getcode(fax, cf_black_decode, cfd_black_initial_bits); - else - code = getcode(fax, cf_white_decode, cfd_white_initial_bits); - - if (code == UNCOMPRESSED) - return fz_throw("uncompressed data in faxd"); - - if (code < 0) - return fz_throw("negative code in 1d faxd"); - - if (fax->a + code > fax->columns) - return fz_throw("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 = SNORMAL; - } - else - fax->stage = SMAKEUP; - - return fz_okay; -} - -/* decode one 2d code */ -static fz_error * -dec2d(fz_faxd *fax) -{ - int code, b1, b2; - - if (fax->stage == SH1 || fax->stage == SH2) - { - if (fax->a == -1) - fax->a = 0; - - if (fax->c) - code = getcode(fax, cf_black_decode, cfd_black_initial_bits); - else - code = getcode(fax, cf_white_decode, cfd_white_initial_bits); - - if (code == UNCOMPRESSED) - return fz_throw("uncompressed data in faxd"); - - if (code < 0) - return fz_throw("negative code in 2d faxd"); - - if (fax->a + code > fax->columns) - return fz_throw("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 == SH1) - fax->stage = SH2; - else if (fax->stage == SH2) - fax->stage = SNORMAL; - } - - return fz_okay; - } - - code = getcode(fax, cf_2d_decode, cfd_2d_initial_bits); - - switch (code) - { - case H: - fax->stage = SH1; - break; - - case P: - b1 = findchangingcolor(fax->ref, fax->a, fax->columns, !fax->c); - b2 = findchanging(fax->ref, b1, fax->columns); - if (fax->c) setbits(fax->dst, fax->a, b2); - fax->a = b2; - break; - - case V0: - b1 = findchangingcolor(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 = findchangingcolor(fax->ref, fax->a, fax->columns, !fax->c); - if (fax->c) setbits(fax->dst, fax->a, b1 + 1); - fax->a = b1 + 1; - fax->c = !fax->c; - break; - - case VR2: - b1 = findchangingcolor(fax->ref, fax->a, fax->columns, !fax->c); - if (fax->c) setbits(fax->dst, fax->a, b1 + 2); - fax->a = b1 + 2; - fax->c = !fax->c; - break; - - case VR3: - b1 = findchangingcolor(fax->ref, fax->a, fax->columns, !fax->c); - if (fax->c) setbits(fax->dst, fax->a, b1 + 3); - fax->a = b1 + 3; - fax->c = !fax->c; - break; - - case VL1: - b1 = findchangingcolor(fax->ref, fax->a, fax->columns, !fax->c); - if (fax->c) setbits(fax->dst, fax->a, b1 - 1); - fax->a = b1 - 1; - fax->c = !fax->c; - break; - - case VL2: - b1 = findchangingcolor(fax->ref, fax->a, fax->columns, !fax->c); - if (fax->c) setbits(fax->dst, fax->a, b1 - 2); - fax->a = b1 - 2; - fax->c = !fax->c; - break; - - case VL3: - b1 = findchangingcolor(fax->ref, fax->a, fax->columns, !fax->c); - if (fax->c) setbits(fax->dst, fax->a, b1 - 3); - fax->a = b1 - 3; - fax->c = !fax->c; - break; - - case UNCOMPRESSED: - return fz_throw("uncompressed data in faxd"); - - case ERROR: - return fz_throw("invalid code in 2d faxd"); - - default: - return fz_throw("invalid code in 2d faxd (%d)", code); - } - - return 0; -} - -fz_error * -fz_processfaxd(fz_filter *f, fz_buffer *in, fz_buffer *out) -{ - fz_faxd *fax = (fz_faxd*)f; - fz_error *error; - int i; - unsigned char *tmp; - - if (fax->stage == SEOL) - goto eol; - -loop: - - if (fillbits(fax, in)) - { - if (in->eof) - { - if (fax->bidx > 31) - { - if (fax->a > 0) - goto eol; - goto rtc; - } - } - else - { - return fz_ioneedin; - } - } - - if ((fax->word >> (32 - 12)) == 0) - { - eatbits(fax, 1); - goto loop; - } - - if ((fax->word >> (32 - 12)) == 1) - { - eatbits(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; - eatbits(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; - eatbits(fax, 1); - } - else if (fax->dim == 1) - { - fax->eolc = 0; - error = dec1d(fax); - if (error) return error; /* can be fz_io* or real error */ - - } - else if (fax->dim == 2) - { - fax->eolc = 0; - error = dec2d(fax); - if (error) return error; /* can be fz_io* or real error */ - } - - /* no eol check after makeup codes nor in the middle of an H code */ - if (fax->stage == SMAKEUP || fax->stage == SH1 || fax->stage == SH2) - 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 = SEOL; - if (out->wp + fax->stride > out->ep) - return fz_ioneedout; - - if (fax->blackis1) - memcpy(out->wp, fax->dst, fax->stride); - else { - unsigned char * restrict d = out->wp; - unsigned char * restrict s = fax->dst; - unsigned w = fax->stride; - for (i = 0; i < w; i++) - *d++ = *s++ ^ 0xff; - } - - tmp = fax->ref; - fax->ref = fax->dst; - fax->dst = tmp; - memset(fax->dst, 0, fax->stride); - out->wp += fax->stride; - - fax->stage = SNORMAL; - fax->c = 0; - fax->a = -1; - fax->ridx ++; - - if (!fax->endofblock && 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 endofline & encodedbytealign, EOLs are *not* optional */ - if (fax->encodedbytealign) - { - if (fax->endofline) - eatbits(fax, (12 - fax->bidx) & 7); - else - eatbits(fax, (8 - fax->bidx) & 7); - } - - goto loop; - -rtc: - i = (32 - fax->bidx) / 8; - while (i-- && in->rp > in->bp) - in->rp --; - - return fz_iodone; -} - diff --git a/stream/filt_faxd.h b/stream/filt_faxd.h deleted file mode 100644 index 9f3fb470..00000000 --- a/stream/filt_faxd.h +++ /dev/null @@ -1,61 +0,0 @@ -/* Fax G3/G4 tables */ - -/* - 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 -}; - -/* Decoding tables */ - -extern const cfd_node cf_white_decode[]; -extern const cfd_node cf_black_decode[]; -extern const cfd_node cf_2d_decode[]; -extern const cfd_node cf_uncompressed_decode[]; - diff --git a/stream/filt_faxdtab.c b/stream/filt_faxdtab.c deleted file mode 100644 index 6efcf053..00000000 --- a/stream/filt_faxdtab.c +++ /dev/null @@ -1,931 +0,0 @@ -/* Tables for CCITTFaxDecode filter. */ - -/* This file was generated automatically. It is governed by the same terms */ -/* as the files scfetab.c and scfdgen.c from which it was derived. */ -/* Consult those files for the licensing terms and conditions. */ - -#include "filt_faxd.h" - -/* White decoding table. */ -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. */ -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. */ -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 } -}; - -/* Uncompresssed decoding table. */ -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 } -}; - -/* Dummy executable code to pacify compilers. */ -void scfdtab_dummy(void) { } - diff --git a/stream/filt_faxe.c b/stream/filt_faxe.c deleted file mode 100644 index 7551fb80..00000000 --- a/stream/filt_faxe.c +++ /dev/null @@ -1,407 +0,0 @@ -#include "fitz-base.h" -#include "fitz-stream.h" - -#include "filt_faxe.h" -#include "filt_faxc.h" - -/* TODO: honor Rows param */ - -typedef struct fz_faxe_s fz_faxe; - -struct fz_faxe_s -{ - fz_filter super; - - int k; - int endofline; - int encodedbytealign; - int columns; - int endofblock; - int blackis1; - - int stride; - int ridx; /* how many rows in total */ - int bidx; /* how many bits are already used in out->wp */ - unsigned char bsave; /* partial byte saved between process() calls */ - - int stage; - int a0, c; /* mid-line coding state */ - - unsigned char *ref; - unsigned char *src; -}; - -fz_error * -fz_newfaxe(fz_filter **fp, fz_obj *params) -{ - fz_obj *obj; - - FZ_NEWFILTER(fz_faxe, fax, faxe); - - fax->ref = nil; - fax->src = nil; - - fax->k = 0; - fax->endofline = 0; - fax->encodedbytealign = 0; - fax->columns = 1728; - fax->endofblock = 1; - fax->blackis1 = 0; - - obj = fz_dictgets(params, "K"); - if (obj) fax->k = fz_toint(obj); - - obj = fz_dictgets(params, "EndOfLine"); - if (obj) fax->endofline = fz_tobool(obj); - - obj = fz_dictgets(params, "EncodedByteAlign"); - if (obj) fax->encodedbytealign = fz_tobool(obj); - - obj = fz_dictgets(params, "Columns"); - if (obj) fax->columns = fz_toint(obj); - - obj = fz_dictgets(params, "EndOfBlock"); - if (obj) fax->endofblock = fz_tobool(obj); - - obj = fz_dictgets(params, "BlackIs1"); - if (obj) fax->blackis1 = fz_tobool(obj); - - fax->stride = ((fax->columns - 1) >> 3) + 1; - fax->bidx = 0; - fax->ridx = 0; - - fax->stage = 0; - fax->a0 = -1; - fax->c = 0; - - fax->ref = fz_malloc(fax->stride); - if (!fax->ref) - { - fz_free(fax); - return fz_throw("outofmemory: scanline buffer one"); - } - - fax->src = fz_malloc(fax->stride); - if (!fax->src) - { - fz_free(fax); - fz_free(fax->ref); - return fz_throw("outofmemory: scanline buffer two"); - } - - memset(fax->ref, 0, fax->stride); - memset(fax->src, 0, fax->stride); - - return fz_okay; -} - -void -fz_dropfaxe(fz_filter *p) -{ - fz_faxe *fax = (fz_faxe*) p; - fz_free(fax->src); - fz_free(fax->ref); -} - -enum { codebytes = 2 }; - -static inline int runbytes(int run) -{ - int m = (run / 64) / 40 + 1; /* number of makeup codes */ - return codebytes * (m + 1); /* bytes for makeup + term codes */ -} - -static void -putbits(fz_faxe *fax, fz_buffer *out, int code, int nbits) -{ - while (nbits > 0) - { - if (fax->bidx == 0) - *out->wp = 0; - - /* code does not fit: shift right */ - if (nbits > (8 - fax->bidx)) - { - *out->wp |= code >> (nbits - (8 - fax->bidx)); - nbits = nbits - (8 - fax->bidx); - fax->bidx = 0; - out->wp ++; - } - - /* shift left */ - else - { - *out->wp |= code << ((8 - fax->bidx) - nbits); - fax->bidx += nbits; - if (fax->bidx == 8) - { - fax->bidx = 0; - out->wp ++; - } - nbits = 0; - } - } -} - -static inline void -putcode(fz_faxe *fax, fz_buffer *out, const cfe_code *run) -{ - putbits(fax, out, run->code, run->nbits); -} - -static void -putrun(fz_faxe *fax, fz_buffer *out, int run, int c) -{ - int m; - - const cf_runs *codetable = c ? &cf_black_runs : &cf_white_runs; - - if (run > 63) - { - m = run / 64; - while (m > 40) - { - putcode(fax, out, &codetable->makeup[40]); - m -= 40; - } - if (m > 0) - { - putcode(fax, out, &codetable->makeup[m]); - } - putcode(fax, out, &codetable->termination[run % 64]); - } - else - { - putcode(fax, out, &codetable->termination[run]); - } -} - -static fz_error * -enc1d(fz_faxe *fax, unsigned char *line, fz_buffer *out) -{ - int run; - - if (fax->a0 < 0) - fax->a0 = 0; - - while (fax->a0 < fax->columns) - { - run = getrun(line, fax->a0, fax->columns, fax->c); - - if (out->wp + 1 + runbytes(run) > out->ep) - return fz_ioneedout; - - putrun(fax, out, run, fax->c); - - fax->a0 += run; - fax->c = !fax->c; - } - - return fz_okay; -} - -static fz_error * -enc2d(fz_faxe *fax, unsigned char *ref, unsigned char *src, fz_buffer *out) -{ - int a1, a2, b1, b2; - int run1, run2, n; - - while (fax->a0 < fax->columns) - { - a1 = findchanging(src, fax->a0, fax->columns); - b1 = findchangingcolor(ref, fax->a0, fax->columns, !fax->c); - b2 = findchanging(ref, b1, fax->columns); - - /* pass */ - if (b2 < a1) - { - if (out->wp + 1 + codebytes > out->ep) - return fz_ioneedout; - - putcode(fax, out, &cf2_run_pass); - - fax->a0 = b2; - } - - /* vertical */ - else if (ABS(b1 - a1) <= 3) - { - if (out->wp + 1 + codebytes > out->ep) - return fz_ioneedout; - - putcode(fax, out, &cf2_run_vertical[b1 - a1 + 3]); - - fax->a0 = a1; - fax->c = !fax->c; - } - - /* horizontal */ - else - { - a2 = findchanging(src, a1, fax->columns); - run1 = a1 - fax->a0; - run2 = a2 - a1; - n = codebytes + runbytes(run1) + runbytes(run2); - - if (out->wp + 1 + n > out->ep) - return fz_ioneedout; - - putcode(fax, out, &cf2_run_horizontal); - putrun(fax, out, run1, fax->c); - putrun(fax, out, run2, !fax->c); - - fax->a0 = a2; - } - } - - return fz_okay; -} - -static fz_error * -process(fz_faxe *fax, fz_buffer *in, fz_buffer *out) -{ - fz_error *error; - int i, n; - - while (1) - { - if (in->rp == in->wp && in->eof) - goto rtc; - - switch (fax->stage) - { - case 0: - if (fax->encodedbytealign) - { - if (fax->endofline) - { - if (out->wp + 1 + 1 > out->ep) - return fz_ioneedout; - - /* make sure that EOL ends on a byte border */ - putbits(fax, out, 0, (12 - fax->bidx) & 7); - } - else - { - if (fax->bidx) - { - if (out->wp + 1 > out->ep) - return fz_ioneedout; - fax->bidx = 0; - out->wp ++; - } - } - } - - fax->stage ++; - - case 1: - if (fax->endofline) - { - if (out->wp + 1 + codebytes + 1 > out->ep) - return fz_ioneedout; - - if (fax->k > 0) - { - if (fax->ridx % fax->k == 0) - putcode(fax, out, &cf2_run_eol_1d); - else - putcode(fax, out, &cf2_run_eol_2d); - } - else - { - putcode(fax, out, &cf_run_eol); - } - } - - fax->stage ++; - - case 2: - if (in->rp + fax->stride > in->wp) - { - if (in->eof) /* XXX barf here? */ - goto rtc; - return fz_ioneedin; - } - - memcpy(fax->ref, fax->src, fax->stride); - memcpy(fax->src, in->rp, fax->stride); - - if (!fax->blackis1) - { - for (i = 0; i < fax->stride; i++) - fax->src[i] = ~fax->src[i]; - } - - in->rp += fax->stride; - - fax->c = 0; - fax->a0 = -1; - - fax->stage ++; - - case 3: - error = 0; /* to silence compiler */ - - if (fax->k < 0) - error = enc2d(fax, fax->ref, fax->src, out); - - else if (fax->k == 0) - error = enc1d(fax, fax->src, out); - - else if (fax->k > 0) - { - if (fax->ridx % fax->k == 0) - error = enc1d(fax, fax->src, out); - else - error = enc2d(fax, fax->ref, fax->src, out); - } - - if (error) - return error; /* one of fz_io* */ - - fax->ridx ++; - - fax->stage = 0; - } - } - -rtc: - if (fax->endofblock) - { - n = fax->k < 0 ? 2 : 6; - - if (out->wp + 1 + codebytes * n > out->ep) - return fz_ioneedout; - - for (i = 0; i < n; i++) - { - putcode(fax, out, &cf_run_eol); - if (fax->k > 0) - putbits(fax, out, 1, 1); - } - } - - if (fax->bidx) - out->wp ++; - - return fz_iodone; -} - -fz_error * -fz_processfaxe(fz_filter *p, fz_buffer *in, fz_buffer *out) -{ - fz_faxe *fax = (fz_faxe*) p; - fz_error *error; - - /* restore partial bits */ - *out->wp = fax->bsave; - - error = process(fax, in, out); - - /* save partial bits */ - fax->bsave = *out->wp; - - return error; -} - diff --git a/stream/filt_faxe.h b/stream/filt_faxe.h deleted file mode 100644 index dd3fc121..00000000 --- a/stream/filt_faxe.h +++ /dev/null @@ -1,37 +0,0 @@ -/* Fax G3/G4 tables */ - -typedef struct cfe_code_s cfe_code; - -struct cfe_code_s -{ - unsigned short code; - unsigned short nbits; -}; - -typedef struct cf_runs_s { - cfe_code termination[64]; - cfe_code makeup[41]; -} cf_runs; - -/* Encoding tables */ - -/* Codes common to 1-D and 2-D encoding. */ -extern const cfe_code cf_run_eol; -extern const cf_runs cf_white_runs, cf_black_runs; -extern const cfe_code cf_uncompressed[6]; -extern const cfe_code cf_uncompressed_exit[10]; /* indexed by 2 x length of */ - -/* 1-D encoding. */ -extern const cfe_code cf1_run_uncompressed; - -/* 2-D encoding. */ -enum { cf2_run_vertical_offset = 3 }; -extern const cfe_code cf2_run_pass; -extern const cfe_code cf2_run_vertical[7]; /* indexed by b1 - a1 + offset */ -extern const cfe_code cf2_run_horizontal; -extern const cfe_code cf2_run_uncompressed; - -/* 2-D Group 3 encoding. */ -extern const cfe_code cf2_run_eol_1d; -extern const cfe_code cf2_run_eol_2d; - diff --git a/stream/filt_faxetab.c b/stream/filt_faxetab.c deleted file mode 100644 index 34914c2d..00000000 --- a/stream/filt_faxetab.c +++ /dev/null @@ -1,131 +0,0 @@ -/* Tables for CCITTFaxEncode filter */ - -#include "filt_faxe.h" - -/* Define the end-of-line code. */ -const cfe_code cf_run_eol = {1, 12}; - -/* Define the 1-D code that signals uncompressed data. */ -const cfe_code cf1_run_uncompressed = {0xf, 12}; - -/* Define the 2-D run codes. */ -const cfe_code cf2_run_pass = {0x1, 4}; -const cfe_code cf2_run_vertical[7] = -{ - {0x3, 7}, - {0x3, 6}, - {0x3, 3}, - {0x1, 1}, - {0x2, 3}, - {0x2, 6}, - {0x2, 7} -}; -const cfe_code cf2_run_horizontal = {1, 3}; -const cfe_code cf2_run_uncompressed = {0xf, 10}; - -/* EOL codes for Group 3 2-D. */ -const cfe_code cf2_run_eol_1d = { (1 << 1) + 1, 12 + 1}; -const cfe_code cf2_run_eol_2d = { (1 << 1) + 0, 12 + 1}; - -/* White run codes. */ -const cf_runs cf_white_runs = -{ - /* Termination codes */ - { - {0x35, 8}, {0x7, 6}, {0x7, 4}, {0x8, 4}, - {0xb, 4}, {0xc, 4}, {0xe, 4}, {0xf, 4}, - {0x13, 5}, {0x14, 5}, {0x7, 5}, {0x8, 5}, - {0x8, 6}, {0x3, 6}, {0x34, 6}, {0x35, 6}, - {0x2a, 6}, {0x2b, 6}, {0x27, 7}, {0xc, 7}, - {0x8, 7}, {0x17, 7}, {0x3, 7}, {0x4, 7}, - {0x28, 7}, {0x2b, 7}, {0x13, 7}, {0x24, 7}, - {0x18, 7}, {0x2, 8}, {0x3, 8}, {0x1a, 8}, - {0x1b, 8}, {0x12, 8}, {0x13, 8}, {0x14, 8}, - {0x15, 8}, {0x16, 8}, {0x17, 8}, {0x28, 8}, - {0x29, 8}, {0x2a, 8}, {0x2b, 8}, {0x2c, 8}, - {0x2d, 8}, {0x4, 8}, {0x5, 8}, {0xa, 8}, - {0xb, 8}, {0x52, 8}, {0x53, 8}, {0x54, 8}, - {0x55, 8}, {0x24, 8}, {0x25, 8}, {0x58, 8}, - {0x59, 8}, {0x5a, 8}, {0x5b, 8}, {0x4a, 8}, - {0x4b, 8}, {0x32, 8}, {0x33, 8}, {0x34, 8} - }, - - /* Make-up codes */ - { - {0, 0} /* dummy */ , {0x1b, 5}, {0x12, 5}, {0x17, 6}, - {0x37, 7}, {0x36, 8}, {0x37, 8}, {0x64, 8}, - {0x65, 8}, {0x68, 8}, {0x67, 8}, {0xcc, 9}, - {0xcd, 9}, {0xd2, 9}, {0xd3, 9}, {0xd4, 9}, - {0xd5, 9}, {0xd6, 9}, {0xd7, 9}, {0xd8, 9}, - {0xd9, 9}, {0xda, 9}, {0xdb, 9}, {0x98, 9}, - {0x99, 9}, {0x9a, 9}, {0x18, 6}, {0x9b, 9}, - {0x8, 11}, {0xc, 11}, {0xd, 11}, {0x12, 12}, - {0x13, 12}, {0x14, 12}, {0x15, 12}, {0x16, 12}, - {0x17, 12}, {0x1c, 12}, {0x1d, 12}, {0x1e, 12}, - {0x1f, 12} - } -}; - -/* Black run codes. */ -const cf_runs cf_black_runs = -{ - /* Termination codes */ - { - {0x37, 10}, {0x2, 3}, {0x3, 2}, {0x2, 2}, - {0x3, 3}, {0x3, 4}, {0x2, 4}, {0x3, 5}, - {0x5, 6}, {0x4, 6}, {0x4, 7}, {0x5, 7}, - {0x7, 7}, {0x4, 8}, {0x7, 8}, {0x18, 9}, - {0x17, 10}, {0x18, 10}, {0x8, 10}, {0x67, 11}, - {0x68, 11}, {0x6c, 11}, {0x37, 11}, {0x28, 11}, - {0x17, 11}, {0x18, 11}, {0xca, 12}, {0xcb, 12}, - {0xcc, 12}, {0xcd, 12}, {0x68, 12}, {0x69, 12}, - {0x6a, 12}, {0x6b, 12}, {0xd2, 12}, {0xd3, 12}, - {0xd4, 12}, {0xd5, 12}, {0xd6, 12}, {0xd7, 12}, - {0x6c, 12}, {0x6d, 12}, {0xda, 12}, {0xdb, 12}, - {0x54, 12}, {0x55, 12}, {0x56, 12}, {0x57, 12}, - {0x64, 12}, {0x65, 12}, {0x52, 12}, {0x53, 12}, - {0x24, 12}, {0x37, 12}, {0x38, 12}, {0x27, 12}, - {0x28, 12}, {0x58, 12}, {0x59, 12}, {0x2b, 12}, - {0x2c, 12}, {0x5a, 12}, {0x66, 12}, {0x67, 12} - }, - - /* Make-up codes. */ - { - {0, 0} /* dummy */ , {0xf, 10}, {0xc8, 12}, {0xc9, 12}, - {0x5b, 12}, {0x33, 12}, {0x34, 12}, {0x35, 12}, - {0x6c, 13}, {0x6d, 13}, {0x4a, 13}, {0x4b, 13}, - {0x4c, 13}, {0x4d, 13}, {0x72, 13}, {0x73, 13}, - {0x74, 13}, {0x75, 13}, {0x76, 13}, {0x77, 13}, - {0x52, 13}, {0x53, 13}, {0x54, 13}, {0x55, 13}, - {0x5a, 13}, {0x5b, 13}, {0x64, 13}, {0x65, 13}, - {0x8, 11}, {0xc, 11}, {0xd, 11}, {0x12, 12}, - {0x13, 12}, {0x14, 12}, {0x15, 12}, {0x16, 12}, - {0x17, 12}, {0x1c, 12}, {0x1d, 12}, {0x1e, 12}, - {0x1f, 12} - } -}; - -/* Uncompressed codes. */ -const cfe_code cf_uncompressed[6] = -{ - {1, 1}, - {1, 2}, - {1, 3}, - {1, 4}, - {1, 5}, - {1, 6} -}; - -/* Uncompressed exit codes. */ -const cfe_code cf_uncompressed_exit[10] = -{ - {2, 8}, {3, 8}, - {2, 9}, {3, 9}, - {2, 10}, {3, 10}, - {2, 11}, {3, 11}, - {2, 12}, {3, 12} -}; - -/* Some C compilers insist on having executable code in every file.... */ -void scfetab_dummy(void) { } - diff --git a/stream/filt_flate.c b/stream/filt_flate.c deleted file mode 100644 index 6a86da3a..00000000 --- a/stream/filt_flate.c +++ /dev/null @@ -1,208 +0,0 @@ -#include "fitz-base.h" -#include "fitz-stream.h" - -#include - -typedef struct fz_flate_s fz_flate; - -struct fz_flate_s -{ - fz_filter super; - z_stream z; -}; - -static void * -zmalloc(void *opaque, unsigned int items, unsigned int size) -{ - return fz_malloc(items * size); -} - -fz_error * -fz_newflated(fz_filter **fp, fz_obj *params) -{ - fz_error *eo; - fz_obj *obj; - int zipfmt; - int ei; - - FZ_NEWFILTER(fz_flate, f, flated); - - f->z.zalloc = zmalloc; - f->z.zfree = (void(*)(void*,void*))fz_currentmemorycontext()->free; - f->z.opaque = fz_currentmemorycontext(); - f->z.next_in = nil; - f->z.avail_in = 0; - - zipfmt = 0; - - if (params) - { - obj = fz_dictgets(params, "ZIP"); - if (obj) zipfmt = fz_tobool(obj); - } - - if (zipfmt) - { - /* if windowbits is negative the zlib header is skipped */ - ei = inflateInit2(&f->z, -15); - } - else - ei = inflateInit(&f->z); - - if (ei != Z_OK) - { - eo = fz_throw("zlib error: inflateInit: %s", f->z.msg); - fz_free(f); - return eo; - } - - return fz_okay; -} - -void -fz_dropflated(fz_filter *f) -{ - z_streamp zp = &((fz_flate*)f)->z; - int err; - - err = inflateEnd(zp); - if (err != Z_OK) - fprintf(stderr, "inflateEnd: %s", zp->msg); -} - -fz_error * -fz_processflated(fz_filter *f, fz_buffer *in, fz_buffer *out) -{ - z_streamp zp = &((fz_flate*)f)->z; - int err; - - if (in->rp == in->wp && !in->eof) - return fz_ioneedin; - if (out->wp == out->ep) - return fz_ioneedout; - - zp->next_in = in->rp; - zp->avail_in = in->wp - in->rp; - - zp->next_out = out->wp; - zp->avail_out = out->ep - out->wp; - - err = inflate(zp, Z_NO_FLUSH); - - in->rp = in->wp - zp->avail_in; - out->wp = out->ep - zp->avail_out; - - if (err == Z_STREAM_END || err == Z_BUF_ERROR) - { - return fz_iodone; - } - else if (err == Z_OK) - { - if (in->rp == in->wp && !in->eof) - return fz_ioneedin; - if (out->wp == out->ep) - return fz_ioneedout; - return fz_ioneedin; /* hmm, what's going on here? */ - } - else - { - return fz_throw("zlib error: inflate: %s", zp->msg); - } -} - -fz_error * -fz_newflatee(fz_filter **fp, fz_obj *params) -{ - fz_obj *obj; - fz_error *eo; - int effort; - int zipfmt; - int ei; - - FZ_NEWFILTER(fz_flate, f, flatee); - - effort = -1; - zipfmt = 0; - - if (params) - { - obj = fz_dictgets(params, "Effort"); - if (obj) effort = fz_toint(obj); - obj = fz_dictgets(params, "ZIP"); - if (obj) zipfmt = fz_tobool(obj); - } - - f->z.zalloc = zmalloc; - f->z.zfree = (void(*)(void*,void*))fz_currentmemorycontext()->free; - f->z.opaque = fz_currentmemorycontext(); - f->z.next_in = nil; - f->z.avail_in = 0; - - if (zipfmt) - ei = deflateInit2(&f->z, effort, Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY); - else - ei = deflateInit(&f->z, effort); - - if (ei != Z_OK) - { - eo = fz_throw("zlib error: deflateInit: %s", f->z.msg); - fz_free(f); - return eo; - } - - return fz_okay; -} - -void -fz_dropflatee(fz_filter *f) -{ - z_streamp zp = &((fz_flate*)f)->z; - int err; - - err = deflateEnd(zp); - if (err != Z_OK) - fprintf(stderr, "deflateEnd: %s", zp->msg); - - fz_free(f); -} - -fz_error * -fz_processflatee(fz_filter *f, fz_buffer *in, fz_buffer *out) -{ - z_streamp zp = &((fz_flate*)f)->z; - int err; - - if (in->rp == in->wp && !in->eof) - return fz_ioneedin; - if (out->wp == out->ep) - return fz_ioneedout; - - zp->next_in = in->rp; - zp->avail_in = in->wp - in->rp; - - zp->next_out = out->wp; - zp->avail_out = out->ep - out->wp; - - err = deflate(zp, in->eof ? Z_FINISH : Z_NO_FLUSH); - - in->rp = in->wp - zp->avail_in; - out->wp = out->ep - zp->avail_out; - - if (err == Z_STREAM_END) - { - return fz_iodone; - } - else if (err == Z_OK) - { - if (in->rp == in->wp && !in->eof) - return fz_ioneedin; - if (out->wp == out->ep) - return fz_ioneedout; - return fz_ioneedin; /* hmm? */ - } - else - { - return fz_throw("zlib error: deflate: %s", zp->msg); - } -} - diff --git a/stream/filt_jbig2d.c b/stream/filt_jbig2d.c deleted file mode 100644 index 3569d3eb..00000000 --- a/stream/filt_jbig2d.c +++ /dev/null @@ -1,119 +0,0 @@ -#include "fitz-base.h" -#include "fitz-stream.h" - -/* TODO: complete rewrite with error checking and use fitz memctx */ - -/* - so to use a global_ctx, you run your global data through a normal ctx - then call jbig2_make_global_ctx with the normal context - that does the (currently null) conversion - make_global_ctx after i fed it all the global stream data? - maskros: yes - and you pass the new global ctx object to jbig2_ctx_new() when you -+create the per-page ctx -*/ - -#ifdef WIN32 /* Microsoft Visual C++ */ - -typedef signed char int8_t; -typedef short int int16_t; -typedef int int32_t; -typedef __int64 int64_t; - -typedef unsigned char uint8_t; -typedef unsigned short int uint16_t; -typedef unsigned int uint32_t; - -#else -#include -#endif - -#include - -typedef struct fz_jbig2d_s fz_jbig2d; - -struct fz_jbig2d_s -{ - fz_filter super; - Jbig2Ctx *ctx; - Jbig2GlobalCtx *gctx; - Jbig2Image *page; - int idx; -}; - -fz_error * -fz_newjbig2d(fz_filter **fp, fz_obj *params) -{ - FZ_NEWFILTER(fz_jbig2d, d, jbig2d); - d->ctx = jbig2_ctx_new(nil, JBIG2_OPTIONS_EMBEDDED, nil, nil, nil); - d->page = nil; - d->idx = 0; - return fz_okay; -} - -void -fz_dropjbig2d(fz_filter *filter) -{ - fz_jbig2d *d = (fz_jbig2d*)filter; - jbig2_ctx_free(d->ctx); -} - -fz_error * -fz_setjbig2dglobalstream(fz_filter *filter, unsigned char *buf, int len) -{ - fz_jbig2d *d = (fz_jbig2d*)filter; - jbig2_data_in(d->ctx, buf, len); - d->gctx = jbig2_make_global_ctx(d->ctx); - d->ctx = jbig2_ctx_new(nil, JBIG2_OPTIONS_EMBEDDED, d->gctx, nil, nil); - return fz_okay; -} - -fz_error * -fz_processjbig2d(fz_filter *filter, fz_buffer *in, fz_buffer *out) -{ - fz_jbig2d *d = (fz_jbig2d*)filter; - int len; - int i; - - while (1) - { - if (in->rp == in->wp) { - if (!in->eof) - return fz_ioneedin; - - if (!d->page) { - jbig2_complete_page(d->ctx); - d->page = jbig2_page_out(d->ctx); - } - - if (out->wp == out->ep) - return fz_ioneedout; - - len = out->ep - out->wp; - if (d->idx + len > d->page->height * d->page->stride) - len = d->page->height * d->page->stride - d->idx; - - /* XXX memcpy(out->wp, d->page->data + d->idx, len); */ - { - unsigned char * restrict in = &d->page->data[d->idx]; - unsigned char * restrict o = out->wp; - for (i = 0; i < len; i++) - *o++ = 0xff ^ *in++; - } - - out->wp += len; - d->idx += len; - - if (d->idx == d->page->height * d->page->stride) { - jbig2_release_page(d->ctx, d->page); - return fz_iodone; - } - } - else { - len = in->wp - in->rp; - jbig2_data_in(d->ctx, in->rp, len); - in->rp += len; - } - } -} - diff --git a/stream/filt_jpxd.c b/stream/filt_jpxd.c deleted file mode 100644 index 28dc87de..00000000 --- a/stream/filt_jpxd.c +++ /dev/null @@ -1,146 +0,0 @@ -#include "fitz-base.h" -#include "fitz-stream.h" - -/* TODO: bpc */ - -/* - * We use the Jasper JPEG2000 coder for now. - */ - -#include - -static char *colorspacename(jas_clrspc_t clrspc) -{ - switch (jas_clrspc_fam(clrspc)) - { - case JAS_CLRSPC_FAM_UNKNOWN: return "Unknown"; - case JAS_CLRSPC_FAM_XYZ: return "XYZ"; - case JAS_CLRSPC_FAM_LAB: return "Lab"; - case JAS_CLRSPC_FAM_GRAY: return "Gray"; - case JAS_CLRSPC_FAM_RGB: return "RGB"; - case JAS_CLRSPC_FAM_YCBCR: return "YCbCr"; - } - return "Unknown"; -} - -typedef struct fz_jpxd_s fz_jpxd; - -struct fz_jpxd_s -{ - fz_filter super; - jas_stream_t *stream; - jas_image_t *image; - int offset; - int stage; -}; - -fz_error * -fz_newjpxd(fz_filter **fp, fz_obj *params) -{ - int err; - - FZ_NEWFILTER(fz_jpxd, d, jpxd); - - err = jas_init(); - if (err) - { - fz_free(d); - return fz_throw("jasper error: jas_init()"); - } - - d->stream = jas_stream_memopen(nil, 0); - if (!d->stream) - { - fz_free(d); - return fz_throw("jasper error: jas_stream_memopen()"); - } - - d->image = nil; - d->offset = 0; - d->stage = 0; - - return fz_okay; -} - -void -fz_dropjpxd(fz_filter *filter) -{ - fz_jpxd *d = (fz_jpxd*)filter; - if (d->stream) jas_stream_close(d->stream); - if (d->image) jas_image_destroy(d->image); -} - -fz_error * -fz_processjpxd(fz_filter *filter, fz_buffer *in, fz_buffer *out) -{ - fz_jpxd *d = (fz_jpxd*)filter; - int n, bpc, w, h; - int i, x, y; - - switch (d->stage) - { - case 0: goto input; - case 1: goto decode; - case 2: goto output; - } - -input: - while (in->rp < in->wp) - { - n = jas_stream_write(d->stream, in->rp, in->wp - in->rp); - in->rp += n; - } - - if (!in->eof) - return fz_ioneedin; - - d->stage = 1; - -decode: - jas_stream_seek(d->stream, 0, 0); - - d->image = jas_image_decode(d->stream, -1, 0); - if (!d->image) - return fz_throw("jasper error: jas_image_decode()"); - - fprintf(stderr, "P%c\n# JPX %d x %d n=%d bpc=%d colorspace=%04x %s\n%d %d\n%d\n", - jas_image_numcmpts(d->image) == 1 ? '5' : '6', - - jas_image_width(d->image), - jas_image_height(d->image), - jas_image_numcmpts(d->image), - jas_image_cmptprec(d->image, 0), - jas_image_clrspc(d->image), - colorspacename(jas_image_clrspc(d->image)), - - jas_image_width(d->image), - jas_image_height(d->image), - (1 << jas_image_cmptprec(d->image, 0)) - 1); - - d->stage = 2; - -output: - w = jas_image_width(d->image); - h = jas_image_height(d->image); - n = jas_image_numcmpts(d->image); - bpc = jas_image_cmptprec(d->image, 0); /* use precision of first component for all... */ - - while (d->offset < w * h) - { - y = d->offset / w; - x = d->offset - y * w; - - /* FIXME bpc != 8 */ - - if (out->wp + n >= out->ep) - return fz_ioneedout; - - for (i = 0; i < n; i++) - *out->wp++ = jas_image_readcmptsample(d->image, i, x, y); - - d->offset ++; - } - - return fz_iodone; -} - diff --git a/stream/filt_lzwd.c b/stream/filt_lzwd.c deleted file mode 100644 index c4aed45b..00000000 --- a/stream/filt_lzwd.c +++ /dev/null @@ -1,254 +0,0 @@ -#include "fitz-base.h" -#include "fitz-stream.h" - -/* TODO: error checking */ - -enum -{ - MINBITS = 9, - MAXBITS = 12, - NUMCODES = (1 << MAXBITS), - LZW_CLEAR = 256, - LZW_EOD = 257, - LZW_FIRST = 258 -}; - -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 firstchar; /* first token of string */ -}; - -typedef struct fz_lzwd_s fz_lzwd; - -struct fz_lzwd_s -{ - fz_filter super; - - int earlychange; - - unsigned int word; /* bits loaded from data */ - int bidx; - - int resume; /* resume output of code from needout */ - int codebits; /* num bits/code */ - int code; /* current code */ - int oldcode; /* previously recognized code */ - int nextcode; /* next free entry */ - lzw_code table[NUMCODES]; -}; - -fz_error * -fz_newlzwd(fz_filter **fp, fz_obj *params) -{ - int i; - - FZ_NEWFILTER(fz_lzwd, lzw, lzwd); - - lzw->earlychange = 0; - - if (params) - { - fz_obj *obj; - obj = fz_dictgets(params, "EarlyChange"); - if (obj) lzw->earlychange = fz_toint(obj) != 0; - } - - lzw->bidx = 32; - lzw->word = 0; - - for (i = 0; i < 256; i++) - { - lzw->table[i].value = i; - lzw->table[i].firstchar = i; - lzw->table[i].length = 1; - lzw->table[i].prev = -1; - } - - for (i = 256; i < NUMCODES; i++) - { - lzw->table[i].value = 0; - lzw->table[i].firstchar = 0; - lzw->table[i].length = 0; - lzw->table[i].prev = -1; - } - - lzw->codebits = MINBITS; - lzw->code = -1; - lzw->nextcode = LZW_FIRST; - lzw->oldcode = -1; - lzw->resume = 0; - - return fz_okay; -} - -void -fz_droplzwd(fz_filter *filter) -{ -} - -static inline void eatbits(fz_lzwd *lzw, int nbits) -{ - lzw->word <<= nbits; - lzw->bidx += nbits; -} - -static inline fz_error * fillbits(fz_lzwd *lzw, fz_buffer *in) -{ - while (lzw->bidx >= 8) - { - if (in->rp + 1 > in->wp) - return fz_ioneedin; - lzw->bidx -= 8; - lzw->word |= *in->rp << lzw->bidx; - in->rp ++; - } - return fz_okay; -} - -static inline void unstuff(fz_lzwd *lzw, fz_buffer *in) -{ - int i = (32 - lzw->bidx) / 8; - while (i-- && in->rp > in->bp) - in->rp --; -} - -fz_error * -fz_processlzwd(fz_filter *filter, fz_buffer *in, fz_buffer *out) -{ - fz_lzwd *lzw = (fz_lzwd*)filter; - unsigned char *s; - int len; - - if (lzw->resume) - { - lzw->resume = 0; - goto output; - } - - while (1) - { - if (fillbits(lzw, in)) - { - if (in->eof) - { - if (lzw->bidx > 32 - lzw->codebits) - { - unstuff(lzw, in); - return fz_iodone; - } - } - else - { - return fz_ioneedin; - } - } - - lzw->code = lzw->word >> (32 - lzw->codebits); - - if (lzw->code == LZW_EOD) - { - eatbits(lzw, lzw->codebits); - unstuff(lzw, in); - return fz_iodone; - } - - if (lzw->code == LZW_CLEAR) - { - int oldcodebits = lzw->codebits; - - lzw->codebits = MINBITS; - lzw->nextcode = LZW_FIRST; - - lzw->code = lzw->word >> (32 - oldcodebits - MINBITS) & ((1 << MINBITS) - 1); - - if (lzw->code == LZW_EOD) - { - eatbits(lzw, oldcodebits + MINBITS); - unstuff(lzw, in); - return fz_iodone; - } - - eatbits(lzw, oldcodebits + MINBITS); - - lzw->oldcode = lzw->code; - - if (out->wp + 1 > out->ep) - { - lzw->resume = 1; - return fz_ioneedout; - } - - *out->wp++ = lzw->code; - - continue; - } - - eatbits(lzw, lzw->codebits); - - /* if stream starts without a clear code, oldcode is undefined... */ - if (lzw->oldcode == -1) - { - lzw->oldcode = lzw->code; - goto output; - } - - /* add new entry to the code table */ - lzw->table[lzw->nextcode].prev = lzw->oldcode; - lzw->table[lzw->nextcode].firstchar = lzw->table[lzw->oldcode].firstchar; - lzw->table[lzw->nextcode].length = lzw->table[lzw->oldcode].length + 1; - if (lzw->code < lzw->nextcode) - lzw->table[lzw->nextcode].value = lzw->table[lzw->code].firstchar; - else - lzw->table[lzw->nextcode].value = lzw->table[lzw->nextcode].firstchar; - - lzw->nextcode ++; - - if (lzw->nextcode >= (1 << lzw->codebits) - lzw->earlychange - 1) - { - lzw->codebits ++; - if (lzw->codebits > MAXBITS) - lzw->codebits = MAXBITS; /* FIXME */ - } - - lzw->oldcode = lzw->code; - -output: - /* code maps to a string, copy to output (in reverse...) */ - if (lzw->code > 255) - { - if (out->wp + lzw->table[lzw->code].length > out->ep) - { - lzw->resume = 1; - return fz_ioneedout; - } - - len = lzw->table[lzw->code].length; - s = out->wp + len; - - do - { - *(--s) = lzw->table[lzw->code].value; - lzw->code = lzw->table[lzw->code].prev; - } while (lzw->code >= 0 && s > out->wp); - out->wp += len; - } - - /* ... or just a single character */ - else - { - if (out->wp + 1 > out->ep) - { - lzw->resume = 1; - return fz_ioneedout; - } - - *out->wp++ = lzw->code; - } - } -} - diff --git a/stream/filt_lzwe.c b/stream/filt_lzwe.c deleted file mode 100644 index 5a221f9f..00000000 --- a/stream/filt_lzwe.c +++ /dev/null @@ -1,261 +0,0 @@ -#include "fitz-base.h" -#include "fitz-stream.h" - -#define noDEBUG 1 - -enum -{ - MINBITS = 9, - MAXBITS = 12, - MAXBYTES = 2, - NUMCODES = (1 << MAXBITS), - LZW_CLEAR = 256, - LZW_EOD = 257, - LZW_FIRST = 258, - HSIZE = 9001, /* 91% occupancy (???) */ - HSHIFT = (13 - 8) -}; - -typedef struct lzw_hash_s lzw_hash; - -struct lzw_hash_s -{ - int hash; - int code; -}; - -typedef struct fz_lzwe_s fz_lzwe; - -struct fz_lzwe_s -{ - fz_filter super; - - int earlychange; - - int bidx; /* partial bits used in out->wp */ - unsigned char bsave; /* partial byte saved between process() calls */ - - int resume; - int code; - int fcode; - int hcode; - - int codebits; - int oldcode; - int nextcode; - - lzw_hash table[HSIZE]; -}; - -static void -clearhash(fz_lzwe *lzw) -{ - int i; - for (i = 0; i < HSIZE; i++) - lzw->table[i].hash = -1; -} - -fz_error * -fz_newlzwe(fz_filter **fp, fz_obj *params) -{ - FZ_NEWFILTER(fz_lzwe, lzw, lzwe); - - lzw->earlychange = 0; - - if (params) - { - fz_obj *obj; - obj = fz_dictgets(params, "EarlyChange"); - if (obj) lzw->earlychange = fz_toint(obj) != 0; - } - - lzw->bidx = 0; - lzw->bsave = 0; - - lzw->resume = 0; - lzw->code = -1; - lzw->hcode = -1; - lzw->fcode = -1; - - lzw->codebits = MINBITS; - lzw->nextcode = LZW_FIRST; - lzw->oldcode = -1; /* generates LZW_CLEAR */ - - clearhash(lzw); - - return fz_okay; -} - -void -fz_droplzwe(fz_filter *filter) -{ -} - -static void -putcode(fz_lzwe *lzw, fz_buffer *out, int code) -{ - int nbits = lzw->codebits; - - while (nbits > 0) - { - if (lzw->bidx == 0) - { - *out->wp = 0; - } - - /* code does not fit: shift right */ - if (nbits > (8 - lzw->bidx)) - { - *out->wp |= code >> (nbits - (8 - lzw->bidx)); - nbits = nbits - (8 - lzw->bidx); - lzw->bidx = 0; - out->wp ++; - } - - /* shift left */ - else - { - *out->wp |= code << ((8 - lzw->bidx) - nbits); - lzw->bidx += nbits; - if (lzw->bidx == 8) - { - lzw->bidx = 0; - out->wp ++; - } - nbits = 0; - } - } -} - - -static fz_error * -compress(fz_lzwe *lzw, fz_buffer *in, fz_buffer *out) -{ - if (lzw->resume) - { - lzw->resume = 0; - goto resume; - } - - /* at start of data, output a clear code */ - if (lzw->oldcode == -1) - { - if (out->wp + 3 > out->ep) - return fz_ioneedout; - - if (in->rp + 1 > in->wp) - { - if (in->eof) - goto eof; - return fz_ioneedin; - } - - putcode(lzw, out, LZW_CLEAR); - - lzw->oldcode = *in->rp++; - } - -begin: - while (1) - { - if (in->rp + 1 > in->wp) - { - if (in->eof) - goto eof; - return fz_ioneedin; - } - - /* read character */ - lzw->code = *in->rp++; - - /* hash string + character */ - lzw->fcode = (lzw->code << MAXBITS) + lzw->oldcode; - lzw->hcode = (lzw->code << HSHIFT) ^ lzw->oldcode; - - /* primary hash */ - if (lzw->table[lzw->hcode].hash == lzw->fcode) - { - lzw->oldcode = lzw->table[lzw->hcode].code; - continue; - } - - /* secondary hash */ - if (lzw->table[lzw->hcode].hash != -1) - { - int disp = HSIZE - lzw->hcode; - if (lzw->hcode == 0) - disp = 1; - do - { - lzw->hcode = lzw->hcode - disp; - if (lzw->hcode < 0) - lzw->hcode += HSIZE; - if (lzw->table[lzw->hcode].hash == lzw->fcode) - { - lzw->oldcode = lzw->table[lzw->hcode].code; - goto begin; - } - } while (lzw->table[lzw->hcode].hash != -1); - } - -resume: - /* new entry: emit code and add to table */ - - /* reserve space for this code and an eventual CLEAR code */ - if (out->wp + 5 > out->ep) - { - lzw->resume = 1; - return fz_ioneedout; - } - - putcode(lzw, out, lzw->oldcode); - - lzw->oldcode = lzw->code; - lzw->table[lzw->hcode].code = lzw->nextcode; - lzw->table[lzw->hcode].hash = lzw->fcode; - - lzw->nextcode ++; - - /* table is full: emit clear code and reset */ - if (lzw->nextcode == NUMCODES - 1) - { - putcode(lzw, out, LZW_CLEAR); - clearhash(lzw); - lzw->nextcode = LZW_FIRST; - lzw->codebits = MINBITS; - } - - /* check if next entry will be too big for the code size */ - else if (lzw->nextcode >= (1 << lzw->codebits) - lzw->earlychange) - { - lzw->codebits ++; - } - } - -eof: - if (out->wp + 5 > out->ep) - return fz_ioneedout; - - putcode(lzw, out, lzw->oldcode); - putcode(lzw, out, LZW_EOD); - - return fz_iodone; -} - -fz_error * -fz_processlzwe(fz_filter *filter, fz_buffer *in, fz_buffer *out) -{ - fz_lzwe *lzw = (fz_lzwe*)filter; - fz_error *error; - - /* restore partial bits */ - *out->wp = lzw->bsave; - - error = compress(lzw, in, out); - - /* save partial bits */ - lzw->bsave = *out->wp; - - return error; -} - diff --git a/stream/filt_null.c b/stream/filt_null.c deleted file mode 100644 index 601ed815..00000000 --- a/stream/filt_null.c +++ /dev/null @@ -1,54 +0,0 @@ -#include "fitz-base.h" -#include "fitz-stream.h" - -typedef struct fz_nullfilter_s fz_nullfilter; - -struct fz_nullfilter_s -{ - fz_filter super; - int len; - int cur; -}; - -fz_error * -fz_newnullfilter(fz_filter **fp, int len) -{ - FZ_NEWFILTER(fz_nullfilter, f, nullfilter); - f->len = len; - f->cur = 0; - return fz_okay; -} - -void -fz_dropnullfilter(fz_filter *f) -{ -} - -fz_error * -fz_processnullfilter(fz_filter *filter, fz_buffer *in, fz_buffer *out) -{ - fz_nullfilter *f = (fz_nullfilter*)filter; - int n; - - n = MIN(in->wp - in->rp, out->ep - out->wp); - if (f->len >= 0) - n = MIN(n, f->len - f->cur); - - if (n) - { - memcpy(out->wp, in->rp, n); - in->rp += n; - out->wp += n; - f->cur += n; - } - - if (f->cur == f->len) - return fz_iodone; - if (in->rp == in->wp) - return fz_ioneedin; - if (out->wp == out->ep) - return fz_ioneedout; - - return fz_throw("braindead programmer trapped in nullfilter"); -} - diff --git a/stream/filt_pipeline.c b/stream/filt_pipeline.c deleted file mode 100644 index ea0b9885..00000000 --- a/stream/filt_pipeline.c +++ /dev/null @@ -1,139 +0,0 @@ -#include "fitz-base.h" -#include "fitz-stream.h" - -#define noDEBUG 1 - -typedef struct fz_pipeline_s fz_pipeline; - -fz_error * fz_processpipeline(fz_filter *filter, fz_buffer *in, fz_buffer *out); - -struct fz_pipeline_s -{ - fz_filter super; - fz_filter *head; - fz_buffer *buffer; - fz_filter *tail; - int tailneedsin; -}; - -fz_error * -fz_chainpipeline(fz_filter **fp, fz_filter *head, fz_filter *tail, fz_buffer *buf) -{ - FZ_NEWFILTER(fz_pipeline, p, pipeline); - p->head = fz_keepfilter(head); - p->tail = fz_keepfilter(tail); - p->tailneedsin = 1; - p->buffer = fz_keepbuffer(buf); - return fz_okay; -} - -void -fz_unchainpipeline(fz_filter *filter, fz_filter **oldfp, fz_buffer **oldbp) -{ - fz_pipeline *p = (fz_pipeline*)filter; - - *oldfp = fz_keepfilter(p->head); - *oldbp = fz_keepbuffer(p->buffer); - - fz_dropfilter(filter); -} - -fz_error * -fz_newpipeline(fz_filter **fp, fz_filter *head, fz_filter *tail) -{ - fz_error *error; - - FZ_NEWFILTER(fz_pipeline, p, pipeline); - p->head = fz_keepfilter(head); - p->tail = fz_keepfilter(tail); - p->tailneedsin = 1; - - error = fz_newbuffer(&p->buffer, FZ_BUFSIZE); - if (error) - { - fz_free(p); - return fz_rethrow(error, "cannot create buffer"); - } - - return fz_okay; -} - -void -fz_droppipeline(fz_filter *filter) -{ - fz_pipeline *p = (fz_pipeline*)filter; - fz_dropfilter(p->head); - fz_dropfilter(p->tail); - fz_dropbuffer(p->buffer); -} - -fz_error * -fz_processpipeline(fz_filter *filter, fz_buffer *in, fz_buffer *out) -{ - fz_pipeline *p = (fz_pipeline*)filter; - fz_error *e; - - if (p->buffer->eof) - goto tail; - - if (p->tailneedsin && p->head->produced) - goto tail; - -head: - e = fz_process(p->head, in, p->buffer); - - if (e == fz_ioneedin) - return fz_ioneedin; - - else if (e == fz_ioneedout) - { - if (p->tailneedsin && !p->head->produced) - { - fz_error *be = nil; - if (p->buffer->rp > p->buffer->bp) - be = fz_rewindbuffer(p->buffer); - else - be = fz_growbuffer(p->buffer); - if (be) - return be; - goto head; - } - goto tail; - } - - else if (e == fz_iodone) - goto tail; - - else if (e) - return fz_rethrow(e, "cannot process head filter"); - - else - return fz_okay; - -tail: - e = fz_process(p->tail, p->buffer, out); - - if (e == fz_ioneedin) - { - if (p->buffer->eof) - return fz_throw("ioerror: premature eof in pipeline"); - p->tailneedsin = 1; - goto head; - } - - else if (e == fz_ioneedout) - { - p->tailneedsin = 0; - return fz_ioneedout; - } - - else if (e == fz_iodone) - return fz_iodone; - - else if (e) - return fz_rethrow(e, "cannot process tail filter"); - - else - return fz_okay; -} - diff --git a/stream/filt_predict.c b/stream/filt_predict.c deleted file mode 100644 index 4654e792..00000000 --- a/stream/filt_predict.c +++ /dev/null @@ -1,254 +0,0 @@ -#include "fitz-base.h" -#include "fitz-stream.h" - -/* TODO: check if this works with 16bpp images */ - -enum { MAXC = 32 }; - -typedef struct fz_predict_s fz_predict; - -struct fz_predict_s -{ - fz_filter super; - - int predictor; - int columns; - int colors; - int bpc; - - int stride; - int bpp; - unsigned char *ref; - - int encode; -}; - -fz_error * -fz_newpredict(fz_filter **fp, fz_obj *params, int encode) -{ - fz_obj *obj; - - FZ_NEWFILTER(fz_predict, p, predict); - - p->encode = encode; - - p->predictor = 1; - p->columns = 1; - p->colors = 1; - p->bpc = 8; - - obj = fz_dictgets(params, "Predictor"); - if (obj) p->predictor = fz_toint(obj); - - obj = fz_dictgets(params, "Columns"); - if (obj) p->columns = fz_toint(obj); - - obj = fz_dictgets(params, "Colors"); - if (obj) p->colors = fz_toint(obj); - - obj = fz_dictgets(params, "BitsPerComponent"); - if (obj) p->bpc = fz_toint(obj); - - p->stride = (p->bpc * p->colors * p->columns + 7) / 8; - p->bpp = (p->bpc * p->colors + 7) / 8; - - if (p->predictor >= 10) - { - p->ref = fz_malloc(p->stride); - if (!p->ref) - { - fz_free(p); - return fz_throw("outofmem: scanline buffer"); - } - memset(p->ref, 0, p->stride); - } - else - { - p->ref = nil; - } - - return fz_okay; -} - -void -fz_droppredict(fz_filter *filter) -{ - fz_predict *p = (fz_predict*)filter; - fz_free(p->ref); -} - -static inline int -getcomponent(unsigned char *buf, int x, int bpc) -{ - switch (bpc) - { - case 1: return buf[x / 8] >> (7 - (x % 8)) & 0x01; - case 2: return buf[x / 4] >> ((3 - (x % 4)) * 2) & 0x03; - case 4: return buf[x / 2] >> ((1 - (x % 2)) * 4) & 0x0f; - case 8: return buf[x]; - } - return 0; -} - -static inline void -putcomponent(unsigned char *buf, int x, int bpc, int value) -{ - switch (bpc) - { - case 1: buf[x / 8] |= value << (7 - (x % 8)); break; - case 2: buf[x / 4] |= value << ((3 - (x % 4)) * 2); break; - case 4: buf[x / 2] |= value << ((1 - (x % 2)) * 4); break; - case 8: buf[x] = 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 = (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 inline void -none(fz_predict *p, unsigned char *in, unsigned char *out) -{ - memcpy(out, in, p->stride); -} - -static void -tiff(fz_predict *p, unsigned char *in, unsigned char *out) -{ - int left[MAXC]; - int i, k; - - for (k = 0; k < p->colors; k++) - left[k] = 0; - - for (i = 0; i < p->columns; i++) - { - for (k = 0; k < p->colors; k++) - { - int a = getcomponent(in, i * p->colors + k, p->bpc); - int b = p->encode ? a - left[k] : a + left[k]; - int c = b % (1 << p->bpc); - putcomponent(out, i * p->colors + k, p->bpc, c); - left[k] = p->encode ? a : c; - } - } -} - -static void -png(fz_predict *p, unsigned char *in, unsigned char *out, int predictor) -{ - int upleft[MAXC], left[MAXC], i, k; - - for (k = 0; k < p->bpp; k++) - { - left[k] = 0; - upleft[k] = 0; - } - - if (p->encode) - { - for (k = 0, i = 0; i < p->stride; k = (k + 1) % p->bpp, i ++) - { - switch (predictor) - { - case 0: out[i] = in[i]; break; - case 1: out[i] = in[i] - left[k]; break; - case 2: out[i] = in[i] - p->ref[i]; break; - case 3: out[i] = in[i] - (left[k] + p->ref[i]) / 2; break; - case 4: out[i] = in[i] - paeth(left[k], p->ref[i], upleft[k]); break; - } - left[k] = in[i]; - upleft[k] = p->ref[i]; - } - } - - else - { - for (k = 0, i = 0; i < p->stride; k = (k + 1) % p->bpp, i ++) - { - switch (predictor) - { - case 0: out[i] = in[i]; break; - case 1: out[i] = in[i] + left[k]; break; - case 2: out[i] = in[i] + p->ref[i]; break; - case 3: out[i] = in[i] + (left[k] + p->ref[i]) / 2; break; - case 4: out[i] = in[i] + paeth(left[k], p->ref[i], upleft[k]); break; - } - left[k] = out[i]; - upleft[k] = p->ref[i]; - } - } -} - -fz_error * -fz_processpredict(fz_filter *filter, fz_buffer *in, fz_buffer *out) -{ - fz_predict *dec = (fz_predict*)filter; - int ispng = dec->predictor >= 10; - int predictor; - - while (1) - { - if (in->rp + dec->stride + (!dec->encode && ispng) > in->wp) - { - if (in->eof) - return fz_iodone; - return fz_ioneedin; - } - - if (out->wp + dec->stride + (dec->encode && ispng) > out->ep) - return fz_ioneedout; - - if (dec->predictor == 1) - { - none(dec, in->rp, out->wp); - } - else if (dec->predictor == 2) - { - if (dec->bpc != 8) - memset(out->wp, 0, dec->stride); - tiff(dec, in->rp, out->wp); - } - else - { - if (dec->encode) - { - predictor = dec->predictor - 10; - if (predictor < 0 || predictor > 4) - predictor = 1; - *out->wp ++ = predictor; - } - else - { - predictor = *in->rp++; - } - png(dec, in->rp, out->wp, predictor); - } - - if (dec->ref) - memcpy(dec->ref, out->wp, dec->stride); - - in->rp += dec->stride; - out->wp += dec->stride; - } -} - -fz_error * -fz_newpredictd(fz_filter **fp, fz_obj *params) -{ - return fz_newpredict(fp, params, 0); -} - -fz_error * -fz_newpredicte(fz_filter **fp, fz_obj *params) -{ - return fz_newpredict(fp, params, 1); -} - diff --git a/stream/filt_rld.c b/stream/filt_rld.c deleted file mode 100644 index 9b0ed75f..00000000 --- a/stream/filt_rld.c +++ /dev/null @@ -1,73 +0,0 @@ -#include "fitz-base.h" -#include "fitz-stream.h" - -fz_error * -fz_newrld(fz_filter **fp, fz_obj *params) -{ - FZ_NEWFILTER(fz_filter, f, rld); - return fz_okay; -} - -void -fz_droprld(fz_filter *rld) -{ -} - -fz_error * -fz_processrld(fz_filter *filter, fz_buffer *in, fz_buffer *out) -{ - int run, i; - unsigned char c; - - while (1) - { - if (in->rp == in->wp) - { - if (in->eof) - { - return fz_iodone; - } - return fz_ioneedin; - } - - if (out->wp == out->ep) - return fz_ioneedout; - - run = *in->rp++; - - if (run == 128) - { - return fz_iodone; - } - - else if (run < 128) { - run = run + 1; - if (in->rp + run > in->wp) { - in->rp --; - return fz_ioneedin; - } - if (out->wp + run > out->ep) { - in->rp --; - return fz_ioneedout; - } - for (i = 0; i < run; i++) - *out->wp++ = *in->rp++; - } - - else if (run > 128) { - run = 257 - run; - if (in->rp + 1 > in->wp) { - in->rp --; - return fz_ioneedin; - } - if (out->wp + run > out->ep) { - in->rp --; - return fz_ioneedout; - } - c = *in->rp++; - for (i = 0; i < run; i++) - *out->wp++ = c; - } - } -} - diff --git a/stream/filt_rle.c b/stream/filt_rle.c deleted file mode 100644 index 65c2a7a4..00000000 --- a/stream/filt_rle.c +++ /dev/null @@ -1,238 +0,0 @@ -#include "fitz-base.h" -#include "fitz-stream.h" - -/* TODO: rewrite! - * make it non-optimal or something, - * just not this horrid mess... - */ - -#define noDEBUG - -typedef struct fz_rle_s fz_rle; - -struct fz_rle_s -{ - fz_filter super; - int reclen; - int curlen; - int state; - int run; - unsigned char buf[128]; -}; - -enum { - ZERO, - ONE, - DIFF, - SAME, - END -}; - -fz_error * -fz_newrle(fz_filter **fp, fz_obj *params) -{ - FZ_NEWFILTER(fz_rle, enc, rle); - - if (params) - enc->reclen = fz_toint(params); - else - enc->reclen = 0; - - enc->curlen = 0; - enc->state = ZERO; - enc->run = 0; - - return fz_okay; -} - -void -fz_droprle(fz_filter *enc) -{ -} - -static fz_error * -putone(fz_rle *enc, fz_buffer *in, fz_buffer *out) -{ - if (out->wp + 2 >= out->ep) - return fz_ioneedout; - -#ifdef DEBUG -fprintf(stderr, "one '%c'\n", enc->buf[0]); -#endif - - *out->wp++ = 0; - *out->wp++ = enc->buf[0]; - - return fz_okay; -} - -static fz_error * -putsame(fz_rle *enc, fz_buffer *in, fz_buffer *out) -{ - if (out->wp + enc->run >= out->ep) - return fz_ioneedout; - -#ifdef DEBUG -fprintf(stderr, "same %d x '%c'\n", enc->run, enc->buf[0]); -#endif - - *out->wp++ = 257 - enc->run; - *out->wp++ = enc->buf[0]; - return fz_okay; -} - -static fz_error * -putdiff(fz_rle *enc, fz_buffer *in, fz_buffer *out) -{ - int i; - if (out->wp + enc->run >= out->ep) - return fz_ioneedout; - -#ifdef DEBUG -fprintf(stderr, "diff %d\n", enc->run); -#endif - - *out->wp++ = enc->run - 1; - for (i = 0; i < enc->run; i++) - *out->wp++ = enc->buf[i]; - return fz_okay; -} - -static fz_error * -puteod(fz_rle *enc, fz_buffer *in, fz_buffer *out) -{ - if (out->wp + 1 >= out->ep) - return fz_ioneedout; - -#ifdef DEBUG -fprintf(stderr, "eod\n"); -#endif - - *out->wp++ = 128; - return fz_okay; -} - -static fz_error * -savebuf(fz_rle *enc, fz_buffer *in, fz_buffer *out) -{ - switch (enc->state) - { - case ZERO: return fz_okay; - case ONE: return putone(enc, in, out); - case SAME: return putsame(enc, in, out); - case DIFF: return putdiff(enc, in, out); - case END: return puteod(enc, in, out); - default: assert(!"invalid state in rle"); return fz_okay; - } -} - -fz_error * -fz_processrle(fz_filter *filter, fz_buffer *in, fz_buffer *out) -{ - fz_rle *enc = (fz_rle*)filter; - fz_error *error; - unsigned char c; - - while (1) - { - - if (enc->reclen && enc->curlen == enc->reclen) { - error = savebuf(enc, in, out); - if (error) return error; -#ifdef DEBUG -fprintf(stderr, "--record--\n"); -#endif - enc->state = ZERO; - enc->curlen = 0; - } - - if (in->rp == in->wp) { - if (in->eof) { - if (enc->state != END) { - error = savebuf(enc, in, out); - if (error) return error; - } - enc->state = END; - } - else - return fz_ioneedin; - } - - c = *in->rp; - - switch (enc->state) - { - case ZERO: - enc->state = ONE; - enc->run = 1; - enc->buf[0] = c; - break; - - case ONE: - enc->state = DIFF; - enc->run = 2; - enc->buf[1] = c; - break; - - case DIFF: - /* out of space */ - if (enc->run == 128) { - error = putdiff(enc, in, out); - if (error) return error; - - enc->state = ONE; - enc->run = 1; - enc->buf[0] = c; - } - - /* run of three that are the same */ - else if ((enc->run > 1) && - (c == enc->buf[enc->run - 1]) && - (c == enc->buf[enc->run - 2])) - { - if (enc->run >= 3) { - enc->run -= 2; /* skip prev two for diff run */ - error = putdiff(enc, in, out); - if (error) return error; - } - - enc->state = SAME; - enc->run = 3; - enc->buf[0] = c; - } - - /* keep on collecting */ - else { - enc->buf[enc->run++] = c; - } - break; - - case SAME: - if (enc->run == 128 || c != enc->buf[0]) { - error = putsame(enc, in, out); - if (error) return error; - - enc->state = ONE; - enc->run = 1; - enc->buf[0] = c; - } - else { - enc->run ++; - } - break; - - case END: - error = puteod(enc, in, out); - if (error) - return error; - - return fz_iodone; - } - - in->rp ++; - - enc->curlen ++; - - } -} - diff --git a/stream/obj_array.c b/stream/obj_array.c deleted file mode 100644 index 3953470a..00000000 --- a/stream/obj_array.c +++ /dev/null @@ -1,230 +0,0 @@ -#include "fitz-base.h" -#include "fitz-stream.h" - -void fz_droparray(fz_obj *obj); - -fz_error * -fz_newarray(fz_obj **op, int initialcap) -{ - fz_obj *obj; - int i; - - obj = *op = fz_malloc(sizeof (fz_obj)); - if (!obj) - return fz_throw("outofmem: array struct"); - - obj->refs = 1; - obj->kind = FZ_ARRAY; - - obj->u.a.len = 0; - obj->u.a.cap = initialcap > 0 ? initialcap : 6; - - obj->u.a.items = fz_malloc(sizeof (fz_obj*) * obj->u.a.cap); - if (!obj->u.a.items) - { - fz_free(obj); - return fz_throw("outofmem: array item buffer"); - } - - for (i = 0; i < obj->u.a.cap; i++) - obj->u.a.items[i] = nil; - - return fz_okay; -} - -fz_error * -fz_copyarray(fz_obj **op, fz_obj *obj) -{ - fz_error *error; - fz_obj *new; - int i; - - if (!fz_isarray(obj)) - return fz_throw("assert: not an array (%s)", fz_objkindstr(obj)); - - error = fz_newarray(&new, fz_arraylen(obj)); - if (error) - return fz_rethrow(error, "cannot create new array"); - - for (i = 0; i < fz_arraylen(obj); i++) - { - error = fz_arraypush(new, fz_arrayget(obj, i)); - if (error) - { - fz_droparray(new); - return fz_rethrow(error, "cannot add item to array"); - } - } - - *op = new; - - return fz_okay; -} - -fz_error * -fz_deepcopyarray(fz_obj **op, fz_obj *obj) -{ - fz_error *error; - fz_obj *new; - fz_obj *val; - int i; - - if (!fz_isarray(obj)) - return fz_throw("assert: not an array (%s)", fz_objkindstr(obj)); - - error = fz_newarray(&new, fz_arraylen(obj)); - if (error) - return fz_rethrow(error, "cannot create new array"); - - for (i = 0; i < fz_arraylen(obj); i++) - { - val = fz_arrayget(obj, i); - - if (fz_isarray(val)) - { - error = fz_deepcopyarray(&val, val); - if (error) - { - fz_droparray(new); - return fz_rethrow(error, "cannot deep copy item"); - } - - error = fz_arraypush(new, val); - if (error) - { - fz_dropobj(val); - fz_droparray(new); - return fz_rethrow(error, "cannot add copied item to array"); - } - - fz_dropobj(val); - } - - else if (fz_isdict(val)) - { - error = fz_deepcopydict(&val, val); - if (error) - { - fz_droparray(new); - return fz_rethrow(error, "cannot deep copy item"); - } - - error = fz_arraypush(new, val); - if (error) - { - fz_dropobj(val); - fz_droparray(new); - return fz_rethrow(error, "cannot add copied item to array"); - } - fz_dropobj(val); - } - - else - { - error = fz_arraypush(new, val); - if (error) - { - fz_droparray(new); - return fz_rethrow(error, "cannot add copied item to array"); - } - } - } - - *op = new; - - return fz_okay; -} - -int -fz_arraylen(fz_obj *obj) -{ - if (!fz_isarray(obj)) - return 0; - return obj->u.a.len; -} - -fz_obj * -fz_arrayget(fz_obj *obj, int i) -{ - if (!fz_isarray(obj)) - return nil; - - if (i < 0 || i >= obj->u.a.len) - return nil; - - return obj->u.a.items[i]; -} - -fz_error * -fz_arrayput(fz_obj *obj, int i, fz_obj *item) -{ - if (!fz_isarray(obj)) - return fz_throw("assert: not an array (%s)", fz_objkindstr(obj)); - if (i < 0) - return fz_throw("assert: index %d < 0", i); - if (i >= obj->u.a.len) - return fz_throw("assert: index %d > length %d", i, obj->u.a.len); - - if (obj->u.a.items[i]) - fz_dropobj(obj->u.a.items[i]); - obj->u.a.items[i] = fz_keepobj(item); - - return fz_okay; -} - -static fz_error * -growarray(fz_obj *obj) -{ - fz_obj **newitems; - int newcap; - int i; - - newcap = obj->u.a.cap * 2; - newitems = fz_realloc(obj->u.a.items, sizeof (fz_obj*) * newcap); - if (!newitems) - return fz_throw("outofmem: resize item buffer"); - - obj->u.a.items = newitems; - for (i = obj->u.a.cap ; i < newcap; i++) - obj->u.a.items[i] = nil; - obj->u.a.cap = newcap; - - return fz_okay; -} - -fz_error * -fz_arraypush(fz_obj *obj, fz_obj *item) -{ - fz_error *error; - - if (!fz_isarray(obj)) - return fz_throw("assert: not an array (%s)", fz_objkindstr(obj)); - - if (obj->u.a.len + 1 > obj->u.a.cap) - { - error = growarray(obj); - if (error) - return fz_rethrow(error, "cannot grow item buffer"); - } - - obj->u.a.items[obj->u.a.len] = fz_keepobj(item); - obj->u.a.len++; - - return fz_okay; -} - -void -fz_droparray(fz_obj *obj) -{ - int i; - - assert(obj->kind == FZ_ARRAY); - - for (i = 0; i < obj->u.a.len; i++) - if (obj->u.a.items[i]) - fz_dropobj(obj->u.a.items[i]); - - fz_free(obj->u.a.items); - fz_free(obj); -} - diff --git a/stream/obj_dict.c b/stream/obj_dict.c deleted file mode 100644 index 236c8a1a..00000000 --- a/stream/obj_dict.c +++ /dev/null @@ -1,399 +0,0 @@ -#include "fitz-base.h" -#include "fitz-stream.h" - -/* keep either names or strings in the dict. don't mix & match. */ - -static int keyvalcmp(const void *ap, const void *bp) -{ - const fz_keyval *a = ap; - const fz_keyval *b = bp; - if (fz_isname(a->k)) - return strcmp(fz_toname(a->k), fz_toname(b->k)); - if (fz_isstring(a->k)) - return strcmp(fz_tostrbuf(a->k), fz_tostrbuf(b->k)); - return -1; -} - -static inline int keystrcmp(fz_obj *key, char *s) -{ - if (fz_isname(key)) - return strcmp(fz_toname(key), s); - if (fz_isstring(key)) - return strcmp(fz_tostrbuf(key), s); - return -1; -} - -fz_error * -fz_newdict(fz_obj **op, int initialcap) -{ - fz_obj *obj; - int i; - - obj = *op = fz_malloc(sizeof (fz_obj)); - if (!obj) - return fz_throw("outofmem: dict struct"); - - obj->refs = 1; - obj->kind = FZ_DICT; - - obj->u.d.sorted = 1; - obj->u.d.len = 0; - obj->u.d.cap = initialcap > 0 ? initialcap : 10; - - obj->u.d.items = fz_malloc(sizeof(fz_keyval) * obj->u.d.cap); - if (!obj->u.d.items) - { - fz_free(obj); - return fz_throw("outofmem: dict item buffer"); - } - - for (i = 0; i < obj->u.d.cap; i++) - { - obj->u.d.items[i].k = nil; - obj->u.d.items[i].v = nil; - } - - return fz_okay; -} - -fz_error * -fz_copydict(fz_obj **op, fz_obj *obj) -{ - fz_error *error; - fz_obj *new; - int i; - - if (!fz_isdict(obj)) - return fz_throw("assert: not a dict (%s)", fz_objkindstr(obj)); - - error = fz_newdict(&new, obj->u.d.cap); - if (error) - return fz_rethrow(error, "cannot create new dict"); - - for (i = 0; i < fz_dictlen(obj); i++) - { - error = fz_dictput(new, fz_dictgetkey(obj, i), fz_dictgetval(obj, i)); - if (error) - { - fz_dropobj(new); - return fz_rethrow(error, "cannot copy dict entry"); - } - } - - *op = new; - return fz_okay; -} - -fz_error * -fz_deepcopydict(fz_obj **op, fz_obj *obj) -{ - fz_error *error; - fz_obj *new; - fz_obj *val; - int i; - - if (!fz_isdict(obj)) - return fz_throw("assert: not a dict (%s)", fz_objkindstr(obj)); - - error = fz_newdict(&new, obj->u.d.cap); - if (error) - return fz_rethrow(error, "cannot create new dict"); - - for (i = 0; i < fz_dictlen(obj); i++) - { - val = fz_dictgetval(obj, i); - - if (fz_isarray(val)) - { - error = fz_deepcopyarray(&val, val); - if (error) - { - fz_dropobj(new); - return fz_rethrow(error, "cannot deep copy item"); - } - error = fz_dictput(new, fz_dictgetkey(obj, i), val); - if (error) - { - fz_dropobj(val); - fz_dropobj(new); - return fz_rethrow(error, "cannot add copied dict entry"); - } - fz_dropobj(val); - } - - else if (fz_isdict(val)) - { - error = fz_deepcopydict(&val, val); - if (error) - { - fz_dropobj(new); - return fz_rethrow(error, "cannot deep copy item"); - } - error = fz_dictput(new, fz_dictgetkey(obj, i), val); - if (error) - { - fz_dropobj(val); - fz_dropobj(new); - return fz_rethrow(error, "cannot add copied dict entry"); - } - fz_dropobj(val); - } - - else - { - error = fz_dictput(new, fz_dictgetkey(obj, i), val); - if (error) - { - fz_dropobj(new); - return fz_rethrow(error, "cannot copy dict entry"); - } - } - } - - *op = new; - return fz_okay; -} - -static fz_error * -growdict(fz_obj *obj) -{ - fz_keyval *newitems; - int newcap; - int i; - - newcap = obj->u.d.cap * 2; - - newitems = fz_realloc(obj->u.d.items, sizeof(fz_keyval) * newcap); - if (!newitems) - return fz_throw("outofmem: resize item buffer"); - - obj->u.d.items = newitems; - for (i = obj->u.d.cap; i < newcap; i++) - { - obj->u.d.items[i].k = nil; - obj->u.d.items[i].v = nil; - } - obj->u.d.cap = newcap; - - return fz_okay; -} - -int -fz_dictlen(fz_obj *obj) -{ - if (!fz_isdict(obj)) - return 0; - return obj->u.d.len; -} - -fz_obj * -fz_dictgetkey(fz_obj *obj, int i) -{ - if (!fz_isdict(obj)) - return nil; - - if (i < 0 || i >= obj->u.d.len) - return nil; - - return obj->u.d.items[i].k; -} - -fz_obj * -fz_dictgetval(fz_obj *obj, int i) -{ - if (!fz_isdict(obj)) - return nil; - - if (i < 0 || i >= obj->u.d.len) - return nil; - - return obj->u.d.items[i].v; -} - -static inline int dictfinds(fz_obj *obj, char *key) -{ - if (obj->u.d.sorted) - { - int l = 0; - int r = obj->u.d.len - 1; - while (l <= r) - { - int m = (l + r) >> 1; - int c = -keystrcmp(obj->u.d.items[m].k, key); - if (c < 0) - r = m - 1; - else if (c > 0) - l = m + 1; - else - return m; - } - } - - else - { - int i; - for (i = 0; i < obj->u.d.len; i++) - if (keystrcmp(obj->u.d.items[i].k, key) == 0) - return i; - } - - return -1; -} - -fz_obj * -fz_dictgets(fz_obj *obj, char *key) -{ - int i; - - if (!fz_isdict(obj)) - return nil; - - i = dictfinds(obj, key); - if (i >= 0) - return obj->u.d.items[i].v; - - return nil; -} - -fz_obj * -fz_dictget(fz_obj *obj, fz_obj *key) -{ - if (fz_isname(key)) - return fz_dictgets(obj, fz_toname(key)); - if (fz_isstring(key)) - return fz_dictgets(obj, fz_tostrbuf(key)); - return nil; -} - -fz_obj * -fz_dictgetsa(fz_obj *obj, char *key, char *abbrev) -{ - fz_obj *v; - v = fz_dictgets(obj, key); - if (v) - return v; - return fz_dictgets(obj, abbrev); -} - -fz_error * -fz_dictput(fz_obj *obj, fz_obj *key, fz_obj *val) -{ - fz_error *error; - char *s; - int i; - - if (!fz_isdict(obj)) - return fz_throw("assert: not a dict (%s)", fz_objkindstr(obj)); - - if (fz_isname(key)) - s = fz_toname(key); - else if (fz_isstring(key)) - s = fz_tostrbuf(key); - else - return fz_throw("assert: key is not string or name (%s)", fz_objkindstr(obj)); - - i = dictfinds(obj, s); - if (i >= 0) - { - fz_dropobj(obj->u.d.items[i].v); - obj->u.d.items[i].v = fz_keepobj(val); - return fz_okay; - } - - if (obj->u.d.len + 1 > obj->u.d.cap) - { - error = growdict(obj); - if (error) - return fz_rethrow(error, "cannot grow dict item buffer"); - } - - /* borked! */ - if (obj->u.d.len) - if (keystrcmp(obj->u.d.items[obj->u.d.len - 1].k, s) > 0) - obj->u.d.sorted = 0; - - obj->u.d.items[obj->u.d.len].k = fz_keepobj(key); - obj->u.d.items[obj->u.d.len].v = fz_keepobj(val); - obj->u.d.len ++; - - return fz_okay; -} - -fz_error * -fz_dictputs(fz_obj *obj, char *key, fz_obj *val) -{ - fz_error *error; - fz_obj *keyobj; - error = fz_newname(&keyobj, key); - if (error) - return fz_rethrow(error, "cannot create dict key"); - error = fz_dictput(obj, keyobj, val); - fz_dropobj(keyobj); - if (error) - return fz_rethrow(error, "cannot insert dict entry"); - return fz_okay; -} - -fz_error * -fz_dictdels(fz_obj *obj, char *key) -{ - int i; - - if (!fz_isdict(obj)) - return fz_throw("assert: not a dict (%s)", fz_objkindstr(obj)); - - i = dictfinds(obj, key); - if (i >= 0) - { - fz_dropobj(obj->u.d.items[i].k); - fz_dropobj(obj->u.d.items[i].v); - obj->u.d.sorted = 0; - obj->u.d.items[i] = obj->u.d.items[obj->u.d.len-1]; - obj->u.d.len --; - } - - return fz_okay; -} - -fz_error * -fz_dictdel(fz_obj *obj, fz_obj *key) -{ - if (fz_isname(key)) - return fz_dictdels(obj, fz_toname(key)); - else if (fz_isstring(key)) - return fz_dictdels(obj, fz_tostrbuf(key)); - else - return fz_throw("assert: key is not string or name (%s)", fz_objkindstr(obj)); -} - -void -fz_dropdict(fz_obj *obj) -{ - int i; - - if (!fz_isdict(obj)) - return; - - for (i = 0; i < obj->u.d.len; i++) { - if (obj->u.d.items[i].k) - fz_dropobj(obj->u.d.items[i].k); - if (obj->u.d.items[i].v) - fz_dropobj(obj->u.d.items[i].v); - } - - fz_free(obj->u.d.items); - fz_free(obj); -} - -void -fz_sortdict(fz_obj *obj) -{ - if (!fz_isdict(obj)) - return; - if (!obj->u.d.sorted) - { - qsort(obj->u.d.items, obj->u.d.len, sizeof(fz_keyval), keyvalcmp); - obj->u.d.sorted = 1; - } -} - diff --git a/stream/obj_parse.c b/stream/obj_parse.c deleted file mode 100644 index 48d59538..00000000 --- a/stream/obj_parse.c +++ /dev/null @@ -1,492 +0,0 @@ -#include "fitz-base.h" -#include "fitz-stream.h" - -struct vap { va_list ap; }; - -static inline int iswhite(int ch) -{ - return - ch == '\000' || - ch == '\011' || - ch == '\012' || - ch == '\014' || - ch == '\015' || - ch == '\040'; -} - -static inline int isdelim(int ch) -{ - return - ch == '(' || ch == ')' || - ch == '<' || ch == '>' || - ch == '[' || ch == ']' || - ch == '{' || ch == '}' || - ch == '/' || - ch == '%'; -} - -static inline int isregular(int ch) -{ - return !isdelim(ch) && !iswhite(ch) && ch != EOF; -} - -static fz_error *parseobj(fz_obj **obj, char **sp, struct vap *v); - -static inline int fromhex(char ch) -{ - if (ch >= '0' && ch <= '9') - return ch - '0'; - else if (ch >= 'A' && ch <= 'F') - return ch - 'A' + 0xA; - else if (ch >= 'a' && ch <= 'f') - return ch - 'a' + 0xA; - return 0; -} - -static inline void skipwhite(char **sp) -{ - char *s = *sp; - while (iswhite(*s)) - s ++; - *sp = s; -} - -static void parsekeyword(char **sp, char *b, char *eb) -{ - char *s = *sp; - while (b < eb && isregular(*s)) - *b++ = *s++; - *b++ = 0; - *sp = s; -} - -static fz_error *parsename(fz_obj **obj, char **sp) -{ - fz_error *error; - char buf[64]; - char *s = *sp; - char *p = buf; - - s ++; /* skip '/' */ - while (p < buf + sizeof buf - 1 && isregular(*s)) - *p++ = *s++; - *p++ = 0; - *sp = s; - - error = fz_newname(obj, buf); - if (error) - return fz_rethrow(error, "cannot create name"); - return fz_okay; -} - -static fz_error *parsenumber(fz_obj **obj, char **sp) -{ - fz_error *error; - char buf[32]; - char *s = *sp; - char *p = buf; - - while (p < buf + sizeof buf - 1) - { - if (s[0] == '-' || s[0] == '.' || (s[0] >= '0' && s[0] <= '9')) - *p++ = *s++; - else - break; - } - *p++ = 0; - *sp = s; - - if (strchr(buf, '.')) - error = fz_newreal(obj, atof(buf)); - else - error = fz_newint(obj, atoi(buf)); - - if (error) - return fz_rethrow(error, "cannot parse number"); - return fz_okay; -} - -static fz_error *parsedict(fz_obj **obj, char **sp, struct vap *v) -{ - fz_error *error = fz_okay; - fz_obj *dict = nil; - fz_obj *key = nil; - fz_obj *val = nil; - char *s = *sp; - - error = fz_newdict(&dict, 8); - if (error) - return fz_rethrow(error, "cannot create dict"); - - s += 2; /* skip "<<" */ - - while (*s) - { - skipwhite(&s); - - /* end-of-dict marker >> */ - if (*s == '>') - { - s ++; - if (*s == '>') - { - s ++; - break; - } - error = fz_throw("malformed >> marker"); - goto cleanup; - } - - /* non-name as key, bail */ - if (*s != '/') - { - error = fz_throw("key is not a name"); - goto cleanup; - } - - error = parsename(&key, &s); - if (error) - { - error = fz_rethrow(error, "cannot parse key"); - goto cleanup; - } - - skipwhite(&s); - - error = parseobj(&val, &s, v); - if (error) - { - error = fz_rethrow(error, "cannot parse value"); - goto cleanup; - } - - error = fz_dictput(dict, key, val); - if (error) - { - error = fz_rethrow(error, "cannot insert dict entry"); - goto cleanup; - } - - fz_dropobj(val); val = nil; - fz_dropobj(key); key = nil; - } - - *obj = dict; - *sp = s; - return fz_okay; - -cleanup: - if (val) fz_dropobj(val); - if (key) fz_dropobj(key); - if (dict) fz_dropobj(dict); - *obj = nil; - *sp = s; - return error; /* already rethrown */ -} - -static fz_error *parsearray(fz_obj **obj, char **sp, struct vap *v) -{ - fz_error *error; - fz_obj *a; - fz_obj *o; - char *s = *sp; - - error = fz_newarray(&a, 8); - if (error) - return fz_rethrow(error, "cannot create array"); - - s ++; /* skip '[' */ - - while (*s) - { - skipwhite(&s); - - if (*s == ']') - { - s ++; - break; - } - - error = parseobj(&o, &s, v); - if (error) - { - fz_dropobj(a); - return fz_rethrow(error, "cannot parse item"); - } - - error = fz_arraypush(a, o); - if (error) - { - fz_dropobj(o); - fz_dropobj(a); - return fz_rethrow(error, "cannot add item to array"); - } - - fz_dropobj(o); - } - - *obj = a; - *sp = s; - return fz_okay; -} - -static fz_error *parsestring(fz_obj **obj, char **sp) -{ - fz_error *error; - char buf[512]; - char *s = *sp; - char *p = buf; - int balance = 1; - int oct; - - s ++; /* skip '(' */ - - while (*s && p < buf + sizeof buf) - { - if (*s == '(') - { - balance ++; - *p++ = *s++; - } - else if (*s == ')') - { - balance --; - *p++ = *s++; - } - else if (*s == '\\') - { - s ++; - if (*s >= '0' && *s <= '9') - { - oct = *s - '0'; - s ++; - if (*s >= '0' && *s <= '9') - { - oct = oct * 8 + (*s - '0'); - s ++; - if (*s >= '0' && *s <= '9') - { - oct = oct * 8 + (*s - '0'); - s ++; - } - } - *p++ = oct; - } - else switch (*s) - { - case 'n': *p++ = '\n'; s++; break; - case 'r': *p++ = '\r'; s++; break; - case 't': *p++ = '\t'; s++; break; - case 'b': *p++ = '\b'; s++; break; - case 'f': *p++ = '\f'; s++; break; - default: *p++ = *s++; break; - } - } - else - *p++ = *s++; - - if (balance == 0) - break; - } - - *sp = s; - - error = fz_newstring(obj, buf, p - buf - 1); - if (error) - return fz_rethrow(error, "cannot create string"); - return fz_okay; -} - -static fz_error *parsehexstring(fz_obj **obj, char **sp) -{ - fz_error *error; - char buf[512]; - char *s = *sp; - char *p = buf; - int a, b; - - s ++; /* skip '<' */ - - while (*s && p < buf + sizeof buf) - { - skipwhite(&s); - if (*s == '>') { - s ++; - break; - } - a = *s++; - - if (*s == '\0') - break; - - skipwhite(&s); - if (*s == '>') { - s ++; - break; - } - b = *s++; - - *p++ = fromhex(a) * 16 + fromhex(b); - } - - *sp = s; - error = fz_newstring(obj, buf, p - buf); - if (error) - return fz_rethrow(error, "cannot create string"); - return fz_okay; -} - -static fz_error *parseobj(fz_obj **obj, char **sp, struct vap *v) -{ - fz_error *error; - char buf[32]; - int oid, gid, len; - char *tmp; - char *s = *sp; - - if (*s == '\0') - return fz_throw("end of data"); - - skipwhite(&s); - - error = fz_okay; - - if (v != nil && *s == '%') - { - s ++; - - switch (*s) - { - case 'p': error = fz_newpointer(obj, va_arg(v->ap, void*)); break; - case 'o': *obj = fz_keepobj(va_arg(v->ap, fz_obj*)); break; - case 'b': error = fz_newbool(obj, va_arg(v->ap, int)); break; - case 'i': error = fz_newint(obj, va_arg(v->ap, int)); break; - case 'f': error = fz_newreal(obj, (float)va_arg(v->ap, double)); break; - case 'n': error = fz_newname(obj, va_arg(v->ap, char*)); break; - case 'r': - oid = va_arg(v->ap, int); - gid = va_arg(v->ap, int); - error = fz_newindirect(obj, oid, gid); - break; - case 's': - tmp = va_arg(v->ap, char*); - error = fz_newstring(obj, tmp, strlen(tmp)); - break; - case '#': - tmp = va_arg(v->ap, char*); - len = va_arg(v->ap, int); - error = fz_newstring(obj, tmp, len); - break; - default: - error = fz_throw("unknown format specifier in packobj: '%c'", *s); - break; - } - - if (error) - error = fz_rethrow(error, "cannot create object for %% format"); - - s ++; - } - - else if (*s == '/') - { - error = parsename(obj, &s); - if (error) - error = fz_rethrow(error, "cannot parse name"); - } - - else if (*s == '(') - { - error = parsestring(obj, &s); - if (error) - error = fz_rethrow(error, "cannot parse string"); - } - - else if (*s == '<') - { - if (s[1] == '<') - { - error = parsedict(obj, &s, v); - if (error) - error = fz_rethrow(error, "cannot parse dict"); - } - else - { - error = parsehexstring(obj, &s); - if (error) - error = fz_rethrow(error, "cannot parse hex string"); - } - } - - else if (*s == '[') - { - error = parsearray(obj, &s, v); - if (error) - error = fz_rethrow(error, "cannot parse array"); - } - - else if (*s == '-' || *s == '.' || (*s >= '0' && *s <= '9')) - { - error = parsenumber(obj, &s); - if (error) - error = fz_rethrow(error, "cannot parse number"); - } - - else if (isregular(*s)) - { - parsekeyword(&s, buf, buf + sizeof buf); - - if (strcmp("true", buf) == 0) - { - error = fz_newbool(obj, 1); - if (error) - error = fz_rethrow(error, "cannot create bool (true)"); - } - else if (strcmp("false", buf) == 0) - { - error = fz_newbool(obj, 0); - if (error) - error = fz_rethrow(error, "cannot create bool (false)"); - } - else if (strcmp("null", buf) == 0) - { - error = fz_newnull(obj); - if (error) - error = fz_rethrow(error, "cannot create null object"); - } - else - error = fz_throw("undefined keyword %s", buf); - } - - else - error = fz_throw("syntax error: unknown byte 0x%d", *s); - - *sp = s; - return error; /* already rethrown */ -} - -fz_error * -fz_packobj(fz_obj **op, char *fmt, ...) -{ - fz_error *error; - struct vap v; - va_list ap; - - va_start(ap, fmt); - va_copy(v.ap, ap); - - error = parseobj(op, &fmt, &v); - - va_end(ap); - - if (error) - return fz_rethrow(error, "cannot parse object"); - return fz_okay; -} - -fz_error * -fz_parseobj(fz_obj **op, char *str) -{ - return parseobj(op, &str, nil); -} - diff --git a/stream/obj_print.c b/stream/obj_print.c deleted file mode 100644 index 4e321127..00000000 --- a/stream/obj_print.c +++ /dev/null @@ -1,339 +0,0 @@ -#include "fitz-base.h" -#include "fitz-stream.h" - -struct fmt -{ - char *buf; - int cap; - int len; - int indent; - int tight; - int col; - int sep; - int last; -}; - -static void fmtobj(struct fmt *fmt, fz_obj *obj); - -static inline int iswhite(int ch) -{ - return - ch == '\000' || - ch == '\011' || - ch == '\012' || - ch == '\014' || - ch == '\015' || - ch == '\040'; -} - -static inline int isdelim(int ch) -{ - return ch == '(' || ch == ')' || - ch == '<' || ch == '>' || - ch == '[' || ch == ']' || - ch == '{' || ch == '}' || - ch == '/' || - ch == '%'; -} - -static inline void fmtputc(struct fmt *fmt, int c) -{ - if (fmt->sep && !isdelim(fmt->last) && !isdelim(c)) { - fmt->sep = 0; - fmtputc(fmt, ' '); - } - fmt->sep = 0; - - if (fmt->buf && fmt->len < fmt->cap) - fmt->buf[fmt->len] = c; - - if (c == '\n') - fmt->col = 0; - else - fmt->col ++; - - fmt->len ++; - - fmt->last = c; -} - -static void fmtindent(struct fmt *fmt) -{ - int i = fmt->indent; - while (i--) { - fmtputc(fmt, ' '); - fmtputc(fmt, ' '); - } -} - -static inline void fmtputs(struct fmt *fmt, char *s) -{ - while (*s) - fmtputc(fmt, *s++); -} - -static inline void fmtsep(struct fmt *fmt) -{ - fmt->sep = 1; -} - -static void fmtstr(struct fmt *fmt, fz_obj *obj) -{ - int i; - int c; - - fmtputc(fmt, '('); - for (i = 0; i < obj->u.s.len; i++) - { - c = (unsigned char) obj->u.s.buf[i]; - if (c == '\n') - fmtputs(fmt, "\\n"); - else if (c == '\r') - fmtputs(fmt, "\\r"); - else if (c == '\t') - fmtputs(fmt, "\\t"); - else if (c == '\b') - fmtputs(fmt, "\\b"); - else if (c == '\f') - fmtputs(fmt, "\\f"); - else if (c == '(') - fmtputs(fmt, "\\("); - else if (c == ')') - fmtputs(fmt, "\\)"); - else if (c < 32 || c > 126) { - char buf[16]; - fmtputc(fmt, '\\'); - sprintf(buf, "%o", c); - fmtputs(fmt, buf); - } - else - fmtputc(fmt, c); - } - fmtputc(fmt, ')'); -} - -static void fmthex(struct fmt *fmt, fz_obj *obj) -{ - int i; - int b; - int c; - - fmtputc(fmt, '<'); - for (i = 0; i < obj->u.s.len; i++) { - b = (unsigned char) obj->u.s.buf[i]; - c = (b >> 4) & 0x0f; - fmtputc(fmt, c < 0xA ? c + '0' : c + 'A' - 0xA); - c = (b) & 0x0f; - fmtputc(fmt, c < 0xA ? c + '0' : c + 'A' - 0xA); - } - fmtputc(fmt, '>'); -} - -static void fmtname(struct fmt *fmt, fz_obj *obj) -{ - char *s = fz_toname(obj); - int i, c; - - fmtputc(fmt, '/'); - - for (i = 0; s[i]; i++) - { - if (isdelim(s[i]) || iswhite(s[i])) - { - fmtputc(fmt, '#'); - c = (s[i] >> 4) & 0xf; - fmtputc(fmt, c < 0xA ? c + '0' : c + 'A' - 0xA); - c = s[i] & 0xf; - fmtputc(fmt, c < 0xA ? c + '0' : c + 'A' - 0xA); - } - else - { - fmtputc(fmt, s[i]); - } - } -} - -static void fmtarray(struct fmt *fmt, fz_obj *obj) -{ - int i; - - if (fmt->tight) { - fmtputc(fmt, '['); - for (i = 0; i < fz_arraylen(obj); i++) { - fmtobj(fmt, fz_arrayget(obj, i)); - fmtsep(fmt); - } - fmtputc(fmt, ']'); - } - else { - fmtputs(fmt, "[ "); - for (i = 0; i < fz_arraylen(obj); i++) { - if (fmt->col > 60) { - fmtputc(fmt, '\n'); - fmtindent(fmt); - } - fmtobj(fmt, fz_arrayget(obj, i)); - fmtputc(fmt, ' '); - } - fmtputc(fmt, ']'); - fmtsep(fmt); - } -} - -static void fmtdict(struct fmt *fmt, fz_obj *obj) -{ - int i; - fz_obj *key, *val; - - if (fmt->tight) { - fmtputs(fmt, "<<"); - for (i = 0; i < fz_dictlen(obj); i++) { - fmtobj(fmt, fz_dictgetkey(obj, i)); - fmtsep(fmt); - fmtobj(fmt, fz_dictgetval(obj, i)); - fmtsep(fmt); - } - fmtputs(fmt, ">>"); - } - else { - fmtputs(fmt, "<<\n"); - fmt->indent ++; - for (i = 0; i < fz_dictlen(obj); i++) { - key = fz_dictgetkey(obj, i); - val = fz_dictgetval(obj, i); - fmtindent(fmt); - fmtobj(fmt, key); - fmtputc(fmt, ' '); - if (fz_isarray(val)) - fmt->indent ++; - fmtobj(fmt, val); - fmtputc(fmt, '\n'); - if (fz_isarray(val)) - fmt->indent --; - } - fmt->indent --; - fmtindent(fmt); - fmtputs(fmt, ">>"); - } -} - -static void fmtobj(struct fmt *fmt, fz_obj *obj) -{ - char buf[256]; - - if (!obj) { - fmtputs(fmt, ""); - return; - } - - switch (obj->kind) - { - case FZ_NULL: - fmtputs(fmt, "null"); - break; - case FZ_BOOL: - fmtputs(fmt, fz_tobool(obj) ? "true" : "false"); - break; - case FZ_INT: - sprintf(buf, "%d", fz_toint(obj)); - fmtputs(fmt, buf); - break; - case FZ_REAL: - sprintf(buf, "%g", fz_toreal(obj)); - if (strchr(buf, 'e')) /* bad news! */ - sprintf(buf, fabs(fz_toreal(obj)) > 1 ? "%1.1f" : "%1.8f", fz_toreal(obj)); - fmtputs(fmt, buf); - break; - case FZ_STRING: - { - int added = 0; - int i, c; - for (i = 0; i < obj->u.s.len; i++) { - c = (unsigned char)obj->u.s.buf[i]; - if (strchr("()\\\n\r\t\b\f", c) != 0) - added ++; - else if (c < 8) - added ++; - else if (c < 32) - added += 2; - else if (c >= 127) - added += 3; - } - if (added < obj->u.s.len) - fmtstr(fmt, obj); - else - fmthex(fmt, obj); - } - break; - case FZ_NAME: - fmtname(fmt, obj); - break; - case FZ_ARRAY: - fmtarray(fmt, obj); - break; - case FZ_DICT: - fmtdict(fmt, obj); - break; - case FZ_INDIRECT: - sprintf(buf, "%d %d R", obj->u.r.oid, obj->u.r.gid); - fmtputs(fmt, buf); - break; - case FZ_POINTER: - sprintf(buf, "$%p", obj->u.p); - fmtputs(fmt, buf); - break; - default: - sprintf(buf, "", obj->kind); - fmtputs(fmt, buf); - break; - } -} - -int -fz_sprintobj(char *s, int n, fz_obj *obj, int tight) -{ - struct fmt fmt; - - fmt.indent = 0; - fmt.col = 0; - fmt.sep = 0; - fmt.last = 0; - - fmt.tight = tight; - fmt.buf = s; - fmt.cap = n; - fmt.len = 0; - fmtobj(&fmt, obj); - - if (fmt.buf && fmt.len < fmt.cap) - fmt.buf[fmt.len] = '\0'; - - return fmt.len; -} - -void -fz_debugobj(fz_obj *obj) -{ - char buf[1024]; - char *ptr; - int n; - - n = fz_sprintobj(nil, 0, obj, 0); - if (n < sizeof buf) - { - fz_sprintobj(buf, sizeof buf, obj, 0); - fputs(buf, stdout); - fputc('\n', stdout); - } - else - { - ptr = fz_malloc(n); - if (!ptr) - return; - fz_sprintobj(ptr, n, obj, 0); - fputs(ptr, stdout); - fputc('\n', stdout); - fz_free(ptr); - } -} - diff --git a/stream/obj_simple.c b/stream/obj_simple.c deleted file mode 100644 index d8eb77b7..00000000 --- a/stream/obj_simple.c +++ /dev/null @@ -1,323 +0,0 @@ -#include "fitz-base.h" -#include "fitz-stream.h" - -extern void fz_droparray(fz_obj *array); -extern void fz_dropdict(fz_obj *dict); - -#define NEWOBJ(KIND,SIZE) \ - fz_obj *o; \ - o = *op = fz_malloc(SIZE); \ - if (!o) return fz_throw("outofmem: dynamic object"); \ - o->refs = 1; \ - o->kind = KIND; - -fz_error * -fz_newnull(fz_obj **op) -{ - NEWOBJ(FZ_NULL, sizeof (fz_obj)); - return fz_okay; -} - -fz_error * -fz_newbool(fz_obj **op, int b) -{ - NEWOBJ(FZ_BOOL, sizeof (fz_obj)); - o->u.b = b; - return fz_okay; -} - -fz_error * -fz_newint(fz_obj **op, int i) -{ - NEWOBJ(FZ_INT, sizeof (fz_obj)); - o->u.i = i; - return fz_okay; -} - -fz_error * -fz_newreal(fz_obj **op, float f) -{ - NEWOBJ(FZ_REAL, sizeof (fz_obj)); - o->u.f = f; - return fz_okay; -} - -fz_error * -fz_newstring(fz_obj **op, char *str, int len) -{ - NEWOBJ(FZ_STRING, offsetof(fz_obj, u.s.buf) + len + 1); - o->u.s.len = len; - memcpy(o->u.s.buf, str, len); - o->u.s.buf[len] = '\0'; - return fz_okay; -} - -fz_error * -fz_newname(fz_obj **op, char *str) -{ - NEWOBJ(FZ_NAME, offsetof(fz_obj, u.n) + strlen(str) + 1); - strcpy(o->u.n, str); - return fz_okay; -} - -fz_error * -fz_newindirect(fz_obj **op, int objid, int genid) -{ - NEWOBJ(FZ_INDIRECT, sizeof (fz_obj)); - o->u.r.oid = objid; - o->u.r.gid = genid; - return fz_okay; -} - -fz_error * -fz_newpointer(fz_obj **op, void *p) -{ - NEWOBJ(FZ_POINTER, sizeof (fz_obj)); - o->u.p = p; - return fz_okay; -} - -fz_obj * -fz_keepobj(fz_obj *o) -{ - assert(o != nil); - o->refs ++; - return o; -} - -void -fz_dropobj(fz_obj *o) -{ - assert(o != nil); - if (--o->refs == 0) - { - if (o->kind == FZ_ARRAY) - fz_droparray(o); - else if (o->kind == FZ_DICT) - fz_dropdict(o); - else - fz_free(o); - } -} - -int -fz_isnull(fz_obj *obj) -{ - return obj ? obj->kind == FZ_NULL : 0; -} - -int -fz_isbool(fz_obj *obj) -{ - return obj ? obj->kind == FZ_BOOL : 0; -} - -int -fz_isint(fz_obj *obj) -{ - return obj ? obj->kind == FZ_INT : 0; -} - -int -fz_isreal(fz_obj *obj) -{ - return obj ? obj->kind == FZ_REAL : 0; -} - -int -fz_isstring(fz_obj *obj) -{ - return obj ? obj->kind == FZ_STRING : 0; -} - -int -fz_isname(fz_obj *obj) -{ - return obj ? obj->kind == FZ_NAME : 0; -} - -int -fz_isarray(fz_obj *obj) -{ - return obj ? obj->kind == FZ_ARRAY : 0; -} - -int -fz_isdict(fz_obj *obj) -{ - return obj ? obj->kind == FZ_DICT : 0; -} - -int -fz_isindirect(fz_obj *obj) -{ - return obj ? obj->kind == FZ_INDIRECT : 0; -} - -int -fz_ispointer(fz_obj *obj) -{ - return obj ? obj->kind == FZ_POINTER : 0; -} - -int -fz_tobool(fz_obj *obj) -{ - if (fz_isbool(obj)) - return obj->u.b; - return 0; -} - -int -fz_toint(fz_obj *obj) -{ - if (fz_isint(obj)) - return obj->u.i; - if (fz_isreal(obj)) - return obj->u.f; - return 0; -} - -float -fz_toreal(fz_obj *obj) -{ - if (fz_isreal(obj)) - return obj->u.f; - if (fz_isint(obj)) - return obj->u.i; - return 0; -} - -char * -fz_toname(fz_obj *obj) -{ - if (fz_isname(obj)) - return obj->u.n; - return ""; -} - -char * -fz_tostrbuf(fz_obj *obj) -{ - if (fz_isstring(obj)) - return obj->u.s.buf; - return ""; -} - -int -fz_tostrlen(fz_obj *obj) -{ - if (fz_isstring(obj)) - return obj->u.s.len; - return 0; -} - -int -fz_tonum(fz_obj *obj) -{ - if (fz_isindirect(obj)) - return obj->u.r.oid; - return 0; -} - -int -fz_togen(fz_obj *obj) -{ - if (fz_isindirect(obj)) - return obj->u.r.gid; - return 0; -} - -void * -fz_topointer(fz_obj *obj) -{ - if (fz_ispointer(obj)) - return obj->u.p; - return fz_okay; -} - -fz_error * -fz_newnamefromstring(fz_obj **op, fz_obj *str) -{ - NEWOBJ(FZ_NAME, offsetof(fz_obj, u.n) + fz_tostrlen(str) + 1); - memcpy(o->u.n, fz_tostrbuf(str), fz_tostrlen(str)); - o->u.n[fz_tostrlen(str)] = '\0'; - return fz_okay; -} - -int -fz_objcmp(fz_obj *a, fz_obj *b) -{ - int i; - - if (a == b) - return 0; - if (a->kind != b->kind) - return 1; - - switch (a->kind) - { - case FZ_NULL: return 0; - case FZ_BOOL: return a->u.b - b->u.b; - case FZ_INT: return a->u.i - b->u.i; - case FZ_REAL: return a->u.f - b->u.f; - - case FZ_STRING: - if (a->u.s.len != b->u.s.len) - return a->u.s.len - b->u.s.len; - return memcmp(a->u.s.buf, b->u.s.buf, a->u.s.len); - - case FZ_NAME: - return strcmp(a->u.n, b->u.n); - - case FZ_INDIRECT: - if (a->u.r.oid == b->u.r.oid) - return a->u.r.gid - b->u.r.gid; - return a->u.r.oid - b->u.r.oid; - - case FZ_ARRAY: - if (a->u.a.len != b->u.a.len) - return a->u.a.len - b->u.a.len; - for (i = 0; i < a->u.a.len; i++) - if (fz_objcmp(a->u.a.items[i], b->u.a.items[i])) - return 1; - return 0; - - case FZ_DICT: - if (a->u.d.len != b->u.d.len) - return a->u.d.len - b->u.d.len; - for (i = 0; i < a->u.d.len; i++) - { - if (fz_objcmp(a->u.d.items[i].k, b->u.d.items[i].k)) - return 1; - if (fz_objcmp(a->u.d.items[i].v, b->u.d.items[i].v)) - return 1; - } - return 0; - - case FZ_POINTER: - return (char *) a->u.p - (char *) b->u.p; - } - return 1; -} - -char *fz_objkindstr(fz_obj *obj) -{ - if (obj == nil) - return ""; - switch (obj->kind) - { - case FZ_NULL: return "null"; - case FZ_BOOL: return "boolean"; - case FZ_INT: return "integer"; - case FZ_REAL: return "real"; - case FZ_STRING: return "string"; - case FZ_NAME: return "name"; - case FZ_ARRAY: return "array"; - case FZ_DICT: return "dictionary"; - case FZ_INDIRECT: return "reference"; - case FZ_POINTER: return "pointer"; - } - return ""; -} - diff --git a/stream/stm_buffer.c b/stream/stm_buffer.c deleted file mode 100644 index 8a1e0850..00000000 --- a/stream/stm_buffer.c +++ /dev/null @@ -1,105 +0,0 @@ -#include "fitz-base.h" -#include "fitz-stream.h" - -fz_error * -fz_newbuffer(fz_buffer **bp, int size) -{ - fz_buffer *b; - - b = *bp = fz_malloc(sizeof(fz_buffer)); - if (!b) - return fz_throw("outofmem: buffer struct"); - - b->refs = 1; - b->ownsdata = 1; - b->bp = fz_malloc(size); - if (!b->bp) - { - fz_free(b); - return fz_throw("outofmem: buffer memory"); - } - - b->rp = b->bp; - b->wp = b->bp; - b->ep = b->bp + size; - b->eof = 0; - - return fz_okay; -} - -fz_error * -fz_newbufferwithmemory(fz_buffer **bp, unsigned char *data, int size) -{ - fz_buffer *b; - - b = *bp = fz_malloc(sizeof(fz_buffer)); - if (!b) - return fz_throw("outofmem: buffer struct"); - - b->refs = 1; - b->ownsdata = 0; - b->bp = data; - - b->rp = b->bp; - b->wp = b->bp + size; - b->ep = b->bp + size; - b->eof = 0; - - return fz_okay; -} - -fz_buffer * -fz_keepbuffer(fz_buffer *buf) -{ - buf->refs ++; - return buf; -} - -void -fz_dropbuffer(fz_buffer *buf) -{ - if (--buf->refs == 0) - { - if (buf->ownsdata) - fz_free(buf->bp); - fz_free(buf); - } -} - -fz_error * -fz_growbuffer(fz_buffer *buf) -{ - unsigned char *newbp; - - int rp = buf->rp - buf->bp; - int wp = buf->wp - buf->bp; - int ep = buf->ep - buf->bp; - - if (!buf->ownsdata) - return fz_throw("assert: grow borrowed memory"); - - newbp = fz_realloc(buf->bp, ep * 2); - if (!newbp) - return fz_throw("outofmem: resize buffer memory"); - - buf->bp = newbp; - buf->rp = buf->bp + rp; - buf->wp = buf->bp + wp; - buf->ep = buf->bp + ep * 2; - - return fz_okay; -} - -fz_error * -fz_rewindbuffer(fz_buffer *buf) -{ - if (!buf->ownsdata) - return fz_throw("assert: rewind borrowed memory"); - - memmove(buf->bp, buf->rp, buf->wp - buf->rp); - buf->wp = buf->bp + (buf->wp - buf->rp); - buf->rp = buf->bp; - - return fz_okay; -} - diff --git a/stream/stm_filter.c b/stream/stm_filter.c deleted file mode 100644 index 450433d4..00000000 --- a/stream/stm_filter.c +++ /dev/null @@ -1,61 +0,0 @@ -#include "fitz-base.h" -#include "fitz-stream.h" - -fz_error fz_kioneedin = { "", "", "", 0, nil }; -fz_error fz_kioneedout = { "", "", "", 0, nil }; -fz_error fz_kiodone = { "", "", "", 0, nil }; - -fz_error * -fz_process(fz_filter *f, fz_buffer *in, fz_buffer *out) -{ - fz_error *reason; - unsigned char *oldrp; - unsigned char *oldwp; - - assert(!out->eof); - - oldrp = in->rp; - oldwp = out->wp; - - if (f->done) - return fz_iodone; - - reason = f->process(f, in, out); - - assert(in->rp <= in->wp); - assert(out->wp <= out->ep); - - f->consumed = in->rp > oldrp; - f->produced = out->wp > oldwp; - f->count += out->wp - oldwp; - - /* iodone or error */ - if (reason != fz_ioneedin && reason != fz_ioneedout) - { - if (reason != fz_iodone) - reason = fz_rethrow(reason, "cannot process filter"); - out->eof = 1; - f->done = 1; - } - - return reason; -} - -fz_filter * -fz_keepfilter(fz_filter *f) -{ - f->refs ++; - return f; -} - -void -fz_dropfilter(fz_filter *f) -{ - if (--f->refs == 0) - { - if (f->drop) - f->drop(f); - fz_free(f); - } -} - diff --git a/stream/stm_misc.c b/stream/stm_misc.c deleted file mode 100644 index 70c1c315..00000000 --- a/stream/stm_misc.c +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Miscellaneous I/O functions - */ - -#include "fitz-base.h" -#include "fitz-stream.h" - -int -fz_tell(fz_stream *stm) -{ - if (stm->mode == FZ_SREAD) - return fz_rtell(stm); - return fz_wtell(stm); -} - -fz_error * -fz_seek(fz_stream *stm, int offset, int whence) -{ - if (stm->mode == FZ_SREAD) - return fz_rseek(stm, offset, whence); - return fz_wseek(stm, offset, whence); -} - -/* - * Read a line terminated by LF or CR or CRLF. - */ - -fz_error * -fz_readline(fz_stream *stm, char *mem, int n) -{ - fz_error *error; - - char *s = mem; - int c = EOF; - while (n > 1) - { - c = fz_readbyte(stm); - if (c == EOF) - break; - if (c == '\r') { - c = fz_peekbyte(stm); - if (c == '\n') - c = fz_readbyte(stm); - break; - } - if (c == '\n') - break; - *s++ = c; - n--; - } - if (n) - *s = '\0'; - - error = fz_readerror(stm); - if (error) - return fz_rethrow(error, "cannot read line"); - return fz_okay; -} - -/* - * Utility function to consume all the contents of an input stream into - * a freshly allocated buffer. - */ - -fz_error * -fz_readall(fz_buffer **bufp, fz_stream *stm, int sizehint) -{ - fz_error *error; - fz_buffer *buf; - int c; - - if (sizehint == 0) - sizehint = 4 * 1024; - - error = fz_newbuffer(&buf, sizehint); - if (error) - return fz_rethrow(error, "cannot create scratch buffer"); - - for (c = fz_readbyte(stm); c != EOF; c = fz_readbyte(stm)) - { - if (buf->wp == buf->ep) - { - error = fz_growbuffer(buf); - if (error) - { - fz_dropbuffer(buf); - return fz_rethrow(error, "cannot resize scratch buffer"); - } - } - - *buf->wp++ = c; - } - - *bufp = buf; - return fz_okay; -} - diff --git a/stream/stm_open.c b/stream/stm_open.c deleted file mode 100644 index 14e52642..00000000 --- a/stream/stm_open.c +++ /dev/null @@ -1,242 +0,0 @@ -/* - * Creation and destruction. - */ - -#include "fitz-base.h" -#include "fitz-stream.h" - -static fz_stream * -newstm(int kind, int mode) -{ - fz_stream *stm; - - stm = fz_malloc(sizeof(fz_stream)); - if (!stm) - return nil; - - stm->refs = 1; - stm->kind = kind; - stm->mode = mode; - stm->dead = 0; - stm->error = fz_okay; - stm->buffer = nil; - - stm->chain = nil; - stm->filter = nil; - stm->file = -1; - - return stm; -} - -fz_stream * -fz_keepstream(fz_stream *stm) -{ - stm->refs ++; - return stm; -} - -void -fz_dropstream(fz_stream *stm) -{ - stm->refs --; - if (stm->refs == 0) - { - if (stm->error) - { - fflush(stdout); - fz_printerror(stm->error); - fz_droperror(stm->error); - fflush(stderr); - fz_warn("dropped unhandled ioerror"); - } - - if (stm->mode == FZ_SWRITE) - { - stm->buffer->eof = 1; - fz_flush(stm); - } - - switch (stm->kind) - { - case FZ_SFILE: - close(stm->file); - break; - case FZ_SFILTER: - fz_dropfilter(stm->filter); - fz_dropstream(stm->chain); - break; - case FZ_SBUFFER: - break; - } - - fz_dropbuffer(stm->buffer); - fz_free(stm); - } -} - -static fz_error * -openfile(fz_stream **stmp, char *path, int mode, int realmode) -{ - fz_error *error; - fz_stream *stm; - - stm = newstm(FZ_SFILE, mode); - if (!stm) - return fz_throw("outofmem: stream struct"); - - error = fz_newbuffer(&stm->buffer, FZ_BUFSIZE); - if (error) - { - fz_free(stm); - return fz_rethrow(error, "cannot create buffer"); - } - - stm->file = open(path, realmode, 0666); - if (stm->file < 0) - { - fz_dropbuffer(stm->buffer); - fz_free(stm); - return fz_throw("syserr: open '%s': %s", path, strerror(errno)); - } - - *stmp = stm; - return fz_okay; -} - -static fz_error * -openfilter(fz_stream **stmp, fz_filter *flt, fz_stream *src, int mode) -{ - fz_error *error; - fz_stream *stm; - - stm = newstm(FZ_SFILTER, mode); - if (!stm) - return fz_throw("outofmem: stream struct"); - - error = fz_newbuffer(&stm->buffer, FZ_BUFSIZE); - if (error) - { - fz_free(stm); - return fz_rethrow(error, "cannot create buffer"); - } - - stm->chain = fz_keepstream(src); - stm->filter = fz_keepfilter(flt); - - *stmp = stm; - return fz_okay; -} - -static fz_error * -openbuffer(fz_stream **stmp, fz_buffer *buf, int mode) -{ - fz_stream *stm; - - stm = newstm(FZ_SBUFFER, mode); - if (!stm) - return fz_throw("outofmem: stream struct"); - - stm->buffer = fz_keepbuffer(buf); - - if (mode == FZ_SREAD) - stm->buffer->eof = 1; - - *stmp = stm; - return fz_okay; -} - -fz_error * fz_openrfile(fz_stream **stmp, char *path) -{ - fz_error *error; - error = openfile(stmp, path, FZ_SREAD, O_BINARY | O_RDONLY); - if (error) - return fz_rethrow(error, "cannot open file for reading: '%s'", path); - return fz_okay; -} - -fz_error * fz_openwfile(fz_stream **stmp, char *path) -{ - fz_error *error; - error = openfile(stmp, path, FZ_SWRITE, - O_BINARY | O_WRONLY | O_CREAT | O_TRUNC); - if (error) - return fz_rethrow(error, "cannot open file for writing: '%s'", path); - return fz_okay; -} - -fz_error * fz_openafile(fz_stream **stmp, char *path) -{ - fz_error *error; - int t; - - error = openfile(stmp, path, FZ_SWRITE, O_BINARY | O_WRONLY); - if (error) - return fz_rethrow(error, "cannot open file for writing: '%s'", path); - - t = lseek((*stmp)->file, 0, 2); - if (t < 0) - { - (*stmp)->dead = 1; - return fz_throw("syserr: lseek '%s': %s", path, strerror(errno)); - } - - return fz_okay; -} - -fz_error * fz_openrfilter(fz_stream **stmp, fz_filter *flt, fz_stream *src) -{ - fz_error *error; - error = openfilter(stmp, flt, src, FZ_SREAD); - if (error) - return fz_rethrow(error, "cannot create reading filter stream"); - return fz_okay; -} - -fz_error * fz_openwfilter(fz_stream **stmp, fz_filter *flt, fz_stream *src) -{ - fz_error *error; - error = openfilter(stmp, flt, src, FZ_SWRITE); - if (error) - return fz_rethrow(error, "cannot create writing filter stream"); - return fz_okay; -} - -fz_error * fz_openrbuffer(fz_stream **stmp, fz_buffer *buf) -{ - fz_error *error; - error = openbuffer(stmp, buf, FZ_SREAD); - if (error) - return fz_rethrow(error, "cannot create reading buffer stream"); - return fz_okay; -} - -fz_error * fz_openwbuffer(fz_stream **stmp, fz_buffer *buf) -{ - fz_error *error; - error = openbuffer(stmp, buf, FZ_SWRITE); - if (error) - return fz_rethrow(error, "cannot create writing buffer stream"); - return fz_okay; -} - -fz_error * fz_openrmemory(fz_stream **stmp, unsigned char *mem, int len) -{ - fz_error *error; - fz_buffer *buf; - - error = fz_newbufferwithmemory(&buf, mem, len); - if (error) - return fz_rethrow(error, "cannot create memory buffer"); - - error = fz_openrbuffer(stmp, buf); - if (error) - { - fz_dropbuffer(buf); - return fz_rethrow(error, "cannot open memory buffer stream"); - } - - fz_dropbuffer(buf); - - return fz_okay; -} - diff --git a/stream/stm_read.c b/stream/stm_read.c deleted file mode 100644 index e0a6e8a1..00000000 --- a/stream/stm_read.c +++ /dev/null @@ -1,313 +0,0 @@ -/* - * Input streams. - */ - -#include "fitz-base.h" -#include "fitz-stream.h" - -fz_error * -fz_readimp(fz_stream *stm) -{ - fz_buffer *buf = stm->buffer; - fz_error *error; - fz_error *reason; - int produced; - int n; - - if (stm->dead) - return fz_throw("assert: read from dead stream"); - - if (stm->mode != FZ_SREAD) - return fz_throw("assert: read from writing stream"); - - if (buf->eof) - return fz_okay; - - error = fz_rewindbuffer(buf); - if (error) - { - stm->dead = 1; - return fz_rethrow(error, "cannot rewind output buffer"); - } - - if (buf->ep - buf->wp == 0) - { - error = fz_growbuffer(buf); - if (error) - { - stm->dead = 1; - return fz_rethrow(error, "cannot grow output buffer"); - } - } - - switch (stm->kind) - { - - case FZ_SFILE: - n = read(stm->file, buf->wp, buf->ep - buf->wp); - if (n == -1) - { - stm->dead = 1; - return fz_throw("syserr: read: %s", strerror(errno)); - } - - if (n == 0) - buf->eof = 1; - buf->wp += n; - - return fz_okay; - - case FZ_SFILTER: - produced = 0; - - while (1) - { - reason = fz_process(stm->filter, stm->chain->buffer, buf); - - if (stm->filter->produced) - produced = 1; - - if (reason == fz_ioneedin) - { - error = fz_readimp(stm->chain); - if (error) - { - stm->dead = 1; - return fz_rethrow(error, "cannot read from input stream"); - } - } - - else if (reason == fz_ioneedout) - { - if (produced) - return 0; - - if (buf->rp > buf->bp) - { - error = fz_rewindbuffer(buf); - if (error) - { - stm->dead = 1; - return fz_rethrow(error, "cannot rewind buffer"); - } - } - else - { - error = fz_growbuffer(buf); - if (error) - { - stm->dead = 1; - return fz_rethrow(error, "cannot grow buffer"); - } - } - } - - else if (reason == fz_iodone) - { - return fz_okay; - } - - else - { - stm->dead = 1; - return fz_rethrow(reason, "cannot process filter"); - } - } - - case FZ_SBUFFER: - return fz_okay; - - default: - return fz_throw("assert: unknown stream type"); - } -} - -int -fz_rtell(fz_stream *stm) -{ - fz_buffer *buf = stm->buffer; - int t; - - if (stm->dead) - return EOF; - if (stm->mode != FZ_SREAD) - return EOF; - - switch (stm->kind) - { - case FZ_SFILE: - t = lseek(stm->file, 0, 1); - if (t < 0) - { - fz_warn("syserr: lseek: %s", strerror(errno)); - stm->dead = 1; - return EOF; - } - return t - (buf->wp - buf->rp); - - case FZ_SFILTER: - return stm->filter->count - (buf->wp - buf->rp); - - case FZ_SBUFFER: - return buf->rp - buf->bp; - - default: - return EOF; - } -} - -fz_error * -fz_rseek(fz_stream *stm, int offset, int whence) -{ - fz_error *error; - fz_buffer *buf = stm->buffer; - int t, c; - - if (stm->dead) - return fz_throw("assert: seek in dead stream"); - - if (stm->mode != FZ_SREAD) - return fz_throw("assert: read operation on writing stream"); - - if (whence == 1) - { - int cur = fz_rtell(stm); - if (cur < 0) - return fz_throw("cannot tell current position"); - offset = cur + offset; - whence = 0; - } - - buf->eof = 0; - - switch (stm->kind) - { - case FZ_SFILE: - t = lseek(stm->file, offset, whence); - if (t < 0) - { - stm->dead = 1; - return fz_throw("syserr: lseek: %s", strerror(errno)); - } - - buf->rp = buf->bp; - buf->wp = buf->bp; - - return fz_okay; - - case FZ_SFILTER: - if (whence == 0) - { - if (offset < fz_rtell(stm)) - { - stm->dead = 1; - return fz_throw("assert: seek backwards in filter"); - } - while (fz_rtell(stm) < offset) - { - c = fz_readbyte(stm); - if (c == EOF) - { - error = fz_readerror(stm); - if (error) - return fz_rethrow(error, "cannot seek forward in filter"); - break; - } - } - return fz_okay; - } - - stm->dead = 1; - return fz_throw("assert: relative seek in filter"); - - case FZ_SBUFFER: - if (whence == 0) - buf->rp = CLAMP(buf->bp + offset, buf->bp, buf->ep); - else - buf->rp = CLAMP(buf->ep + offset, buf->bp, buf->ep); - return fz_okay; - - default: - return fz_throw("unknown stream type"); - } -} - -fz_error * -fz_read(int *np, fz_stream *stm, unsigned char *mem, int n) -{ - fz_error *error; - fz_buffer *buf = stm->buffer; - int i = 0; - - while (i < n) - { - while (buf->rp < buf->wp && i < n) - mem[i++] = *buf->rp++; - - if (buf->rp == buf->wp) - { - if (buf->eof) - { - *np = i; - return fz_okay; - } - - error = fz_readimp(stm); - if (error) - return fz_rethrow(error, "cannot produce data"); - } - } - - *np = i; - return fz_okay; -} - -fz_error * -fz_readerror(fz_stream *stm) -{ - fz_error *error; - if (stm->error) - { - error = stm->error; - stm->error = fz_okay; - return fz_rethrow(error, "delayed read error"); - } - return fz_okay; -} - -int -fz_readbytex(fz_stream *stm) -{ - fz_buffer *buf = stm->buffer; - - if (buf->rp == buf->wp) - { - if (!buf->eof && !stm->error) - { - fz_error *error = fz_readimp(stm); - if (error) - stm->error = fz_rethrow(error, "cannot read data"); - } - } - - return buf->rp < buf->wp ? *buf->rp++ : EOF ; -} - -int -fz_peekbytex(fz_stream *stm) -{ - fz_buffer *buf = stm->buffer; - - if (buf->rp == buf->wp) - { - if (!buf->eof && !stm->error) - { - fz_error *error = fz_readimp(stm); - if (error) - stm->error = fz_rethrow(error, "cannot read data"); - } - } - - return buf->rp < buf->wp ? *buf->rp : EOF ; -} - diff --git a/stream/stm_write.c b/stream/stm_write.c deleted file mode 100644 index ed928b50..00000000 --- a/stream/stm_write.c +++ /dev/null @@ -1,313 +0,0 @@ -/* - * Output streams. - */ - -#include "fitz-base.h" -#include "fitz-stream.h" - -int -fz_wtell(fz_stream *stm) -{ - fz_buffer *buf = stm->buffer; - int t; - - if (stm->dead) - return EOF; - - if (stm->mode != FZ_SWRITE) - return EOF; - - switch (stm->kind) - { - case FZ_SFILE: - t = lseek(stm->file, 0, 1); - if (t < 0) - { - fz_warn("syserr: lseek: %s", strerror(errno)); - stm->dead = 1; - return EOF; - } - return t + (buf->wp - buf->rp); - - case FZ_SFILTER: - return stm->filter->count + (buf->wp - buf->rp); - - case FZ_SBUFFER: - return buf->wp - buf->bp; - - default: - return EOF; - } -} - -fz_error * -fz_wseek(fz_stream *stm, int offset, int whence) -{ - fz_buffer *buf = stm->buffer; - int t; - - if (stm->dead) - return fz_throw("assert: seek in dead stream"); - - if (stm->mode != FZ_SWRITE) - return fz_throw("assert: write operation on reading stream"); - - if (stm->kind != FZ_SFILE) - return fz_throw("assert: write seek on non-file stream"); - - t = lseek(stm->file, offset, whence); - if (t < 0) - { - stm->dead = 1; - return fz_throw("syserr: lseek: %s", strerror(errno)); - } - - buf->rp = buf->bp; - buf->wp = buf->bp; - buf->eof = 0; - - return fz_okay; -} - -static fz_error * -fz_flushfilterimp(fz_stream *stm) -{ - fz_buffer *buf = stm->buffer; - fz_error *error; - fz_error *reason; - -loop: - - reason = fz_process(stm->filter, stm->buffer, stm->chain->buffer); - - if (reason == fz_ioneedin) - { - if (buf->rp > buf->bp) - { - error = fz_rewindbuffer(buf); - if (error) - { - stm->dead = 1; - return fz_rethrow(error, "cannot rewind buffer"); - } - } - else - { - error = fz_growbuffer(buf); - if (error) - { - stm->dead = 1; - return fz_rethrow(error, "cannot grow buffer"); - } - } - } - - else if (reason == fz_ioneedout) - { - error = fz_flush(stm->chain); - if (error) - return fz_rethrow(error, "cannot flush chain buffer"); - } - - else if (reason == fz_iodone) - { - stm->dead = 2; /* special flag that we are dead because of eod */ - } - - else - { - stm->dead = 1; - return fz_rethrow(reason, "cannot process filter"); - } - - /* if we are at eof, repeat until other filter sets otherside to eof */ - if (buf->eof && !stm->chain->buffer->eof) - goto loop; - - return fz_okay; -} - -/* - * Empty the buffer into the sink. - * Promise to make more space available. - * Called by fz_write and fz_dropstream. - * If buffer is eof, then all data must be flushed. - */ -fz_error * -fz_flush(fz_stream *stm) -{ - fz_buffer *buf = stm->buffer; - fz_error *error; - int t; - - if (stm->dead == 2) /* eod flag */ - return fz_okay; - - if (stm->dead) - return fz_throw("assert: flush on dead stream"); - - if (stm->mode != FZ_SWRITE) - return fz_throw("assert: write operation on reading stream"); - - switch (stm->kind) - { - case FZ_SFILE: - while (buf->rp < buf->wp) - { - t = write(stm->file, buf->rp, buf->wp - buf->rp); - if (t < 0) - { - stm->dead = 1; - return fz_throw("syserr: write: %s", strerror(errno)); - } - - buf->rp += t; - } - - if (buf->rp > buf->bp) - { - error = fz_rewindbuffer(buf); - if (error) - { - stm->dead = 1; - return fz_rethrow(error, "cannot rewind buffer"); - } - } - - return fz_okay; - - case FZ_SFILTER: - error = fz_flushfilterimp(stm); - if (error) - return fz_rethrow(error, "cannot flush through filter"); - return fz_okay; - - case FZ_SBUFFER: - if (!buf->eof && buf->wp == buf->ep) - { - error = fz_growbuffer(buf); - if (error) - { - stm->dead = 1; - return fz_rethrow(error, "cannot grow buffer"); - } - } - return fz_okay; - - default: - return fz_throw("unknown stream type"); - } -} - -/* - * Write data to stream. - * Buffer until internal buffer is full. - * When full, call fz_flush to make more space available. - * Return error if all the data could not be written. - */ -fz_error * -fz_write(fz_stream *stm, unsigned char *mem, int n) -{ - fz_buffer *buf = stm->buffer; - fz_error *error; - int i = 0; - - if (stm->dead) - return fz_throw("assert: write on dead stream"); - - if (stm->mode != FZ_SWRITE) - return fz_throw("assert: write on reading stream"); - - while (i < n) - { - while (buf->wp < buf->ep && i < n) - *buf->wp++ = mem[i++]; - - if (buf->wp == buf->ep && i < n) - { - error = fz_flush(stm); - if (error) - return fz_rethrow(error, "cannot flush buffer"); - if (stm->dead) - return fz_throw("assert: write on dead stream"); - } - } - - return fz_okay; -} - -fz_error * -fz_printstr(fz_stream *stm, char *s) -{ - return fz_write(stm, (unsigned char *) s, strlen(s)); -} - -fz_error * -fz_printobj(fz_stream *file, fz_obj *obj, int tight) -{ - fz_error *error; - unsigned char buf[1024]; - char *ptr; - int n; - - n = fz_sprintobj(nil, 0, obj, tight); - if (n < sizeof buf) - { - fz_sprintobj(buf, sizeof buf, obj, tight); - error = fz_write(file, (unsigned char *) buf, n); - if (error) - return fz_rethrow(error, "cannot write buffer"); - return fz_okay; - } - else - { - ptr = fz_malloc(n); - if (!ptr) - return fz_throw("outofmem: scratch buffer"); - fz_sprintobj(ptr, n, obj, tight); - error = fz_write(file, (unsigned char *) ptr, n); - fz_free(ptr); - if (error) - return fz_rethrow(error, "cannot write buffer"); - return fz_okay; - } -} - -fz_error * -fz_print(fz_stream *stm, char *fmt, ...) -{ - fz_error *error; - va_list ap; - char buf[1024]; - char *p; - int n; - - va_start(ap, fmt); - n = vsnprintf(buf, sizeof buf, fmt, ap); - va_end(ap); - - if (n < sizeof buf) - { - error = fz_write(stm, (unsigned char *) buf, n); - if (error) - return fz_rethrow(error, "cannot write buffer"); - return fz_okay; - } - - p = fz_malloc(n); - if (!p) - return fz_throw("outofmem: scratch buffer"); - - va_start(ap, fmt); - vsnprintf(p, n, fmt, ap); - va_end(ap); - - error = fz_write(stm, (unsigned char *) p, n); - - fz_free(p); - - if (error) - return fz_rethrow(error, "cannot write buffer"); - return fz_okay; -} - diff --git a/world/Jamfile b/world/Jamfile deleted file mode 100644 index 9f53ef0a..00000000 --- a/world/Jamfile +++ /dev/null @@ -1,19 +0,0 @@ -SubDir TOP world ; - -Library libworld : - - node_toxml.c - node_misc1.c - node_misc2.c - node_optimize.c - node_path.c - node_text.c - node_tree.c - - res_colorspace.c - res_font.c - res_image.c - res_shade.c - - ; - diff --git a/world/node_misc1.c b/world/node_misc1.c deleted file mode 100644 index fc8407d5..00000000 --- a/world/node_misc1.c +++ /dev/null @@ -1,155 +0,0 @@ -#include "fitz-base.h" -#include "fitz-world.h" - -void fz_droplinknode(fz_linknode* node); -void fz_droppathnode(fz_pathnode* node); -void fz_droptextnode(fz_textnode* node); -void fz_dropimagenode(fz_imagenode* node); -void fz_dropshadenode(fz_shadenode* node); - -fz_rect fz_boundtransformnode(fz_transformnode* node, fz_matrix ctm); -fz_rect fz_boundovernode(fz_overnode* node, fz_matrix ctm); -fz_rect fz_boundmasknode(fz_masknode* node, fz_matrix ctm); -fz_rect fz_boundblendnode(fz_blendnode* node, fz_matrix ctm); -fz_rect fz_boundsolidnode(fz_solidnode* node, fz_matrix ctm); -fz_rect fz_boundpathnode(fz_pathnode* node, fz_matrix ctm); -fz_rect fz_boundtextnode(fz_textnode* node, fz_matrix ctm); -fz_rect fz_boundimagenode(fz_imagenode* node, fz_matrix ctm); -fz_rect fz_boundshadenode(fz_shadenode* node, fz_matrix ctm); -fz_rect fz_boundlinknode(fz_linknode* node, fz_matrix ctm); - -void -fz_initnode(fz_node *node, fz_nodekind kind) -{ - node->kind = kind; - node->parent = nil; - node->first = nil; - node->last = nil; - node->next = nil; -} - -void -fz_dropnode(fz_node *node) -{ - if (node->first) - fz_dropnode(node->first); - if (node->next) - fz_dropnode(node->next); - - switch (node->kind) - { - case FZ_NTRANSFORM: - case FZ_NOVER: - case FZ_NMASK: - case FZ_NBLEND: - case FZ_NCOLOR: - break; - case FZ_NPATH: - fz_droppathnode((fz_pathnode *) node); - break; - case FZ_NTEXT: - fz_droptextnode((fz_textnode *) node); - break; - case FZ_NIMAGE: - fz_dropimagenode((fz_imagenode *) node); - break; - case FZ_NSHADE: - fz_dropshadenode((fz_shadenode *) node); - break; - case FZ_NLINK: - fz_droplinknode((fz_linknode *) node); - break; - } - - fz_free(node); -} - -fz_rect -fz_boundnode(fz_node *node, fz_matrix ctm) -{ - switch (node->kind) - { - case FZ_NTRANSFORM: - return fz_boundtransformnode((fz_transformnode *) node, ctm); - case FZ_NOVER: - return fz_boundovernode((fz_overnode *) node, ctm); - case FZ_NMASK: - return fz_boundmasknode((fz_masknode *) node, ctm); - case FZ_NBLEND: - return fz_boundblendnode((fz_blendnode *) node, ctm); - case FZ_NCOLOR: - return fz_boundsolidnode((fz_solidnode *) node, ctm); - case FZ_NPATH: - return fz_boundpathnode((fz_pathnode *) node, ctm); - case FZ_NTEXT: - return fz_boundtextnode((fz_textnode *) node, ctm); - case FZ_NIMAGE: - return fz_boundimagenode((fz_imagenode *) node, ctm); - case FZ_NSHADE: - return fz_boundshadenode((fz_shadenode *) node, ctm); - case FZ_NLINK: - return fz_boundlinknode((fz_linknode *) node, ctm); - } - return fz_emptyrect; -} - -int -fz_istransformnode(fz_node *node) -{ - return node ? node->kind == FZ_NTRANSFORM : 0; -} - -int -fz_isovernode(fz_node *node) -{ - return node ? node->kind == FZ_NOVER : 0; -} - -int -fz_ismasknode(fz_node *node) -{ - return node ? node->kind == FZ_NMASK : 0; -} - -int -fz_isblendnode(fz_node *node) -{ - return node ? node->kind == FZ_NBLEND : 0; -} - -int -fz_issolidnode(fz_node *node) -{ - return node ? node->kind == FZ_NCOLOR : 0; -} - -int -fz_ispathnode(fz_node *node) -{ - return node ? node->kind == FZ_NPATH : 0; -} - -int -fz_istextnode(fz_node *node) -{ - return node ? node->kind == FZ_NTEXT : 0; -} - -int -fz_isimagenode(fz_node *node) -{ - return node ? node->kind == FZ_NIMAGE : 0; -} - -int -fz_isshadenode(fz_node *node) -{ - return node ? node->kind == FZ_NSHADE : 0; -} - -int -fz_islinknode(fz_node *node) -{ - return node ? node->kind == FZ_NLINK : 0; -} - diff --git a/world/node_misc2.c b/world/node_misc2.c deleted file mode 100644 index b83678d1..00000000 --- a/world/node_misc2.c +++ /dev/null @@ -1,296 +0,0 @@ -#include "fitz-base.h" -#include "fitz-world.h" - -/* - * Over - */ - -fz_error * -fz_newovernode(fz_node **nodep) -{ - fz_node *node; - - node = *nodep = fz_malloc(sizeof (fz_overnode)); - if (!node) - return fz_outofmem; - - fz_initnode(node, FZ_NOVER); - - return fz_okay; -} - -fz_rect -fz_boundovernode(fz_overnode *node, fz_matrix ctm) -{ - fz_node *child; - fz_rect bbox; - fz_rect temp; - - child = node->super.first; - if (!child) - return fz_emptyrect; - - bbox = fz_boundnode(child, ctm); - - child = child->next; - while (child) - { - temp = fz_boundnode(child, ctm); - bbox = fz_mergerects(temp, bbox); - child = child->next; - } - - return bbox; -} - -/* - * Mask - */ - -fz_error * -fz_newmasknode(fz_node **nodep) -{ - fz_node *node; - - node = *nodep = fz_malloc(sizeof (fz_masknode)); - if (!node) - return fz_outofmem; - - fz_initnode(node, FZ_NMASK); - - return fz_okay; -} - -fz_rect -fz_boundmasknode(fz_masknode *node, fz_matrix ctm) -{ - fz_node *shape; - fz_node *color; - fz_rect one, two; - - shape = node->super.first; - color = shape->next; - - one = fz_boundnode(shape, ctm); - two = fz_boundnode(color, ctm); - return fz_intersectrects(one, two); -} - -/* - * Blend - */ - -fz_error * -fz_newblendnode(fz_node **nodep, fz_blendkind b, int k, int i) -{ - fz_blendnode *node; - - node = fz_malloc(sizeof (fz_blendnode)); - if (!node) - return fz_outofmem; - *nodep = (fz_node*)node; - - fz_initnode((fz_node*)node, FZ_NBLEND); - node->mode = b; - node->knockout = k; - node->isolated = i; - - return fz_okay; -} - -fz_rect -fz_boundblendnode(fz_blendnode *node, fz_matrix ctm) -{ - fz_node *child; - fz_rect bbox; - fz_rect temp; - - child = node->super.first; - if (!child) - return fz_emptyrect; - - bbox = fz_boundnode(child, ctm); - - child = child->next; - while (child) - { - temp = fz_boundnode(child, ctm); - bbox = fz_mergerects(temp, bbox); - child = child->next; - } - - return bbox; -} - -void -fz_dropblendnode(fz_blendnode *node) -{ - fz_dropcolorspace(node->cs); -} - -/* - * Transform - */ - -fz_error * -fz_newtransformnode(fz_node **nodep, fz_matrix m) -{ - fz_transformnode *node; - - node = fz_malloc(sizeof (fz_transformnode)); - if (!node) - return fz_outofmem; - *nodep = (fz_node*)node; - - fz_initnode((fz_node*)node, FZ_NTRANSFORM); - node->m = m; - - return fz_okay; -} - -fz_rect -fz_boundtransformnode(fz_transformnode *node, fz_matrix ctm) -{ - if (!node->super.first) - return fz_emptyrect; - return fz_boundnode(node->super.first, fz_concat(node->m, ctm)); -} - -/* - * Link to tree - */ - -fz_error * -fz_newlinknode(fz_node **nodep, fz_tree *subtree) -{ - fz_linknode *node; - - node = fz_malloc(sizeof (fz_linknode)); - if (!node) - return fz_outofmem; - *nodep = (fz_node*)node; - - fz_initnode((fz_node*)node, FZ_NLINK); - node->tree = fz_keeptree(subtree); - - return fz_okay; -} - -void -fz_droplinknode(fz_linknode *node) -{ - fz_droptree(node->tree); -} - -fz_rect -fz_boundlinknode(fz_linknode *node, fz_matrix ctm) -{ - return fz_boundtree(node->tree, ctm); -} - -/* - * Solid color - */ - -fz_error * -fz_newsolidnode(fz_node **nodep, float a, fz_colorspace *cs, int n, float *v) -{ - fz_solidnode *node; - int i; - - node = fz_malloc(sizeof(fz_solidnode) + sizeof(float) * n); - if (!node) - return fz_outofmem; - *nodep = (fz_node*)node; - - fz_initnode((fz_node*)node, FZ_NCOLOR); - node->a = a; - node->cs = fz_keepcolorspace(cs); - node->n = n; - for (i = 0; i < n; i++) - node->samples[i] = v[i]; - - return fz_okay; -} - -fz_rect -fz_boundsolidnode(fz_solidnode *node, fz_matrix ctm) -{ - return fz_infiniterect; -} - -void -fz_dropsolidnode(fz_solidnode *node) -{ - fz_dropcolorspace(node->cs); -} - -/* - * Image node - */ - -fz_error * -fz_newimagenode(fz_node **nodep, fz_image *image) -{ - fz_imagenode *node; - - node = fz_malloc(sizeof (fz_imagenode)); - if (!node) - return fz_outofmem; - *nodep = (fz_node*)node; - - fz_initnode((fz_node*)node, FZ_NIMAGE); - node->image = fz_keepimage(image); - - return fz_okay; -} - -void -fz_dropimagenode(fz_imagenode *node) -{ - fz_dropimage(node->image); -} - -fz_rect -fz_boundimagenode(fz_imagenode *node, fz_matrix ctm) -{ - fz_rect bbox; - bbox.x0 = 0; - bbox.y0 = 0; - bbox.x1 = 1; - bbox.y1 = 1; - return fz_transformaabb(ctm, bbox); -} - -/* - * Shade node - */ - -fz_error * -fz_newshadenode(fz_node **nodep, fz_shade *shade) -{ - fz_shadenode *node; - - node = fz_malloc(sizeof (fz_shadenode)); - if (!node) - return fz_outofmem; - *nodep = (fz_node*)node; - - fz_initnode((fz_node*)node, FZ_NSHADE); - node->shade = fz_keepshade(shade); - - return fz_okay; -} - -void -fz_dropshadenode(fz_shadenode *node) -{ - fz_dropshade(node->shade); -} - -fz_rect -fz_boundshadenode(fz_shadenode *node, fz_matrix ctm) -{ - return fz_boundshade(node->shade, ctm); -} - diff --git a/world/node_optimize.c b/world/node_optimize.c deleted file mode 100644 index cb3918e1..00000000 --- a/world/node_optimize.c +++ /dev/null @@ -1,235 +0,0 @@ -#include "fitz-base.h" -#include "fitz-world.h" - -/* - * Remove (mask ... white) until we get something not white - */ - -static int iswhitenode(fz_solidnode *node) -{ - if (!strcmp(node->cs->name, "DeviceGray")) - return fabs(node->samples[0] - 1.0) < FLT_EPSILON; - if (!strcmp(node->cs->name, "DeviceRGB")) - return fabs(node->samples[0] - 1.0) < FLT_EPSILON && - fabs(node->samples[1] - 1.0) < FLT_EPSILON && - fabs(node->samples[2] - 1.0) < FLT_EPSILON; - if (!strcmp(node->cs->name, "DeviceCMYK")) - return fabs(node->samples[0]) < FLT_EPSILON && - fabs(node->samples[1]) < FLT_EPSILON && - fabs(node->samples[2]) < FLT_EPSILON && - fabs(node->samples[3]) < FLT_EPSILON; - return 0; -} - -static int cleanwhite(fz_node *node) -{ - fz_node *current; - fz_node *next; - fz_node *shape; - fz_node *color; - - for (current = node->first; current; current = next) - { - next = current->next; - - if (fz_islinknode(current)) - return 1; - else if (fz_isimagenode(current)) - return 1; - else if (fz_isshadenode(current)) - return 1; - else if (fz_issolidnode(current)) - { - if (!iswhitenode((fz_solidnode*)current)) - return 1; - } - - else if (fz_ismasknode(current)) - { - shape = current->first; - color = shape->next; - if (fz_issolidnode(color)) - { - if (iswhitenode((fz_solidnode*)color)) - fz_removenode(current); - else - return 1; - } - else - { - if (cleanwhite(current)) - return 1; - } - } - - else - { - if (cleanwhite(current)) - return 1; - } - } - - return 0; -} - -/* - * Remove useless overs that only have one child. - */ - -static void cleanovers(fz_node *node) -{ - fz_node *prev; - fz_node *next; - fz_node *current; - fz_node *child; - - prev = nil; - for (current = node->first; current; current = next) - { - next = current->next; - - if (fz_isovernode(current)) - { - if (current->first == current->last) - { - child = current->first; - fz_removenode(current); - if (child) - { - if (prev) - fz_insertnodeafter(prev, child); - else - fz_insertnodefirst(node, child); - } - current = child; - } - } - - if (current) - prev = current; - } - - for (current = node->first; current; current = current->next) - cleanovers(current); -} - -/* - * Remove rectangular clip-masks whose contents fit... - */ - -static int getrect(fz_pathnode *path, fz_rect *bboxp) -{ - float x, y, w, h; - - /* move x y, line x+w y, line x+w y+h, line x y+h, close */ - - if (path->len != 13) - return 0; - - if (path->els[0].k != FZ_MOVETO) return 0; - x = path->els[1].v; - y = path->els[2].v; - - if (path->els[3].k != FZ_LINETO) return 0; - w = path->els[4].v - x; - if (path->els[5].v != y) return 0; - - if (path->els[6].k != FZ_LINETO) return 0; - if (path->els[7].v != x + w) return 0; - h = path->els[8].v - y; - - if (path->els[9].k != FZ_LINETO) return 0; - if (path->els[10].v != x) return 0; - if (path->els[11].v != y + h) return 0; - - if (path->els[12].k != FZ_CLOSEPATH) return 0; - - bboxp->x0 = MIN(x, x + w); - bboxp->y0 = MIN(y, y + h); - bboxp->x1 = MAX(x, x + w); - bboxp->y1 = MAX(y, y + h); - - return 1; -} - -static int fitsinside(fz_node *node, fz_rect clip) -{ - fz_rect bbox; - bbox = fz_boundnode(node, fz_identity()); - if (fz_isinfiniterect(bbox)) return 0; - if (fz_isemptyrect(bbox)) return 1; - if (bbox.x0 < clip.x0) return 0; - if (bbox.x1 > clip.x1) return 0; - if (bbox.y0 < clip.y0) return 0; - if (bbox.y1 > clip.y1) return 0; - return 1; -} - -static void cleanmasks(fz_node *node) -{ - fz_node *prev; - fz_node *current; - fz_node *shape; - fz_node *color; - fz_rect bbox; - - for (current = node->first; current; current = current->next) - cleanmasks(current); - - prev = nil; - for (current = node->first; current; current = current->next) - { -retry: - if (!current) - break; - - if (fz_ismasknode(current)) - { - shape = current->first; - color = shape->next; - - if (color == nil) - { - fz_removenode(current); - prev = nil; - current = node->first; - goto retry; - } - - if (fz_ispathnode(shape)) - { - if (getrect((fz_pathnode*)shape, &bbox)) - { - if (fitsinside(color, bbox)) - { - fz_removenode(current); - if (prev) - fz_insertnodeafter(prev, color); - else - fz_insertnodefirst(node, color); - current = color; - goto retry; - } - } - } - } - - prev = current; - } -} - -/* - * - */ - -fz_error * -fz_optimizetree(fz_tree *tree) -{ - if (getenv("DONTOPT")) - return fz_okay; - cleanwhite(tree->root); - cleanovers(tree->root); - cleanmasks(tree->root); - return fz_okay; -} - diff --git a/world/node_path.c b/world/node_path.c deleted file mode 100644 index b5aea542..00000000 --- a/world/node_path.c +++ /dev/null @@ -1,347 +0,0 @@ -#include "fitz-base.h" -#include "fitz-world.h" - -fz_error * -fz_newpathnode(fz_pathnode **pathp) -{ - fz_pathnode *path; - - path = *pathp = fz_malloc(sizeof(fz_pathnode)); - if (!path) - return fz_outofmem; - - fz_initnode((fz_node*)path, FZ_NPATH); - - path->paint = FZ_FILL; - path->linecap = 0; - path->linejoin = 0; - path->linewidth = 1.0; - path->miterlimit = 10.0; - path->dash = nil; - path->len = 0; - path->cap = 0; - path->els = nil; - - return fz_okay; -} - -fz_error * -fz_clonepathnode(fz_pathnode **pathp, fz_pathnode *oldpath) -{ - fz_pathnode *path; - - path = *pathp = fz_malloc(sizeof(fz_pathnode)); - if (!path) - return fz_outofmem; - - fz_initnode((fz_node*)path, FZ_NPATH); - - path->paint = FZ_FILL; - path->linecap = 0; - path->linejoin = 0; - path->linewidth = 1.0; - path->miterlimit = 10.0; - path->dash = nil; - path->len = oldpath->len; - path->cap = oldpath->len; - - path->els = fz_malloc(sizeof (fz_pathel) * path->len); - if (!path->els) { - fz_free(path); - return fz_outofmem; - } - memcpy(path->els, oldpath->els, sizeof(fz_pathel) * path->len); - - return fz_okay; -} - -void -fz_droppathnode(fz_pathnode *node) -{ - fz_free(node->dash); - fz_free(node->els); -} - -static fz_error * -growpath(fz_pathnode *path, int n) -{ - int newcap; - fz_pathel *newels; - - while (path->len + n > path->cap) - { - newcap = path->cap + 36; - newels = fz_realloc(path->els, sizeof (fz_pathel) * newcap); - if (!newels) - return fz_outofmem; - path->cap = newcap; - path->els = newels; - } - - return fz_okay; -} - -fz_error * -fz_moveto(fz_pathnode *path, float x, float y) -{ - if (growpath(path, 3) != nil) - return fz_outofmem; - path->els[path->len++].k = FZ_MOVETO; - path->els[path->len++].v = x; - path->els[path->len++].v = y; - return fz_okay; -} - -fz_error * -fz_lineto(fz_pathnode *path, float x, float y) -{ - if (growpath(path, 3) != nil) - return fz_outofmem; - path->els[path->len++].k = FZ_LINETO; - path->els[path->len++].v = x; - path->els[path->len++].v = y; - return fz_okay; -} - -fz_error * -fz_curveto(fz_pathnode *path, - float x1, float y1, - float x2, float y2, - float x3, float y3) -{ - if (growpath(path, 7) != nil) - return fz_outofmem; - path->els[path->len++].k = FZ_CURVETO; - path->els[path->len++].v = x1; - path->els[path->len++].v = y1; - path->els[path->len++].v = x2; - path->els[path->len++].v = y2; - path->els[path->len++].v = x3; - path->els[path->len++].v = y3; - return fz_okay; -} - -fz_error * -fz_curvetov(fz_pathnode *path, float x2, float y2, float x3, float y3) -{ - float x1 = path->els[path->len-2].v; - float y1 = path->els[path->len-1].v; - return fz_curveto(path, x1, y1, x2, y2, x3, y3); -} - -fz_error * -fz_curvetoy(fz_pathnode *path, float x1, float y1, float x3, float y3) -{ - return fz_curveto(path, x1, y1, x3, y3, x3, y3); -} - -fz_error * -fz_closepath(fz_pathnode *path) -{ - if (growpath(path, 1) != nil) - return fz_outofmem; - path->els[path->len++].k = FZ_CLOSEPATH; - return fz_okay; -} - -fz_error * -fz_endpath(fz_pathnode *path, fz_pathkind paint, fz_stroke *stroke, fz_dash *dash) -{ - if (path->len == 0) - fz_warn("creating an empty path"); - - path->paint = paint; - path->dash = dash; - if (stroke) - { - path->linecap = stroke->linecap; - path->linejoin = stroke->linejoin; - path->linewidth = stroke->linewidth; - path->miterlimit = stroke->miterlimit; - } - - if (path->linewidth < 0.01) - path->linewidth = 0.01; - - return fz_okay; -} - -static inline fz_rect boundexpand(fz_rect r, 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_boundpathnode(fz_pathnode *path, fz_matrix ctm) -{ - fz_point p; - fz_rect r = fz_emptyrect; - int i = 0; - - if (path->len) - { - p.x = path->els[1].v; - p.y = path->els[2].v; - p = fz_transformpoint(ctm, p); - r.x0 = r.x1 = p.x; - r.y0 = r.y1 = p.y; - } - - while (i < path->len) - { - switch (path->els[i++].k) - { - case FZ_CURVETO: - p.x = path->els[i++].v; - p.y = path->els[i++].v; - r = boundexpand(r, fz_transformpoint(ctm, p)); - p.x = path->els[i++].v; - p.y = path->els[i++].v; - r = boundexpand(r, fz_transformpoint(ctm, p)); - case FZ_MOVETO: - case FZ_LINETO: - p.x = path->els[i++].v; - p.y = path->els[i++].v; - r = boundexpand(r, fz_transformpoint(ctm, p)); - break; - case FZ_CLOSEPATH: - break; - } - } - - if (path->paint == FZ_STROKE) - { - float miterlength = sin(path->miterlimit / 2.0); - float linewidth = path->linewidth; - float expand = MAX(miterlength, linewidth) / 2.0; - r.x0 -= expand; - r.y0 -= expand; - r.x1 += expand; - r.y1 += expand; - } - - return r; -} - -void -fz_printpathnode(fz_pathnode *path, int indent) -{ - float x, y; - int i = 0; - int n; - while (i < path->len) - { - for (n = 0; n < indent; n++) - putchar(' '); - switch (path->els[i++].k) - { - case FZ_MOVETO: - x = path->els[i++].v; - y = path->els[i++].v; - printf("%g %g m\n", x, y); - break; - case FZ_LINETO: - x = path->els[i++].v; - y = path->els[i++].v; - printf("%g %g l\n", x, y); - break; - case FZ_CURVETO: - x = path->els[i++].v; - y = path->els[i++].v; - printf("%g %g ", x, y); - x = path->els[i++].v; - y = path->els[i++].v; - printf("%g %g ", x, y); - x = path->els[i++].v; - y = path->els[i++].v; - printf("%g %g c\n", x, y); - break; - case FZ_CLOSEPATH: - printf("h\n"); - } - } - - for (n = 0; n < indent; n++) - putchar(' '); - - switch (path->paint) - { - case FZ_STROKE: - printf("S\n"); - break; - case FZ_FILL: - printf("f\n"); - break; - case FZ_EOFILL: - printf("f*\n"); - break; - } -} - -void -fz_debugpathnode(fz_pathnode *path, int indent) -{ - float x, y; - int i = 0; - int n; - while (i < path->len) - { - for (n = 0; n < indent; n++) - putchar(' '); - switch (path->els[i++].k) - { - case FZ_MOVETO: - x = path->els[i++].v; - y = path->els[i++].v; - printf("\n", x, y); - break; - case FZ_LINETO: - x = path->els[i++].v; - y = path->els[i++].v; - printf("\n", x, y); - break; - case FZ_CURVETO: - x = path->els[i++].v; - y = path->els[i++].v; - printf("els[i++].v; - y = path->els[i++].v; - printf("x2=\"%g\" y2=\"%g\" ", x, y); - x = path->els[i++].v; - y = path->els[i++].v; - printf("x3=\"%g\" y3=\"%g\" />\n", x, y); - break; - case FZ_CLOSEPATH: - printf("\n"); - } - } -} - -fz_error * -fz_newdash(fz_dash **dashp, float phase, int len, float *array) -{ - fz_dash *dash; - int i; - - dash = *dashp = fz_malloc(sizeof(fz_dash) + sizeof(float) * len); - if (!dash) - return fz_outofmem; - - dash->len = len; - dash->phase = phase; - for (i = 0; i < len; i++) - dash->array[i] = array[i]; - - return fz_okay; -} - -void -fz_dropdash(fz_dash *dash) -{ - fz_free(dash); -} - diff --git a/world/node_text.c b/world/node_text.c deleted file mode 100644 index 86a523df..00000000 --- a/world/node_text.c +++ /dev/null @@ -1,143 +0,0 @@ -#include "fitz-base.h" -#include "fitz-world.h" - -fz_error * -fz_newtextnode(fz_textnode **textp, fz_font *font) -{ - fz_textnode *text; - - text = fz_malloc(sizeof(fz_textnode)); - if (!text) - return fz_outofmem; - - fz_initnode((fz_node*)text, FZ_NTEXT); - - text->font = fz_keepfont(font); - text->trm = fz_identity(); - text->len = 0; - text->cap = 0; - text->els = nil; - - *textp = text; - return fz_okay; -} - -fz_error * -fz_clonetextnode(fz_textnode **textp, fz_textnode *oldtext) -{ - fz_textnode *text; - - text = *textp = fz_malloc(sizeof(fz_textnode)); - if (!text) - return fz_outofmem; - - fz_initnode((fz_node*)text, FZ_NTEXT); - - text->font = fz_keepfont(oldtext->font); - text->trm = oldtext->trm; - text->len = oldtext->len; - text->cap = oldtext->len; - text->els = nil; - - text->els = fz_malloc(sizeof(fz_textel) * text->len); - if (!text->els) - { - fz_dropfont(text->font); - fz_free(text); - return fz_outofmem; - } - - memcpy(text->els, oldtext->els, sizeof(fz_textel) * text->len); - - *textp = text; - return fz_okay; -} - -void -fz_droptextnode(fz_textnode *text) -{ - fz_dropfont(text->font); - fz_free(text->els); -} - -fz_rect -fz_boundtextnode(fz_textnode *text, fz_matrix ctm) -{ - fz_matrix trm; - fz_rect bbox; - fz_rect fbox; - int i; - - if (text->len == 0) - return fz_emptyrect; - - /* find bbox of glyph origins in ctm space */ - - bbox.x0 = bbox.x1 = text->els[0].x; - bbox.y0 = bbox.y1 = text->els[0].y; - - for (i = 1; i < text->len; i++) - { - bbox.x0 = MIN(bbox.x0, text->els[i].x); - bbox.y0 = MIN(bbox.y0, text->els[i].y); - bbox.x1 = MAX(bbox.x1, text->els[i].x); - bbox.y1 = MAX(bbox.y1, text->els[i].y); - } - - bbox = fz_transformaabb(ctm, bbox); - - /* find bbox of font in trm * ctm space */ - - trm = fz_concat(text->trm, ctm); - trm.e = 0; - trm.f = 0; - - fbox.x0 = text->font->bbox.x0 * 0.001; - fbox.y0 = text->font->bbox.y0 * 0.001; - fbox.x1 = text->font->bbox.x1 * 0.001; - fbox.y1 = text->font->bbox.y1 * 0.001; - - fbox = fz_transformaabb(trm, fbox); - - /* expand glyph origin bbox by font bbox */ - - bbox.x0 += fbox.x0; - bbox.y0 += fbox.y0; - bbox.x1 += fbox.x1; - bbox.y1 += fbox.y1; - - return bbox; -} - -static fz_error * -growtext(fz_textnode *text, int n) -{ - int newcap; - fz_textel *newels; - - while (text->len + n > text->cap) - { - newcap = text->cap + 36; - newels = fz_realloc(text->els, sizeof (fz_textel) * newcap); - if (!newels) - return fz_outofmem; - text->cap = newcap; - text->els = newels; - } - - return fz_okay; -} - -fz_error * -fz_addtext(fz_textnode *text, int gid, int ucs, float x, float y) -{ - if (growtext(text, 1) != nil) - return fz_outofmem; - text->els[text->len].ucs = ucs; - text->els[text->len].gid = gid; - text->els[text->len].x = x; - text->els[text->len].y = y; - text->len++; - return fz_okay; -} - diff --git a/world/node_tolisp.c b/world/node_tolisp.c deleted file mode 100644 index 364d2862..00000000 --- a/world/node_tolisp.c +++ /dev/null @@ -1,192 +0,0 @@ -#include "fitz-base.h" -#include "fitz-world.h" - -static void indent(int level) -{ - while (level--) - putchar(' '); -} - -static void lispnode(fz_node *node, int level); - -static void lispmeta(fz_metanode *node, int level) -{ - fz_node *child; - indent(level); - printf("(meta "); - if (node->name) { fz_debugobj(node->name); } - if (node->dict) { printf("\n"); fz_debugobj(node->dict); } - printf("\n"); - for (child = node->super.first; child; child = child->next) - lispnode(child, level + 1); - indent(level); - printf(")\n"); -} - -static void lispover(fz_overnode *node, int level) -{ - fz_node *child; - indent(level); - printf("(over\n"); - for (child = node->super.first; child; child = child->next) - lispnode(child, level + 1); - indent(level); - printf(")\n"); -} - -static void lispmask(fz_masknode *node, int level) -{ - fz_node *child; - indent(level); - printf("(mask\n"); - for (child = node->super.first; child; child = child->next) - lispnode(child, level + 1); - indent(level); - printf(")\n"); -} - -static void lispblend(fz_blendnode *node, int level) -{ - fz_node *child; - indent(level); - printf("(blend-%d %d\n", node->mode, node->cs->refs); - for (child = node->super.first; child; child = child->next) - lispnode(child, level + 1); - indent(level); - printf(")\n"); -} - -static void lisptransform(fz_transformnode *node, int level) -{ - indent(level); - printf("(transform %g %g %g %g %g %g\n", - node->m.a, node->m.b, - node->m.c, node->m.d, - node->m.e, node->m.f); - lispnode(node->super.first, level + 1); - indent(level); - printf(")\n"); -} - -static void lispcolor(fz_colornode *node, int level) -{ - int i; - indent(level); - printf("(color %s ", node->cs->name); - for (i = 0; i < node->n; i++) - printf("%g ", node->samples[i]); - printf(" %d)\n", node->cs->refs); -} - -static void lisplink(fz_linknode *node, int level) -{ - indent(level); - printf("(link %p %d)\n", node->tree, node->tree->refs); -} - -static void lisppath(fz_pathnode *node, int level) -{ - int i; - - indent(level); - - if (node->paint == FZ_STROKE) - { - printf("(path 'stroke %d %d %g %g ", - node->linecap, - node->linejoin, - node->linewidth, - node->miterlimit); - if (node->dash) - { - printf("%g '( ", node->dash->phase); - for (i = 0; i < node->dash->len; i++) - printf("%g ", node->dash->array[i]); - printf(")"); - } - else - printf("0 '()"); - } - else - { - printf("(path '%s", node->paint == FZ_FILL ? "fill" : "eofill"); - } - - printf("\n"); - fz_debugpathnode(node); - - indent(level); - printf(")\n"); -} - -static void lisptext(fz_textnode *node, int level) -{ - int i; - - indent(level); - printf("(text %s [%g %g %g %g]\n", node->font->name, - node->trm.a, node->trm.b, node->trm.c, node->trm.d); - - for (i = 0; i < node->len; i++) - { - indent(level + 1); - if (node->els[i].cid >= 32 && node->els[i].cid < 128) - printf("(cid '%c' %g %g)\n", node->els[i].cid, node->els[i].x, node->els[i].y); - else - printf("(cid <%04x> %g %g)\n", node->els[i].cid, node->els[i].x, node->els[i].y); - } - - indent(level); - printf(")\n"); -} - -static void lispimage(fz_imagenode *node, int level) -{ - fz_image *image = node->image; - indent(level); - printf("(image %dx%d %d+%d %d)\n", image->w, image->h, image->n, image->a, image->refs); -} - -static void lispshade(fz_shadenode *node, int level) -{ - indent(level); - printf("(shade %d)\n", node->shade->refs); -} - -static void lispnode(fz_node *node, int level) -{ - if (!node) - { - indent(level); - printf("(nil)\n"); - return; - } - - switch (node->kind) - { - case FZ_NMETA: lispmeta((fz_metanode*)node, level); break; - case FZ_NOVER: lispover((fz_overnode*)node, level); break; - case FZ_NMASK: lispmask((fz_masknode*)node, level); break; - case FZ_NBLEND: lispblend((fz_blendnode*)node, level); break; - case FZ_NTRANSFORM: lisptransform((fz_transformnode*)node, level); break; - case FZ_NCOLOR: lispcolor((fz_colornode*)node, level); break; - case FZ_NPATH: lisppath((fz_pathnode*)node, level); break; - case FZ_NTEXT: lisptext((fz_textnode*)node, level); break; - case FZ_NIMAGE: lispimage((fz_imagenode*)node, level); break; - case FZ_NSHADE: lispshade((fz_shadenode*)node, level); break; - case FZ_NLINK: lisplink((fz_linknode*)node, level); break; - } -} - -void -fz_debugnode(fz_node *node) -{ - lispnode(node, 0); -} - -void -fz_debugtree(fz_tree *tree) -{ - lispnode(tree->root, 0); -} - diff --git a/world/node_toxml.c b/world/node_toxml.c deleted file mode 100644 index cc87c997..00000000 --- a/world/node_toxml.c +++ /dev/null @@ -1,185 +0,0 @@ -#include "fitz-base.h" -#include "fitz-world.h" - -static void indent(int level) -{ - while (level--) - putchar(' '); -} - -static void xmlnode(fz_node *node, int level); - -static void xmlover(fz_overnode *node, int level) -{ - fz_node *child; - indent(level); - printf("\n"); - for (child = node->super.first; child; child = child->next) - xmlnode(child, level + 1); - indent(level); - printf("\n"); -} - -static void xmlmask(fz_masknode *node, int level) -{ - fz_node *child; - indent(level); - printf("\n"); - for (child = node->super.first; child; child = child->next) - xmlnode(child, level + 1); - indent(level); - printf("\n"); -} - -static void xmlblend(fz_blendnode *node, int level) -{ - fz_node *child; - indent(level); - printf("\n", node->mode); - for (child = node->super.first; child; child = child->next) - xmlnode(child, level + 1); - indent(level); - printf("\n"); -} - -static void xmltransform(fz_transformnode *node, int level) -{ - indent(level); - printf("\n", - node->m.a, node->m.b, - node->m.c, node->m.d, - node->m.e, node->m.f); - xmlnode(node->super.first, level + 1); - indent(level); - printf("\n"); -} - -static void xmlsolid(fz_solidnode *node, int level) -{ - int i; - indent(level); - printf("cs->name, node->a); - for (i = 0; i < node->n; i++) - { - printf("%g", node->samples[i]); - if (i < node->n - 1) - putchar(' '); - } - printf("\" />\n"); -} - -static void xmllink(fz_linknode *node, int level) -{ - indent(level); - printf("\n", node->tree); -} - -static void xmlpath(fz_pathnode *node, int level) -{ - int i; - - indent(level); - - if (node->paint == FZ_STROKE) - { - printf("linecap, - node->linejoin, - node->linewidth, - node->miterlimit); - if (node->dash) - { - printf(" phase=\"%g\" array=\"", node->dash->phase); - for (i = 0; i < node->dash->len; i++) - printf("%g ", node->dash->array[i]); - printf("\""); - } - printf(">\n"); - } - else - { - printf("\n", - node->paint == FZ_FILL ? "nonzero" : "evenodd"); - } - - fz_debugpathnode(node, level + 2); - - indent(level); - printf("\n"); -} - -static void xmltext(fz_textnode *node, int level) -{ - int i; - - indent(level); - printf("\n", node->font->name, - node->trm.a, node->trm.b, node->trm.c, node->trm.d); - - for (i = 0; i < node->len; i++) - { - indent(level + 1); - if (node->els[i].ucs >= 32 && node->els[i].ucs < 128) - printf("\n", - node->els[i].ucs, node->els[i].gid, node->els[i].x, node->els[i].y); - else - printf("\n", - node->els[i].ucs, node->els[i].gid, node->els[i].x, node->els[i].y); - } - - indent(level); - printf("\n"); -} - -static void xmlimage(fz_imagenode *node, int level) -{ - fz_image *image = node->image; - indent(level); - printf("\n", - image->w, image->h, image->n, image->a); -} - -static void xmlshade(fz_shadenode *node, int level) -{ - indent(level); - printf("\n"); -} - -static void xmlnode(fz_node *node, int level) -{ - if (!node) - { - indent(level); - printf("\n"); - return; - } - - switch (node->kind) - { - case FZ_NOVER: xmlover((fz_overnode*)node, level); break; - case FZ_NMASK: xmlmask((fz_masknode*)node, level); break; - case FZ_NBLEND: xmlblend((fz_blendnode*)node, level); break; - case FZ_NTRANSFORM: xmltransform((fz_transformnode*)node, level); break; - case FZ_NCOLOR: xmlsolid((fz_solidnode*)node, level); break; - case FZ_NPATH: xmlpath((fz_pathnode*)node, level); break; - case FZ_NTEXT: xmltext((fz_textnode*)node, level); break; - case FZ_NIMAGE: xmlimage((fz_imagenode*)node, level); break; - case FZ_NSHADE: xmlshade((fz_shadenode*)node, level); break; - case FZ_NLINK: xmllink((fz_linknode*)node, level); break; - } -} - -void -fz_debugnode(fz_node *node) -{ - xmlnode(node, 0); -} - -void -fz_debugtree(fz_tree *tree) -{ - printf("\n"); - xmlnode(tree->root, 1); - printf("\n"); -} - diff --git a/world/node_tree.c b/world/node_tree.c deleted file mode 100644 index f5698bc1..00000000 --- a/world/node_tree.c +++ /dev/null @@ -1,108 +0,0 @@ -#include "fitz-base.h" -#include "fitz-world.h" - -fz_error * -fz_newtree(fz_tree **treep) -{ - fz_tree *tree; - - tree = *treep = fz_malloc(sizeof (fz_tree)); - if (!tree) - return fz_outofmem; - - tree->refs = 1; - tree->root = nil; - tree->head = nil; - - return fz_okay; -} - -fz_tree * -fz_keeptree(fz_tree *tree) -{ - tree->refs ++; - return tree; -} - -void -fz_droptree(fz_tree *tree) -{ - if (--tree->refs == 0) - { - if (tree->root) - fz_dropnode(tree->root); - fz_free(tree); - } -} - -fz_rect -fz_boundtree(fz_tree *tree, fz_matrix ctm) -{ - if (tree->root) - return fz_boundnode(tree->root, ctm); - return fz_emptyrect; -} - -void -fz_insertnodefirst(fz_node *parent, fz_node *child) -{ - child->parent = parent; - child->next = parent->first; - parent->first = child; - if (!parent->last) - parent->last = child; -} - -void -fz_insertnodelast(fz_node *parent, fz_node *child) -{ - child->parent = parent; - if (!parent->first) - parent->first = child; - else - parent->last->next = child; - parent->last = child; -} - -void -fz_insertnodeafter(fz_node *prev, fz_node *child) -{ - fz_node *parent = prev->parent; - child->parent = parent; - if (parent->last == prev) - parent->last = child; - child->next = prev->next; - prev->next = child; -} - -void -fz_removenode(fz_node *child) -{ - fz_node *parent = child->parent; - fz_node *prev; - fz_node *node; - - if (parent->first == child) - { - parent->first = child->next; - if (parent->last == child) - parent->last = nil; - return; - } - - prev = parent->first; - node = prev->next; - - while (node) - { - if (node == child) - { - prev->next = child->next; - } - prev = node; - node = node->next; - } - - parent->last = prev; -} - diff --git a/world/res_colorspace.c b/world/res_colorspace.c deleted file mode 100644 index 04fc532e..00000000 --- a/world/res_colorspace.c +++ /dev/null @@ -1,88 +0,0 @@ -#include "fitz-base.h" -#include "fitz-world.h" - -void -fz_convertpixmap(fz_colorspace *srcs, fz_pixmap *src, fz_colorspace *dsts, fz_pixmap *dst) -{ - srcs->convpixmap(srcs, src, dsts, dst); -} - -void -fz_convertcolor(fz_colorspace *srcs, float *srcv, fz_colorspace *dsts, float *dstv) -{ - srcs->convcolor(srcs, srcv, dsts, dstv); -} - -fz_colorspace * -fz_keepcolorspace(fz_colorspace *cs) -{ - if (cs->refs < 0) - return cs; - cs->refs ++; - return cs; -} - -void -fz_dropcolorspace(fz_colorspace *cs) -{ - if (cs && cs->refs < 0) - return; - if (cs && --cs->refs == 0) - { - if (cs->drop) - cs->drop(cs); - fz_free(cs); - } -} - -void -fz_stdconvcolor(fz_colorspace *srcs, float *srcv, fz_colorspace *dsts, float *dstv) -{ - float xyz[3]; - int i; - - if (srcs != dsts) - { - srcs->toxyz(srcs, srcv, xyz); - dsts->fromxyz(dsts, xyz, dstv); - for (i = 0; i < dsts->n; i++) - dstv[i] = CLAMP(dstv[i], 0.0, 1.0); - } - else - { - for (i = 0; i < srcs->n; i++) - dstv[i] = srcv[i]; - } -} - -void -fz_stdconvpixmap(fz_colorspace *srcs, fz_pixmap *src, fz_colorspace *dsts, fz_pixmap *dst) -{ - float srcv[FZ_MAXCOLORS]; - float dstv[FZ_MAXCOLORS]; - int y, x, k; - - unsigned char *s = src->samples; - unsigned char *d = dst->samples; - - assert(src->w == dst->w && src->h == dst->h); - assert(src->n == srcs->n + 1); - assert(dst->n == dsts->n + 1); - - for (y = 0; y < src->h; y++) - { - for (x = 0; x < src->w; x++) - { - *d++ = *s++; - - for (k = 0; k < src->n - 1; k++) - srcv[k] = *s++ / 255.0; - - fz_convertcolor(srcs, srcv, dsts, dstv); - - for (k = 0; k < dst->n - 1; k++) - *d++ = dstv[k] * 255; - } - } -} - diff --git a/world/res_font.c b/world/res_font.c deleted file mode 100644 index 7238cc3c..00000000 --- a/world/res_font.c +++ /dev/null @@ -1,408 +0,0 @@ -#include "fitz-base.h" -#include "fitz-world.h" -#include "fitz-draw.h" /* for type3 font rendering */ - -#include -#include FT_FREETYPE_H - -static fz_font * -fz_newfont(void) -{ - fz_font *font; - - font = fz_malloc(sizeof(fz_font)); - if (!font) - return nil; - - font->refs = 1; - strcpy(font->name, ""); - - font->ftface = nil; - font->ftsubstitute = 0; - font->fthint = 0; - - font->t3matrix = fz_identity(); - font->t3procs = nil; - - font->bbox.x0 = 0; - font->bbox.y0 = 0; - font->bbox.x1 = 1000; - font->bbox.y1 = 1000; - - return font; -} - -fz_font * -fz_keepfont(fz_font *font) -{ - font->refs ++; - return font; -} - -void -fz_dropfont(fz_font *font) -{ - int i; - - if (font && --font->refs == 0) - { - if (font->t3procs) - { - for (i = 0; i < 256; i++) - if (font->t3procs[i]) - fz_droptree(font->t3procs[i]); - fz_free(font->t3procs); - } - - if (font->ftface) - { - FT_Done_Face((FT_Face)font->ftface); - } - - fz_free(font); - } -} - -void -fz_setfontbbox(fz_font *font, int xmin, int ymin, int xmax, int ymax) -{ - font->bbox.x0 = xmin; - font->bbox.y0 = ymin; - font->bbox.x1 = xmax; - font->bbox.y1 = ymax; -} - -/* - * Freetype hooks - */ - -static FT_Library fz_ftlib = nil; - -#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; -}; - -const struct ft_error ft_errors[] = -{ -#include FT_ERRORS_H -}; - -char *ft_errorstring(int err) -{ - const struct ft_error *e; - - for (e = ft_errors; e->str != NULL; e++) - if (e->err == err) - return e->str; - - return "Unknown error"; -} - -static fz_error * -fz_initfreetype(void) -{ - int code; - int maj, min, pat; - - if (fz_ftlib) - return fz_okay; - - code = FT_Init_FreeType(&fz_ftlib); - if (code) - return fz_throw("cannot init freetype: %s", ft_errorstring(code)); - - FT_Library_Version(fz_ftlib, &maj, &min, &pat); - if (maj == 2 && min == 1 && pat < 7) - return fz_throw("freetype version too old: %d.%d.%d", maj, min, pat); - - return fz_okay; -} - -fz_error * -fz_newfontfromfile(fz_font **fontp, char *path, int index) -{ - fz_error *error; - fz_font *font; - int code; - - error = fz_initfreetype(); - if (error) - return fz_rethrow(error, "cannot init freetype library"); - - font = fz_newfont(); - if (!font) - return fz_throw("outofmem: font struct"); - - code = FT_New_Face(fz_ftlib, path, index, (FT_Face*)&font->ftface); - if (code) - { - fz_free(font); - return fz_throw("freetype: cannot load font: %s", ft_errorstring(code)); - } - - *fontp = font; - return fz_okay; -} - -fz_error * -fz_newfontfrombuffer(fz_font **fontp, unsigned char *data, int len, int index) -{ - fz_error *error; - fz_font *font; - int code; - - error = fz_initfreetype(); - if (error) - return fz_rethrow(error, "cannot init freetype library"); - - font = fz_newfont(); - if (!font) - return fz_throw("outofmem: font struct"); - - code = FT_New_Memory_Face(fz_ftlib, data, len, index, (FT_Face*)&font->ftface); - if (code) - { - fz_free(font); - return fz_throw("freetype: cannot load font: %s", ft_errorstring(code)); - } - - *fontp = font; - return fz_okay; -} - -fz_error * -fz_renderftglyph(fz_glyph *glyph, fz_font *font, int gid, fz_matrix trm) -{ - FT_Face face = font->ftface; - FT_Matrix m; - FT_Vector v; - FT_Error fterr; - int x, y; - -#if 0 - /* We lost this feature in refactoring. - * We can't access pdf_fontdesc metrics from fz_font. - * The pdf_fontdesc metrics are character based (cid), - * where the glyph being rendered is given by glyph (gid). - */ - if (font->ftsubstitute && font->wmode == 0) - { - fz_hmtx subw; - int realw; - float scale; - - FT_Set_Char_Size(face, 1000, 1000, 72, 72); - - fterr = FT_Load_Glyph(font->ftface, gid, - FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP | FT_LOAD_IGNORE_TRANSFORM); - if (fterr) - return fz_throw("freetype failed to load glyph: %s", ft_errorstring(fterr)); - - realw = ((FT_Face)font->ftface)->glyph->advance.x; - subw = fz_gethmtx(font, cid); // <-- this is the offender - if (realw) - scale = (float) subw.w / realw; - else - scale = 1.0; - - trm = fz_concat(fz_scale(scale, 1.0), trm); - } -#endif - - glyph->w = 0; - glyph->h = 0; - glyph->x = 0; - glyph->y = 0; - glyph->samples = nil; - - /* 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 = trm.a * 64; /* should be 65536 */ - m.yx = trm.b * 64; - m.xy = trm.c * 64; - m.yy = trm.d * 64; - v.x = trm.e * 64; - v.y = trm.f * 64; - - FT_Set_Char_Size(face, 65536, 65536, 72, 72); /* should be 64, 64 */ - FT_Set_Transform(face, &m, &v); - - if (font->fthint) - { - /* 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. - */ -#ifdef USE_HINTING - /* If you really want grid fitting, enable this code. */ - float scale = fz_matrixexpansion(trm); - m.xx = trm.a * 65536 / scale; - m.xy = trm.b * 65536 / scale; - m.yx = trm.c * 65536 / scale; - m.yy = trm.d * 65536 / scale; - v.x = 0; - v.y = 0; - FT_Set_Char_Size(face, 64 * scale, 64 * scale, 72, 72); - FT_Set_Transform(face, &m, &v); -#endif - fterr = FT_Load_Glyph(face, gid, FT_LOAD_NO_BITMAP); - if (fterr) - fz_warn("freetype load glyph: %s", ft_errorstring(fterr)); - } - else - { - fterr = FT_Load_Glyph(face, gid, FT_LOAD_NO_BITMAP | FT_LOAD_NO_HINTING); - if (fterr) - fz_warn("freetype load glyph: %s", ft_errorstring(fterr)); - } - - fterr = FT_Render_Glyph(face->glyph, ft_render_mode_normal); - if (fterr) - fz_warn("freetype render glyph: %s", ft_errorstring(fterr)); - - glyph->w = face->glyph->bitmap.width; - glyph->h = face->glyph->bitmap.rows; - glyph->x = face->glyph->bitmap_left; - glyph->y = face->glyph->bitmap_top - glyph->h; - glyph->samples = face->glyph->bitmap.buffer; - - for (y = 0; y < glyph->h / 2; y++) - { - for (x = 0; x < glyph->w; x++) - { - unsigned char a = glyph->samples[y * glyph->w + x ]; - unsigned char b = glyph->samples[(glyph->h - y - 1) * glyph->w + x]; - glyph->samples[y * glyph->w + x ] = b; - glyph->samples[(glyph->h - y - 1) * glyph->w + x] = a; - } - } - - return fz_okay; -} - - -/* - * Type 3 fonts... - */ - -fz_error * -fz_newtype3font(fz_font **fontp, char *name, fz_matrix matrix, void **procs0) -{ - fz_font *font; - fz_tree **procs = (fz_tree**)procs0; - int i; - - font = fz_newfont(); - if (!font) - return fz_throw("outofmem: font struct"); - - font->t3procs = fz_malloc(sizeof(fz_tree*) * 256); - if (!font->t3procs) - { - fz_free(font); - return fz_throw("outofmem: type3 font charproc array"); - } - - font->t3matrix = matrix; - for (i = 0; i < 256; i++) - font->t3procs[i] = procs[i]; - - strlcpy(font->name, name, sizeof(font->name)); - - *fontp = font; - return fz_okay; -} - -fz_error * -fz_rendert3glyph(fz_glyph *glyph, fz_font *font, int gid, fz_matrix trm) -{ - fz_error *error; - fz_renderer *gc; - fz_tree *tree; - fz_matrix ctm; - fz_irect bbox; - - /* TODO: make it reentrant */ - static fz_pixmap *pixmap = nil; - if (pixmap) - { - fz_droppixmap(pixmap); - pixmap = nil; - } - - if (gid < 0 || gid > 255) - return fz_throw("assert: glyph out of range"); - - tree = font->t3procs[gid]; - if (!tree) - { - glyph->w = 0; - glyph->h = 0; - return fz_okay; - } - - /* XXX UGLY HACK XXX */ - extern fz_colorspace *pdf_devicegray; - - ctm = fz_concat(font->t3matrix, trm); - bbox = fz_roundrect(fz_boundtree(tree, ctm)); - - error = fz_newrenderer(&gc, pdf_devicegray, 1, 4096); - if (error) - return fz_rethrow(error, "cannot create renderer"); - error = fz_rendertree(&pixmap, gc, tree, ctm, bbox, 0); - fz_droprenderer(gc); - if (error) - return fz_rethrow(error, "cannot render glyph"); - - assert(pixmap->n == 1); - - glyph->x = pixmap->x; - glyph->y = pixmap->y; - glyph->w = pixmap->w; - glyph->h = pixmap->h; - glyph->samples = pixmap->samples; - - return fz_okay; -} - -void -fz_debugfont(fz_font *font) -{ - printf("font '%s' {\n", font->name); - - if (font->ftface) - { - printf(" freetype face %p\n", font->ftface); - if (font->ftsubstitute) - printf(" substitute font\n"); - } - - if (font->t3procs) - { - printf(" type3 matrix [%g %g %g %g]\n", - font->t3matrix.a, font->t3matrix.b, - font->t3matrix.c, font->t3matrix.d); - } - - printf(" bbox [%d %d %d %d]\n", - font->bbox.x0, font->bbox.y0, - font->bbox.x1, font->bbox.y1); - - printf("}\n"); -} - diff --git a/world/res_image.c b/world/res_image.c deleted file mode 100644 index 4379cf17..00000000 --- a/world/res_image.c +++ /dev/null @@ -1,23 +0,0 @@ -#include "fitz-base.h" -#include "fitz-world.h" - -fz_image * -fz_keepimage(fz_image *image) -{ - image->refs ++; - return image; -} - -void -fz_dropimage(fz_image *image) -{ - if (image && --image->refs == 0) - { - if (image->drop) - image->drop(image); - if (image->cs) - fz_dropcolorspace(image->cs); - fz_free(image); - } -} - diff --git a/world/res_shade.c b/world/res_shade.c deleted file mode 100644 index d1bd991e..00000000 --- a/world/res_shade.c +++ /dev/null @@ -1,29 +0,0 @@ -#include "fitz-base.h" -#include "fitz-world.h" - -fz_shade * -fz_keepshade(fz_shade *shade) -{ - shade->refs ++; - return shade; -} - -void -fz_dropshade(fz_shade *shade) -{ - if (shade && --shade->refs == 0) - { - if (shade->cs) - fz_dropcolorspace(shade->cs); - fz_free(shade->mesh); - fz_free(shade); - } -} - -fz_rect -fz_boundshade(fz_shade *shade, fz_matrix ctm) -{ - ctm = fz_concat(shade->matrix, ctm); - return fz_transformaabb(ctm, shade->bbox); -} - -- cgit v1.2.3