From 9a36550815c3d874ce62650bf06ee85a3f705f1c Mon Sep 17 00:00:00 2001 From: Tor Andersson Date: Mon, 29 Nov 2004 16:15:08 +0100 Subject: shift things about a bit --- Jamfile | 25 +- TODO | 5 +- base/cpudep.c | 6 + filter/dctd.c | 4 + include/fitz.h | 2 +- include/fitz/cpudep.h | 4 + include/fitz/pathscan.h | 46 +++ include/fitz/render.h | 81 +++--- include/fitz/scanconv.h | 48 ---- mupdf/colorspace1.c | 5 +- mupdf/image.c | 412 +++++++++++++++++++++++++++ mupdf/image1.c | 340 ----------------------- mupdf/image2.c | 255 ----------------- mupdf/resources.c | 2 + render/archppc.c | 65 +++++ render/archsparc.c | 21 ++ render/archx86.c | 226 +++++++++++++++ render/edgelist.c | 300 -------------------- render/fill.c | 132 --------- render/optduff.c | 324 ++++++++++++++++++++++ render/optimage.c | 238 ++++++++++++++++ render/optscale.c | 191 +++++++++++++ render/optunpack.c | 183 ++++++++++++ render/pathfill.c | 132 +++++++++ render/pathscan.c | 454 ++++++++++++++++++++++++++++++ render/pathstroke.c | 725 ++++++++++++++++++++++++++++++++++++++++++++++++ render/rastport.c | 570 ------------------------------------- render/rastppc.c | 23 -- render/rastsparc.c | 21 -- render/rastx86.c | 225 --------------- render/render.c | 60 ++-- render/scale.c | 225 --------------- render/scanconv.c | 152 ---------- render/stroke.c | 725 ------------------------------------------------ test/pdfrip.c | 3 + test/x11pdf.c | 3 + test/ximage.c | 4 +- tree/optimize.c | 8 + 38 files changed, 3138 insertions(+), 3107 deletions(-) create mode 100644 include/fitz/pathscan.h delete mode 100644 include/fitz/scanconv.h create mode 100644 mupdf/image.c delete mode 100644 mupdf/image1.c delete mode 100644 mupdf/image2.c create mode 100644 render/archppc.c create mode 100644 render/archsparc.c create mode 100644 render/archx86.c delete mode 100644 render/edgelist.c delete mode 100644 render/fill.c create mode 100644 render/optduff.c create mode 100644 render/optimage.c create mode 100644 render/optscale.c create mode 100644 render/optunpack.c create mode 100644 render/pathfill.c create mode 100644 render/pathscan.c create mode 100644 render/pathstroke.c delete mode 100644 render/rastport.c delete mode 100644 render/rastppc.c delete mode 100644 render/rastsparc.c delete mode 100644 render/rastx86.c delete mode 100644 render/scale.c delete mode 100644 render/scanconv.c delete mode 100644 render/stroke.c diff --git a/Jamfile b/Jamfile index 6357a47d..3745d795 100644 --- a/Jamfile +++ b/Jamfile @@ -86,17 +86,19 @@ Library libfitz : # render render/glyphcache.c render/pixmap.c - render/edgelist.c - render/scanconv.c - render/fill.c - render/stroke.c - render/scale.c render/rastshade.c - render/rastport.c - render/rastppc.c - render/rastsparc.c - render/rastx86.c + render/pathscan.c + render/pathfill.c + render/pathstroke.c + render/optduff.c + render/optimage.c + render/optunpack.c + render/optscale.c render/render.c + + render/archppc.c + render/archsparc.c + render/archx86.c ; Library libmupdf : @@ -120,13 +122,14 @@ Library libmupdf : mupdf/fontagl.c mupdf/fontenc.c mupdf/fontfile.c +# mupdf/fontfilefc.c +# mupdf/fontfilems.c mupdf/unicode.c mupdf/font.c mupdf/type3.c mupdf/colorspace1.c mupdf/colorspace2.c - mupdf/image1.c - mupdf/image2.c + mupdf/image.c mupdf/xobject.c mupdf/pattern.c mupdf/shade.c diff --git a/TODO b/TODO index 85462d64..7e845aac 100644 --- a/TODO +++ b/TODO @@ -28,16 +28,19 @@ shadings - ... jeong ... rendering + - fix glyphcache evictlast - bbox culling per glyph - optimize image load/decode/scale - cpu-specific optims + - font focus parser + - image color key transparency + - rewrite 1x1 images as fillrect - try to clean up colorspace/material handling in interpreter - annotations and destinations (for links and outline) fz_optimizetree() - - remove white fills at beginning of page - concatenate chained transforms - remove identity transforms diff --git a/base/cpudep.c b/base/cpudep.c index c7af38b9..d4bd1a6c 100644 --- a/base/cpudep.c +++ b/base/cpudep.c @@ -7,6 +7,12 @@ Glenn Kennard #include +#ifdef WIN32 +#define sigjmp_buf jmp_buf +#define sigsetjmp setjmp +#define siglongjmp longjmp +#endif + typedef struct { void (*test)(void); const unsigned flag; diff --git a/filter/dctd.c b/filter/dctd.c index 0c0b072e..750f7893 100644 --- a/filter/dctd.c +++ b/filter/dctd.c @@ -91,6 +91,10 @@ fz_newdctd(fz_filter **fp, fz_obj *params) 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 nil; } diff --git a/include/fitz.h b/include/fitz.h index 8c38652f..4c9756a0 100644 --- a/include/fitz.h +++ b/include/fitz.h @@ -29,6 +29,6 @@ #include "fitz/path.h" #include "fitz/text.h" -#include "fitz/scanconv.h" +#include "fitz/pathscan.h" #include "fitz/render.h" diff --git a/include/fitz/cpudep.h b/include/fitz/cpudep.h index 261c3c79..fc07393d 100644 --- a/include/fitz/cpudep.h +++ b/include/fitz/cpudep.h @@ -21,6 +21,10 @@ /* call this before using fitz */ extern void fz_cpudetect(); +#ifndef HAVE_CPUDEP +#define fz_accelerate() +#endif + /* treat as constant! */ extern unsigned fz_cpuflags; diff --git a/include/fitz/pathscan.h b/include/fitz/pathscan.h new file mode 100644 index 00000000..109d16b6 --- /dev/null +++ b/include/fitz/pathscan.h @@ -0,0 +1,46 @@ +typedef struct fz_edge_s fz_edge; +typedef struct fz_gel_s fz_gel; +typedef struct fz_ael_s fz_ael; + +struct fz_edge_s +{ + int x, e, h, y; + int adjup, adjdown; + int xmove; + int xdir, ydir; /* -1 or +1 */ +}; + +struct fz_gel_s +{ + int hs, vs; + int xmin, xmax; + int ymin, ymax; + int cap; + int len; + fz_edge *edges; +}; + +struct fz_ael_s +{ + int cap; + int len; + fz_edge **edges; +}; + +fz_error *fz_newgel(fz_gel **gelp); +fz_error *fz_insertgel(fz_gel *gel, float x0, float y0, float x1, float y1); +fz_irect fz_boundgel(fz_gel *gel); +void fz_resetgel(fz_gel *gel, int hs, int vs); +void fz_sortgel(fz_gel *gel); +void fz_dropgel(fz_gel *gel); + +fz_error *fz_newael(fz_ael **aelp); +void fz_dropael(fz_ael *ael); + +fz_error *fz_scanconvert(fz_gel *gel, fz_ael *ael, int eofill, int y0, int y1, + void (*blitfunc)(int,int,int,unsigned char*,void*), void *blitdata); + +fz_error *fz_fillpath(fz_gel *gel, fz_pathnode *path, fz_matrix ctm, float flatness); +fz_error *fz_strokepath(fz_gel *gel, fz_pathnode *path, fz_matrix ctm, float flatness); +fz_error *fz_dashpath(fz_gel *gel, fz_pathnode *path, fz_matrix ctm, float flatness); + diff --git a/include/fitz/render.h b/include/fitz/render.h index d951b3da..5c2c7a67 100644 --- a/include/fitz/render.h +++ b/include/fitz/render.h @@ -1,9 +1,7 @@ typedef struct fz_renderer_s fz_renderer; -typedef struct fz_rastfuncs_s fz_rastfuncs; #define FZ_BYTE unsigned char -/* TODO: use 'restrict' on pointers - they never alias, do they? */ #define FZ_PSRC \ unsigned char *src, int srcw, int srch #define FZ_PDST \ @@ -11,33 +9,52 @@ typedef struct fz_rastfuncs_s fz_rastfuncs; #define FZ_PCTM \ int u0, int v0, int fa, int fb, int fc, int fd, int w0, int h -struct fz_rastfuncs_s -{ - void (*duff_NoN)(FZ_BYTE*,int,int,FZ_BYTE*,int,int,int); - void (*duff_NiMcN)(FZ_BYTE*,int,int,FZ_BYTE*,int,int,FZ_BYTE*,int,int,int); - void (*duff_NiMoN)(FZ_BYTE*,int,int,FZ_BYTE*,int,int,FZ_BYTE*,int,int,int); - void (*duff_1o1)(FZ_BYTE*,int,FZ_BYTE*,int,int,int); - void (*duff_4o4)(FZ_BYTE*,int,FZ_BYTE*,int,int,int); - void (*duff_1i1c1)(FZ_BYTE*,int,FZ_BYTE*,int,FZ_BYTE*,int,int,int); - void (*duff_4i1c4)(FZ_BYTE*,int,FZ_BYTE*,int,FZ_BYTE*,int,int,int); - void (*duff_1i1o1)(FZ_BYTE*,int,FZ_BYTE*,int,FZ_BYTE*,int,int,int); - void (*duff_4i1o4)(FZ_BYTE*,int,FZ_BYTE*,int,FZ_BYTE*,int,int,int); - - void (*msk_1c1)(FZ_BYTE*,FZ_BYTE*,int); - void (*msk_1o1)(FZ_BYTE*,FZ_BYTE*,int); - void (*msk_w3i1o4)(FZ_BYTE*,FZ_BYTE*,FZ_BYTE*,int); - - void (*glf_1c1)(FZ_BYTE*,int,FZ_BYTE*,int,int,int); - void (*glf_1o1)(FZ_BYTE*,int,FZ_BYTE*,int,int,int); - void (*glf_w3i1o4)(FZ_BYTE*,FZ_BYTE*,int,FZ_BYTE*,int,int,int); - - void (*img_NcN)(FZ_PSRC, int sn, FZ_PDST, FZ_PCTM); - void (*img_1c1)(FZ_PSRC, FZ_PDST, FZ_PCTM); - void (*img_4c4)(FZ_PSRC, FZ_PDST, FZ_PCTM); - void (*img_1o1)(FZ_PSRC, FZ_PDST, FZ_PCTM); - void (*img_4o4)(FZ_PSRC, FZ_PDST, FZ_PCTM); - void (*img_w3i1o4)(FZ_BYTE*,FZ_PSRC,FZ_PDST,FZ_PCTM); -}; +/* + * Function pointers -- they can be replaced by cpu-optimized versions + */ + +extern void (*fz_duff_non)(FZ_BYTE*,int,int,FZ_BYTE*,int,int,int); +extern void (*fz_duff_nimcn)(FZ_BYTE*,int,int,FZ_BYTE*,int,int,FZ_BYTE*,int,int,int); +extern void (*fz_duff_nimon)(FZ_BYTE*,int,int,FZ_BYTE*,int,int,FZ_BYTE*,int,int,int); +extern void (*fz_duff_1o1)(FZ_BYTE*,int,FZ_BYTE*,int,int,int); +extern void (*fz_duff_4o4)(FZ_BYTE*,int,FZ_BYTE*,int,int,int); +extern void (*fz_duff_1i1c1)(FZ_BYTE*,int,FZ_BYTE*,int,FZ_BYTE*,int,int,int); +extern void (*fz_duff_4i1c4)(FZ_BYTE*,int,FZ_BYTE*,int,FZ_BYTE*,int,int,int); +extern void (*fz_duff_1i1o1)(FZ_BYTE*,int,FZ_BYTE*,int,FZ_BYTE*,int,int,int); +extern void (*fz_duff_4i1o4)(FZ_BYTE*,int,FZ_BYTE*,int,FZ_BYTE*,int,int,int); + +extern void (*fz_path_1c1)(FZ_BYTE*,FZ_BYTE*,int); +extern void (*fz_path_1o1)(FZ_BYTE*,FZ_BYTE*,int); +extern void (*fz_path_w3i1o4)(FZ_BYTE*,FZ_BYTE*,FZ_BYTE*,int); + +extern void (*fz_text_1c1)(FZ_BYTE*,int,FZ_BYTE*,int,int,int); +extern void (*fz_text_1o1)(FZ_BYTE*,int,FZ_BYTE*,int,int,int); +extern void (*fz_text_w3i1o4)(FZ_BYTE*,FZ_BYTE*,int,FZ_BYTE*,int,int,int); + +extern void (*fz_img_ncn)(FZ_PSRC, int sn, FZ_PDST, FZ_PCTM); +extern void (*fz_img_1c1)(FZ_PSRC, FZ_PDST, FZ_PCTM); +extern void (*fz_img_4c4)(FZ_PSRC, FZ_PDST, FZ_PCTM); +extern void (*fz_img_1o1)(FZ_PSRC, FZ_PDST, FZ_PCTM); +extern void (*fz_img_4o4)(FZ_PSRC, FZ_PDST, FZ_PCTM); +extern void (*fz_img_w3i1o4)(FZ_BYTE*,FZ_PSRC,FZ_PDST,FZ_PCTM); + +extern void (*fz_decodetile)(fz_pixmap *pix, int skip, float *decode); +extern void (*fz_loadtile1)(FZ_BYTE*, int sw, FZ_BYTE*, int dw, int w, int h, int pad); +extern void (*fz_loadtile2)(FZ_BYTE*, int sw, FZ_BYTE*, int dw, int w, int h, int pad); +extern void (*fz_loadtile4)(FZ_BYTE*, int sw, FZ_BYTE*, int dw, int w, int h, int pad); +extern void (*fz_loadtile8)(FZ_BYTE*, int sw, FZ_BYTE*, int dw, int w, int h, int pad); + +extern void (*fz_srown)(FZ_BYTE *src, FZ_BYTE *dst, int w, int denom, int n); +extern void (*fz_srow1)(FZ_BYTE *src, FZ_BYTE *dst, int w, int denom); +extern void (*fz_srow2)(FZ_BYTE *src, FZ_BYTE *dst, int w, int denom); +extern void (*fz_srow4)(FZ_BYTE *src, FZ_BYTE *dst, int w, int denom); +extern void (*fz_srow5)(FZ_BYTE *src, FZ_BYTE *dst, int w, int denom); + +extern void (*fz_scoln)(FZ_BYTE *src, FZ_BYTE *dst, int w, int denom, int n); +extern void (*fz_scol1)(FZ_BYTE *src, FZ_BYTE *dst, int w, int denom); +extern void (*fz_scol2)(FZ_BYTE *src, FZ_BYTE *dst, int w, int denom); +extern void (*fz_scol4)(FZ_BYTE *src, FZ_BYTE *dst, int w, int denom); +extern void (*fz_scol5)(FZ_BYTE *src, FZ_BYTE *dst, int w, int denom); #undef FZ_BYTE @@ -49,8 +66,6 @@ struct fz_renderer_s fz_gel *gel; fz_ael *ael; - fz_rastfuncs rast; - fz_irect clip; fz_pixmap *dest; fz_pixmap *over; @@ -58,11 +73,9 @@ struct fz_renderer_s int flag; }; -extern void fz_loadrastfuncs(fz_rastfuncs *); -extern void fz_accelrastfuncs(fz_rastfuncs *); +extern void fz_accelerate(); fz_error *fz_newrenderer(fz_renderer **gcp, fz_colorspace *pcm, int maskonly, int gcmem); void fz_droprenderer(fz_renderer *gc); - fz_error *fz_rendertree(fz_pixmap **out, fz_renderer *gc, fz_tree *tree, fz_matrix ctm, fz_irect bbox, int white); diff --git a/include/fitz/scanconv.h b/include/fitz/scanconv.h deleted file mode 100644 index 675d6806..00000000 --- a/include/fitz/scanconv.h +++ /dev/null @@ -1,48 +0,0 @@ -typedef struct fz_edge_s fz_edge; -typedef struct fz_gel_s fz_gel; -typedef struct fz_ael_s fz_ael; - -struct fz_edge_s -{ - int x, e, h, y; - int adjup, adjdown; - int xmove; - int xdir, ydir; /* -1 or +1 */ -}; - -struct fz_gel_s -{ - int hs, vs; - int xmin, xmax; - int ymin, ymax; - int cap; - int len; - fz_edge *edges; -}; - -struct fz_ael_s -{ - int cap; - int len; - fz_edge **edges; -}; - -fz_error *fz_newgel(fz_gel **gelp); -fz_error *fz_insertgel(fz_gel *gel, float x0, float y0, float x1, float y1); -fz_irect fz_boundgel(fz_gel *gel); -void fz_resetgel(fz_gel *gel, int hs, int vs); -void fz_sortgel(fz_gel *gel); -void fz_dropgel(fz_gel *gel); - -fz_error *fz_newael(fz_ael **aelp); -fz_error *fz_insertael(fz_ael *ael, fz_gel *gel, int y, int *e); -void fz_advanceael(fz_ael *ael); -void fz_dropael(fz_ael *ael); - -fz_error *fz_scanconvert(fz_gel *gel, fz_ael *ael, int eofill, int y0, int y1, - void (*blitfunc)(int,int,int,unsigned char*,void*), void *blitdata); - -fz_error *fz_fillpath(fz_gel *gel, fz_pathnode *path, fz_matrix ctm, float flatness); -fz_error *fz_strokepath(fz_gel *gel, fz_pathnode *path, fz_matrix ctm, float flatness); -fz_error *fz_dashpath(fz_gel *gel, fz_pathnode *path, fz_matrix ctm, float flatness); - diff --git a/mupdf/colorspace1.c b/mupdf/colorspace1.c index b1608740..08569cc4 100644 --- a/mupdf/colorspace1.c +++ b/mupdf/colorspace1.c @@ -515,6 +515,7 @@ loadseparation(fz_colorspace **csp, pdf_xref *xref, fz_obj *array) * Indexed */ +#if 0 static void indexedtoxyz(fz_colorspace *fzcs, float *ind, float *xyz) { @@ -523,11 +524,11 @@ indexedtoxyz(fz_colorspace *fzcs, float *ind, float *xyz) int i, k; i = ind[0] * 255; i = CLAMP(i, 0, cs->high); -printf("indexedtoxyz: %d\n", i); for (k = 0; k < cs->base->n; k++) alt[k] = cs->lookup[i * cs->base->n + k] / 255.0; cs->base->toxyz(cs->base, alt, xyz); } +#endif static void dropindexed(fz_colorspace *fzcs) @@ -563,7 +564,7 @@ loadindexed(fz_colorspace **csp, pdf_xref *xref, fz_obj *array) return fz_outofmem; } - initcs((fz_colorspace*)cs, "Indexed", 1, indexedtoxyz, nil, dropindexed); + initcs((fz_colorspace*)cs, "Indexed", 1, nil, nil, dropindexed); cs->base = base; cs->high = fz_toint(highobj); diff --git a/mupdf/image.c b/mupdf/image.c new file mode 100644 index 00000000..2b4242e5 --- /dev/null +++ b/mupdf/image.c @@ -0,0 +1,412 @@ +#include +#include + +void pdf_dropimage(fz_image *fzimg) +{ + pdf_image *img = (pdf_image*)fzimg; + fz_dropbuffer(img->samples); + if (img->mask) + fz_dropimage(img->mask); +} + +fz_error * +pdf_loadinlineimage(pdf_image **imgp, pdf_xref *xref, fz_obj *rdb, fz_obj *dict, fz_file *file) +{ + fz_error *error; + pdf_image *img; + fz_filter *filter; + fz_obj *f; + fz_obj *cs; + fz_obj *d; + int ismask; + int i; + + img = *imgp = fz_malloc(sizeof(pdf_image)); + if (!img) + return fz_outofmem; + + img->super.loadtile = pdf_loadtile; + img->super.drop = pdf_dropimage; + img->super.n = 0; + img->super.a = 0; + img->indexed = nil; + img->mask = nil; + + img->super.w = fz_toint(fz_dictgetsa(dict, "Width", "W")); + img->super.h = fz_toint(fz_dictgetsa(dict, "Height", "H")); + img->bpc = fz_toint(fz_dictgetsa(dict, "BitsPerComponent", "BPC")); + ismask = fz_tobool(fz_dictgetsa(dict, "ImageMask", "IM")); + d = fz_dictgetsa(dict, "Decode", "D"); + cs = fz_dictgetsa(dict, "ColorSpace", "CS"); + + if (ismask) + { + img->super.cs = nil; + img->super.n = 0; + img->super.a = 1; + img->bpc = 1; + } + + if (cs) + { + img->super.cs = nil; + + if (fz_isname(cs)) + { + fz_obj *csd = fz_dictgets(rdb, "ColorSpace"); + if (csd) + { + fz_obj *cso = fz_dictget(csd, cs); + img->super.cs = pdf_findresource(xref->rcolorspace, cso); + } + } + + if (!img->super.cs) + { + error = pdf_loadcolorspace(&img->super.cs, xref, cs); + if (error) + return error; + } + + if (!strcmp(img->super.cs->name, "Indexed")) + { + img->indexed = (pdf_indexed*)img->super.cs; + img->super.cs = img->indexed->base; + } + + img->super.n = img->super.cs->n; + img->super.a = 0; + } + + if (fz_isarray(d)) + { + if (img->indexed) + for (i = 0; i < 2; i++) + img->decode[i] = fz_toreal(fz_arrayget(d, i)); + else + for (i = 0; i < (img->super.n + img->super.a) * 2; i++) + img->decode[i] = fz_toreal(fz_arrayget(d, i)); + } + else + { + if (img->indexed) + for (i = 0; i < 2; i++) + img->decode[i] = i & 1 ? (1 << img->bpc) - 1 : 0; + else + for (i = 0; i < (img->super.n + img->super.a) * 2; i++) + img->decode[i] = i & 1; + } + + if (img->indexed) + img->stride = (img->super.w * img->bpc + 7) / 8; + else + img->stride = (img->super.w * (img->super.n + img->super.a) * img->bpc + 7) / 8; + + /* load image data */ + + f = fz_dictgetsa(dict, "Filter", "F"); + if (f) + { + error = pdf_decodefilter(&filter, dict); + if (error) + return error; + + error = fz_pushfilter(file, filter); + if (error) + return error; + + error = fz_readfile(&img->samples, file); + if (error) + return error; + + fz_popfilter(file); + } + else + { + error = fz_newbuffer(&img->samples, img->super.h * img->stride); + if (error) + return error; + + i = fz_read(file, img->samples->bp, img->super.h * img->stride); + error = fz_ferror(file); + if (error) + return error; + + img->samples->wp += img->super.h * img->stride; + } + + /* 0 means opaque and 1 means transparent, so we invert to get alpha */ + if (ismask) + { + unsigned char *p; + for (p = img->samples->bp; p < img->samples->ep; p++) + *p = ~*p; + } + + return nil; +} + +/* TODO error cleanup */ +fz_error * +pdf_loadimage(pdf_image **imgp, pdf_xref *xref, fz_obj *dict, fz_obj *ref) +{ + fz_error *error; + pdf_image *img; + pdf_image *mask; + int ismask; + fz_obj *obj; + fz_obj *sub; + int i; + + int w, h, bpc; + int n = 0; + int a = 0; + fz_colorspace *cs = nil; + pdf_indexed *indexed = nil; + int stride; + + img = fz_malloc(sizeof(pdf_image)); + if (!img) + return fz_outofmem; + + /* + * Dimensions, BPC and ColorSpace + */ + + w = fz_toint(fz_dictgets(dict, "Width")); + h = fz_toint(fz_dictgets(dict, "Height")); + bpc = fz_toint(fz_dictgets(dict, "BitsPerComponent")); + + cs = nil; + obj = fz_dictgets(dict, "ColorSpace"); + if (obj) + { + error = pdf_resolve(&obj, xref); + if (error) + return error; + + error = pdf_loadcolorspace(&cs, xref, obj); + if (error) + return error; + + if (!strcmp(cs->name, "Indexed")) + { + indexed = (pdf_indexed*)cs; + cs = indexed->base; + } + n = cs->n; + a = 0; + + fz_dropobj(obj); + } + + /* + * ImageMask, Mask and SoftMask + */ + + mask = nil; + + ismask = fz_tobool(fz_dictgets(dict, "ImageMask")); + if (ismask) + { + bpc = 1; + n = 0; + a = 1; + } + + obj = fz_dictgets(dict, "SMask"); + if (fz_isindirect(obj)) + { + error = pdf_loadindirect(&sub, xref, obj); + if (error) + return error; + + error = pdf_loadimage(&mask, xref, sub, obj); + if (error) + return error; + + if (mask->super.cs != pdf_devicegray) + return fz_throw("syntaxerror: SMask must be DeviceGray"); + + mask->super.cs = 0; + mask->super.n = 0; + mask->super.a = 1; + + fz_dropobj(sub); + } + + obj = fz_dictgets(dict, "Mask"); + if (fz_isindirect(obj)) + { + error = pdf_loadindirect(&sub, xref, obj); + if (error) + return error; + if (fz_isarray(sub)) + { + puts(" mask / color key"); + } + else + { + error = pdf_loadimage(&mask, xref, sub, obj); + if (error) + return error; + } + fz_dropobj(sub); + } + else if (fz_isarray(obj)) + { + puts(" mask / color key"); + } + + /* + * Decode + */ + + obj = fz_dictgets(dict, "Decode"); + if (fz_isarray(obj)) + { + if (indexed) + for (i = 0; i < 2; i++) + img->decode[i] = fz_toreal(fz_arrayget(obj, i)); + else + for (i = 0; i < (n + a) * 2; i++) + img->decode[i] = fz_toreal(fz_arrayget(obj, i)); + } + else + { + if (indexed) + for (i = 0; i < 2; i++) + img->decode[i] = i & 1 ? (1 << bpc) - 1 : 0; + else + for (i = 0; i < (n + a) * 2; i++) + img->decode[i] = i & 1; + } + + /* + * Load samples + */ + + if (indexed) + stride = (w * bpc + 7) / 8; + else + stride = (w * (n + a) * bpc + 7) / 8; + + error = pdf_loadstream(&img->samples, xref, fz_tonum(ref), fz_togen(ref)); + if (error) + { + /* TODO: colorspace? */ + fz_free(img); + return error; + } + + if (img->samples->wp - img->samples->bp < stride * h) + { + /* TODO: colorspace? */ + fz_dropbuffer(img->samples); + fz_free(img); + return fz_throw("syntaxerror: truncated image data"); + } + + /* 0 means opaque and 1 means transparent, so we invert to get alpha */ + if (ismask) + { + unsigned char *p; + for (p = img->samples->bp; p < img->samples->ep; p++) + *p = ~*p; + } + + /* + * Create image object + */ + + img->super.loadtile = pdf_loadtile; + img->super.drop = pdf_dropimage; + img->super.cs = cs; + img->super.w = w; + img->super.h = h; + img->super.n = n; + img->super.a = a; + img->indexed = indexed; + img->stride = stride; + img->bpc = bpc; + img->mask = (fz_image*)mask; + + *imgp = img; + + return nil; +} + +fz_error * +pdf_loadtile(fz_image *img, fz_pixmap *tile) +{ + pdf_image *src = (pdf_image*)img; + void (*tilefunc)(unsigned char*,int,unsigned char*, int, int, int, int); + fz_error *error; + + assert(tile->n == img->n + 1); + assert(tile->x >= 0); + assert(tile->y >= 0); + assert(tile->x + tile->w <= img->w); + assert(tile->y + tile->h <= img->h); + + switch (src->bpc) + { + case 1: tilefunc = fz_loadtile1; break; + case 2: tilefunc = fz_loadtile2; break; + case 4: tilefunc = fz_loadtile4; break; + case 8: tilefunc = fz_loadtile8; break; + default: + return fz_throw("rangecheck: unsupported bit depth: %d", src->bpc); + } + + if (src->indexed) + { + fz_pixmap *tmp; + int x, y, k, i; + int bpcfact = 1; + + error = fz_newpixmap(&tmp, tile->x, tile->y, tile->w, tile->h, 1); + if (error) + return error; + + switch (src->bpc) + { + case 1: bpcfact = 255; break; + case 2: bpcfact = 85; break; + case 4: bpcfact = 17; break; + case 8: bpcfact = 1; break; + } + + tilefunc(src->samples->rp, src->stride, + tmp->samples, tmp->w, + tmp->w, tmp->h, 0); + + for (y = 0; y < tile->h; y++) + { + for (x = 0; x < tile->w; x++) + { + tile->samples[(y * tile->w + x) * tile->n] = 255; + i = tmp->samples[y * tile->w + x] / bpcfact; + i = CLAMP(i, 0, src->indexed->high); + for (k = 0; k < src->indexed->base->n; k++) + { + tile->samples[(y * tile->w + x) * tile->n + k + 1] = + src->indexed->lookup[i * src->indexed->base->n + k]; + } + } + } + + fz_droppixmap(tmp); + } + + else + { + tilefunc(src->samples->rp, src->stride, + tile->samples, tile->w * tile->n, + img->w * (img->n + img->a), img->h, img->a ? 0 : img->n); + fz_decodetile(tile, !img->a, src->decode); + } + + return nil; +} + diff --git a/mupdf/image1.c b/mupdf/image1.c deleted file mode 100644 index ee1ff5b3..00000000 --- a/mupdf/image1.c +++ /dev/null @@ -1,340 +0,0 @@ -#include -#include - -void pdf_dropimage(fz_image *fzimg) -{ - pdf_image *img = (pdf_image*)fzimg; - fz_dropbuffer(img->samples); - if (img->mask) - fz_dropimage(img->mask); -} - -fz_error * -pdf_loadinlineimage(pdf_image **imgp, pdf_xref *xref, fz_obj *rdb, fz_obj *dict, fz_file *file) -{ - fz_error *error; - pdf_image *img; - fz_filter *filter; - fz_obj *f; - fz_obj *cs; - fz_obj *d; - int ismask; - int i; - - img = *imgp = fz_malloc(sizeof(pdf_image)); - if (!img) - return fz_outofmem; - - img->super.loadtile = pdf_loadtile; - img->super.drop = pdf_dropimage; - img->super.n = 0; - img->super.a = 0; - img->indexed = nil; - img->mask = nil; - - img->super.w = fz_toint(fz_dictgetsa(dict, "Width", "W")); - img->super.h = fz_toint(fz_dictgetsa(dict, "Height", "H")); - img->bpc = fz_toint(fz_dictgetsa(dict, "BitsPerComponent", "BPC")); - ismask = fz_tobool(fz_dictgetsa(dict, "ImageMask", "IM")); - d = fz_dictgetsa(dict, "Decode", "D"); - cs = fz_dictgetsa(dict, "ColorSpace", "CS"); - - if (ismask) - { - img->super.cs = nil; - img->super.n = 0; - img->super.a = 1; - img->bpc = 1; - } - - if (cs) - { - img->super.cs = nil; - - if (fz_isname(cs)) - { - fz_obj *csd = fz_dictgets(rdb, "ColorSpace"); - if (csd) - { - fz_obj *cso = fz_dictget(csd, cs); - img->super.cs = pdf_findresource(xref->rcolorspace, cso); - } - } - - if (!img->super.cs) - { - error = pdf_loadcolorspace(&img->super.cs, xref, cs); - if (error) - return error; - } - - if (!strcmp(img->super.cs->name, "Indexed")) - { - img->indexed = (pdf_indexed*)img->super.cs; - img->super.cs = img->indexed->base; - } - - img->super.n = img->super.cs->n; - img->super.a = 0; - } - - if (fz_isarray(d)) - { - if (img->indexed) - for (i = 0; i < 2; i++) - img->decode[i] = fz_toreal(fz_arrayget(d, i)); - else - for (i = 0; i < (img->super.n + img->super.a) * 2; i++) - img->decode[i] = fz_toreal(fz_arrayget(d, i)); - } - else - { - if (img->indexed) - for (i = 0; i < 2; i++) - img->decode[i] = i & 1 ? (1 << img->bpc) - 1 : 0; - else - for (i = 0; i < (img->super.n + img->super.a) * 2; i++) - img->decode[i] = i & 1; - } - - if (img->indexed) - img->stride = (img->super.w * img->bpc + 7) / 8; - else - img->stride = (img->super.w * (img->super.n + img->super.a) * img->bpc + 7) / 8; - - /* load image data */ - - f = fz_dictgetsa(dict, "Filter", "F"); - if (f) - { - error = pdf_decodefilter(&filter, dict); - if (error) - return error; - - error = fz_pushfilter(file, filter); - if (error) - return error; - - error = fz_readfile(&img->samples, file); - if (error) - return error; - - fz_popfilter(file); - } - else - { - error = fz_newbuffer(&img->samples, img->super.h * img->stride); - if (error) - return error; - - i = fz_read(file, img->samples->bp, img->super.h * img->stride); - error = fz_ferror(file); - if (error) - return error; - - img->samples->wp += img->super.h * img->stride; - } - - /* 0 means opaque and 1 means transparent, so we invert to get alpha */ - if (ismask) - { - unsigned char *p; - for (p = img->samples->bp; p < img->samples->ep; p++) - *p = ~*p; - } - - return nil; -} - -/* TODO error cleanup */ -fz_error * -pdf_loadimage(pdf_image **imgp, pdf_xref *xref, fz_obj *dict, fz_obj *ref) -{ - fz_error *error; - pdf_image *img; - pdf_image *mask; - int ismask; - fz_obj *obj; - fz_obj *sub; - int i; - - int w, h, bpc; - int n = 0; - int a = 0; - fz_colorspace *cs = nil; - pdf_indexed *indexed = nil; - int stride; - - img = fz_malloc(sizeof(pdf_image)); - if (!img) - return fz_outofmem; - - /* - * Dimensions, BPC and ColorSpace - */ - - w = fz_toint(fz_dictgets(dict, "Width")); - h = fz_toint(fz_dictgets(dict, "Height")); - bpc = fz_toint(fz_dictgets(dict, "BitsPerComponent")); - - cs = nil; - obj = fz_dictgets(dict, "ColorSpace"); - if (obj) - { - error = pdf_resolve(&obj, xref); - if (error) - return error; - - error = pdf_loadcolorspace(&cs, xref, obj); - if (error) - return error; - - if (!strcmp(cs->name, "Indexed")) - { - indexed = (pdf_indexed*)cs; - cs = indexed->base; - } - n = cs->n; - a = 0; - - fz_dropobj(obj); - } - - /* - * ImageMask, Mask and SoftMask - */ - - mask = nil; - - ismask = fz_tobool(fz_dictgets(dict, "ImageMask")); - if (ismask) - { - bpc = 1; - n = 0; - a = 1; - } - - obj = fz_dictgets(dict, "SMask"); - if (fz_isindirect(obj)) - { - puts(" smask"); - error = pdf_loadindirect(&sub, xref, obj); - if (error) - return error; - - error = pdf_loadimage(&mask, xref, sub, obj); - if (error) - return error; - - if (mask->super.cs != pdf_devicegray) - return fz_throw("syntaxerror: SMask must be DeviceGray"); - - mask->super.cs = 0; - mask->super.n = 0; - mask->super.a = 1; - - fz_dropobj(sub); - } - - obj = fz_dictgets(dict, "Mask"); - if (fz_isindirect(obj)) - { - error = pdf_loadindirect(&sub, xref, obj); - if (error) - return error; - if (fz_isarray(sub)) - { - puts(" mask / color key"); - } - else - { - puts(" mask"); - error = pdf_loadimage(&mask, xref, sub, obj); - if (error) - return error; - } - fz_dropobj(sub); - } - else if (fz_isarray(obj)) - { - puts(" mask / color key"); - } - - /* - * Decode - */ - - obj = fz_dictgets(dict, "Decode"); - if (fz_isarray(obj)) - { - if (indexed) - for (i = 0; i < 2; i++) - img->decode[i] = fz_toreal(fz_arrayget(obj, i)); - else - for (i = 0; i < (n + a) * 2; i++) - img->decode[i] = fz_toreal(fz_arrayget(obj, i)); - } - else - { - if (indexed) - for (i = 0; i < 2; i++) - img->decode[i] = i & 1 ? (1 << bpc) - 1 : 0; - else - for (i = 0; i < (n + a) * 2; i++) - img->decode[i] = i & 1; - } - - /* - * Load samples - */ - - if (indexed) - stride = (w * bpc + 7) / 8; - else - stride = (w * (n + a) * bpc + 7) / 8; - - error = pdf_loadstream(&img->samples, xref, fz_tonum(ref), fz_togen(ref)); - if (error) - { - /* TODO: colorspace? */ - fz_free(img); - return error; - } - - if (img->samples->wp - img->samples->bp < stride * h) - { - /* TODO: colorspace? */ - fz_dropbuffer(img->samples); - fz_free(img); - return fz_throw("syntaxerror: truncated image data"); - } - - /* 0 means opaque and 1 means transparent, so we invert to get alpha */ - if (ismask) - { - unsigned char *p; - for (p = img->samples->bp; p < img->samples->ep; p++) - *p = ~*p; - } - - /* - * Create image object - */ - - img->super.loadtile = pdf_loadtile; - img->super.drop = pdf_dropimage; - img->super.cs = cs; - img->super.w = w; - img->super.h = h; - img->super.n = n; - img->super.a = a; - img->indexed = indexed; - img->stride = stride; - img->bpc = bpc; - img->mask = (fz_image*)mask; - - *imgp = img; - - return nil; -} - diff --git a/mupdf/image2.c b/mupdf/image2.c deleted file mode 100644 index ad07e6bc..00000000 --- a/mupdf/image2.c +++ /dev/null @@ -1,255 +0,0 @@ -#include -#include - -static inline int getbit(const unsigned char *buf, int x) -{ - return ( buf[x >> 3] >> ( 7 - (x & 7) ) ) & 1; -} - -static inline int gettwo(const unsigned char *buf, int x) -{ - return ( buf[x >> 2] >> ( ( 3 - (x & 3) ) << 1 ) ) & 3; -} - -static inline int getnib(const unsigned char *buf, int x) -{ - return ( buf[x >> 1] >> ( ( 1 - (x & 1) ) << 2 ) ) & 0xf; -} - -static void loadtile1(pdf_image *src, fz_pixmap *dst, int n) -{ - int x, y, k; - for (y = dst->y; y < dst->y + dst->h; y++) - { - unsigned char *s = src->samples->bp + y * src->stride; - unsigned char *d = dst->samples + y * dst->w * dst->n; - for (x = dst->x; x < dst->x + dst->w; x++) - { - for (k = 0; k < n; k++) - d[x * n + k] = getbit(s, x * n + k); - } - } -} - -static void loadtile1a(pdf_image *src, fz_pixmap *dst, int n) -{ - int x, y, k; - for (y = dst->y; y < dst->y + dst->h; y++) - { - unsigned char *s = src->samples->bp + y * src->stride; - unsigned char *d = dst->samples + y * dst->w * dst->n; - for (x = dst->x; x < dst->x + dst->w; x++) - { - d[x * (n+1) + 0] = 1; - for (k = 0; k < n; k++) - d[x * (n+1) + k + 1] = getbit(s, x * n + k); - } - } -} - -static void loadtile2(pdf_image *src, fz_pixmap *dst, int n) -{ - int x, y, k; - for (y = dst->y; y < dst->y + dst->h; y++) - { - unsigned char *s = src->samples->bp + y * src->stride; - unsigned char *d = dst->samples + y * dst->w * dst->n; - for (x = dst->x; x < dst->x + dst->w; x++) - { - for (k = 0; k < n; k++) - d[x * n + k] = gettwo(s, x * n + k); - } - } -} - -static void loadtile2a(pdf_image *src, fz_pixmap *dst, int n) -{ - int x, y, k; - for (y = dst->y; y < dst->y + dst->h; y++) - { - unsigned char *s = src->samples->bp + y * src->stride; - unsigned char *d = dst->samples + y * dst->w * dst->n; - for (x = dst->x; x < dst->x + dst->w; x++) - { - d[x * (n+1) + 0] = 1; - for (k = 0; k < n; k++) - d[x * (n+1) + k + 1] = gettwo(s, x * n + k); - } - } -} - -static void loadtile4(pdf_image *src, fz_pixmap *dst, int n) -{ - int x, y, k; - for (y = dst->y; y < dst->y + dst->h; y++) - { - unsigned char *s = src->samples->bp + y * src->stride; - unsigned char *d = dst->samples + y * dst->w * dst->n; - for (x = dst->x; x < dst->x + dst->w; x++) - { - for (k = 0; k < n; k++) - d[x * n + k] = getnib(s, x * n + k); - } - } -} - -static void loadtile4a(pdf_image *src, fz_pixmap *dst, int n) -{ - int x, y, k; - for (y = dst->y; y < dst->y + dst->h; y++) - { - unsigned char *s = src->samples->bp + y * src->stride; - unsigned char *d = dst->samples + y * dst->w * dst->n; - for (x = dst->x; x < dst->x + dst->w; x++) - { - d[x * (n+1) + 0] = 1; - for (k = 0; k < n; k++) - d[x * (n+1) + k + 1] = getnib(s, x * n + k); - } - } -} - -static void loadtile8(pdf_image *src, fz_pixmap *dst, int n) -{ - int x, y, k; - for (y = dst->y; y < dst->y + dst->h; y++) - { - unsigned char *s = src->samples->bp + y * src->stride; - unsigned char *d = dst->samples + y * dst->w * dst->n; - for (x = dst->x; x < dst->x + dst->w; x++) - for (k = 0; k < n; k++) - *d++ = *s++; - } -} - -static void loadtile8a(pdf_image *src, fz_pixmap *dst, int n) -{ - int x, y, k; - for (y = dst->y; y < dst->y + dst->h; y++) - { - unsigned char *s = src->samples->bp + y * src->stride; - unsigned char *d = dst->samples + y * dst->w * dst->n; - for (x = dst->x; x < dst->x + dst->w; x++) - { - *d++ = 255; - for (k = 0; k < n; k++) - *d++ = *s++; - } - } -} - -static void -decodetile(fz_pixmap *pix, int bpc, int skip, float *decode) -{ - unsigned char table[FZ_MAXCOLORS][256]; - float invtwon = 1.0 / ((1 << bpc) - 1); - int x, y, k, i; - - for (i = 0; i < (1 << bpc); i++) - { - if (skip) - table[0][i] = (i * 255) * invtwon; - for (k = skip; k < pix->n; k++) - { - float min = decode[(k - skip) * 2 + 0]; - float max = decode[(k - skip) * 2 + 1]; - float f = min + i * (max - min) * invtwon; - table[k][i] = f * 255; - } - } - - for (y = 0; y < pix->h; y++) - { - for (x = 0; x < pix->w; x++) - { - for (k = 0; k < pix->n; k++) - { - i = pix->samples[ (y * pix->w + x) * pix->n + k]; - pix->samples[ (y * pix->w + x) * pix->n + k] = table[k][i]; - } - } - } -} - -fz_error * -pdf_loadtile(fz_image *img, fz_pixmap *tile) -{ - pdf_image *src = (pdf_image*)img; - fz_error *error; - - assert(tile->n == img->n + 1); - assert(tile->x >= 0); - assert(tile->y >= 0); - assert(tile->x + tile->w <= img->w); - assert(tile->y + tile->h <= img->h); - - if (src->indexed) - { - fz_pixmap *tmp; - int x, y, k, i; - - error = fz_newpixmap(&tmp, tile->x, tile->y, tile->w, tile->h, 1); - if (error) - return error; - - switch (src->bpc) - { - case 1: loadtile1(src, tmp, 1); break; - case 2: loadtile2(src, tmp, 1); break; - case 4: loadtile4(src, tmp, 1); break; - case 8: loadtile8(src, tmp, 1); break; - default: - return fz_throw("rangecheck: unsupported bit depth: %d", src->bpc); - } - - for (y = 0; y < tile->h; y++) - { - for (x = 0; x < tile->w; x++) - { - tile->samples[(y * tile->w + x) * tile->n] = 255; - i = tmp->samples[y * tile->w + x]; - i = CLAMP(i, 0, src->indexed->high); - for (k = 0; k < src->indexed->base->n; k++) - { - tile->samples[(y * tile->w + x) * tile->n + k + 1] = - src->indexed->lookup[i * src->indexed->base->n + k]; - } - } - } - - fz_droppixmap(tmp); - } - - else - { - if (img->a) - { - switch (src->bpc) - { - case 1: loadtile1(src, tile, img->n + img->a); break; - case 2: loadtile2(src, tile, img->n + img->a); break; - case 4: loadtile4(src, tile, img->n + img->a); break; - case 8: loadtile8(src, tile, img->n + img->a); break; - default: - return fz_throw("rangecheck: unsupported bit depth: %d", src->bpc); - } - } - else - { - switch (src->bpc) - { - case 1: loadtile1a(src, tile, img->n); break; - case 2: loadtile2a(src, tile, img->n); break; - case 4: loadtile4a(src, tile, img->n); break; - case 8: loadtile8a(src, tile, img->n); break; - default: - return fz_throw("rangecheck: unsupported bit depth: %d", src->bpc); - } - } - - decodetile(tile, src->bpc, !img->a, src->decode); - } - - return nil; -} - diff --git a/mupdf/resources.c b/mupdf/resources.c index 3d962a43..10d7de43 100644 --- a/mupdf/resources.c +++ b/mupdf/resources.c @@ -4,6 +4,8 @@ void * pdf_findresource(pdf_rsrc *rsrc, fz_obj *key) { + if (key == nil) + return nil; while (rsrc) { if (!fz_cmpobj(rsrc->key, key)) diff --git a/render/archppc.c b/render/archppc.c new file mode 100644 index 00000000..2d0fee1d --- /dev/null +++ b/render/archppc.c @@ -0,0 +1,65 @@ +/* + * PowerPC specific render optims live here + */ + +#include + +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/render/archsparc.c b/render/archsparc.c new file mode 100644 index 00000000..32e142c3 --- /dev/null +++ b/render/archsparc.c @@ -0,0 +1,21 @@ +/* +SPARC specific render optims live here +*/ +#include + +#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/render/archx86.c b/render/archx86.c new file mode 100644 index 00000000..9754214f --- /dev/null +++ b/render/archx86.c @@ -0,0 +1,226 @@ +/* +x86 specific render optims live here +*/ +#include + +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 >> 17; + int iv = v >> 17; + + 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(s0, s1); + ms2s3 = _mm_set_pi32(s2, s3); + } + 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_unpackhi_pi8(ms0s1, mzero); + __m64 ms1 = _mm_unpacklo_pi8(ms0s1, mzero); + __m64 ms2 = _mm_unpackhi_pi8(ms2s3, mzero); + __m64 ms3 = _mm_unpacklo_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); + __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); + __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); + __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/render/edgelist.c b/render/edgelist.c deleted file mode 100644 index 9eaaf7a7..00000000 --- a/render/edgelist.c +++ /dev/null @@ -1,300 +0,0 @@ -#include - -/* - * 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->xmin = gel->ymin = INT_MAX; - gel->xmax = gel->ymax = INT_MIN; - gel->hs = 1; - gel->vs = 1; - - return nil; -} - -void -fz_resetgel(fz_gel *gel, int hs, int vs) -{ - gel->xmin = gel->ymin = INT_MAX; - gel->xmax = gel->ymax = INT_MIN; - gel->hs = hs; - gel->vs = vs; - 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.min.x = fz_idiv(gel->xmin, gel->hs); - bbox.min.y = fz_idiv(gel->ymin, gel->vs); - bbox.max.x = fz_idiv(gel->xmax, gel->hs) + 1; - bbox.max.y = fz_idiv(gel->ymax, gel->vs) + 1; - return bbox; -} - -fz_error * -fz_insertgel(fz_gel *gel, float fx0, float fy0, float fx1, float fy1) -{ - fz_edge *edge; - int x0, y0, x1, y1; - int dx, dy; - int winding; - int width; - int tmp; - - fx0 *= gel->hs; - fy0 *= gel->vs; - fx1 *= gel->hs; - fy1 *= gel->vs; - - /* TODO: should we round or truncate? */ - x0 = fx0 < 0 ? fx0 - 0.5 : fx0 + 0.5; - y0 = fy0 < 0 ? fy0 - 0.5 : fy0 + 0.5; - x1 = fx1 < 0 ? fx1 - 0.5 : fx1 + 0.5; - y1 = fy1 < 0 ? fy1 - 0.5 : fy1 + 0.5; - - if (y0 == y1) - return nil; - - if (y0 > y1) { - winding = -1; - tmp = x0; x0 = x1; x1 = tmp; - tmp = y0; y0 = y1; y1 = tmp; - } - else - winding = 1; - - if (x0 < gel->xmin) gel->xmin = x0; - if (x0 > gel->xmax) gel->xmax = x0; - if (x1 < gel->xmin) gel->xmin = x1; - if (x1 > gel->xmax) gel->xmax = x1; - - if (y0 < gel->ymin) gel->ymin = y0; - if (y1 > gel->ymax) gel->ymax = 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 nil; -} - -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 nil; -} - -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; - } -} - -fz_error * -fz_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 nil; -} - -void -fz_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 ++; - } - } -} - diff --git a/render/fill.c b/render/fill.c deleted file mode 100644 index d25f78b1..00000000 --- a/render/fill.c +++ /dev/null @@ -1,132 +0,0 @@ -#include - -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 nil; -} - diff --git a/render/optduff.c b/render/optduff.c new file mode 100644 index 00000000..75d305ba --- /dev/null +++ b/render/optduff.c @@ -0,0 +1,324 @@ +#include + +typedef unsigned char byte; + +/* + * Blend pixmap regions + */ + +/* dst = src over dst */ +static void +duff_non(byte *sp0, int sw, int sn, byte *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 *sp0, int sw, int sn, byte *mp0, int mw, int mn, byte *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 *sp0, int sw, int sn, byte *mp0, int mw, int mn, byte *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 *sp0, int sw, byte *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 *sp0, int sw, byte *mp0, int mw, byte *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 *sp0, int sw, byte *mp0, int mw, byte *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 *sp0, int sw, byte *mp0, int mw, byte *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 *sp0, int sw, byte *mp0, int mw, byte *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 *src, byte *dst, int w) +{ + memcpy(dst, src, w); +} + +static void path_1o1(byte *src, byte *dst, int w) +{ + while (w--) + { + dst[0] = src[0] + fz_mul255(dst[0], 255 - src[0]); + src++; + dst++; + } +} + +static void path_w3i1o4(byte *rgb, byte *src, byte *dst, int n) +{ + byte rgb0 = rgb[0]; + byte rgb1 = rgb[1]; + byte rgb2 = rgb[2]; + byte sa, ssa; + while (n--) + { + sa = src[0]; + ssa = 255 - sa; + dst[0] = sa + fz_mul255(dst[0], ssa); + dst[1] = rgb0 + fz_mul255((short)dst[1] - rgb0, ssa); + dst[2] = rgb1 + fz_mul255((short)dst[2] - rgb1, ssa); + dst[3] = rgb2 + fz_mul255((short)dst[3] - rgb2, ssa); + src ++; + dst += 4; + } +} + +static void text_1c1(byte *src, int srcw, byte *dst, int dstw, int w0, int h) +{ + while (h--) + { + path_1c1(src, dst, w0); + src += srcw; + dst += dstw; + } +} + +static void text_1o1(byte *src, int srcw, byte *dst, int dstw, int w0, int h) +{ + while (h--) + { + path_1o1(src, dst, w0); + src += srcw; + dst += dstw; + } +} + +static void text_w3i1o4(byte *rgb, byte *src, int srcw, byte *dst, int dstw, int w0, int h) +{ + while (h--) + { + path_w3i1o4(rgb, src, dst, w0); + src += srcw; + dst += 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) = path_1c1; +void (*fz_path_1o1)(byte*,byte*,int) = path_1o1; +void (*fz_path_w3i1o4)(byte*,byte*,byte*,int) = path_w3i1o4; + +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_w3i1o4)(byte*,byte*,int,byte*,int,int,int) = text_w3i1o4; + diff --git a/render/optimage.c b/render/optimage.c new file mode 100644 index 00000000..0654b006 --- /dev/null +++ b/render/optimage.c @@ -0,0 +1,238 @@ +#include + +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_w3i1o4(byte *rgb, FZ_PSRC, FZ_PDST, FZ_PCTM) +{ + byte rgb0 = rgb[0]; + byte rgb1 = rgb[1]; + byte rgb2 = rgb[2]; + byte sa, ssa; + while (h--) + { + byte *dstp = dst0; + int u = u0; + int v = v0; + int w = w0; + while (w--) + { + sa = samplemask(src, srcw, srch, u, v); + ssa = 255 - sa; + dstp[0] = sa + fz_mul255(dstp[0], ssa); + dstp[1] = rgb0 + fz_mul255((short)dstp[1] - rgb0, ssa); + dstp[2] = rgb1 + fz_mul255((short)dstp[2] - rgb1, ssa); + dstp[3] = rgb2 + fz_mul255((short)dstp[3] - rgb2, ssa); + 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_w3i1o4)(byte*,FZ_PSRC,FZ_PDST,FZ_PCTM) = img_w3i1o4; + diff --git a/render/optscale.c b/render/optscale.c new file mode 100644 index 00000000..ede19f1c --- /dev/null +++ b/render/optscale.c @@ -0,0 +1,191 @@ +#include + +typedef unsigned char byte; + +static void srown(byte *src, byte *dst, int w, int denom, int n) +{ + int x, left, k; + int 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] / denom; + sum[k] = 0; + } + dst += n; + } + } + + /* left overs */ + if (left) + for (k = 0; k < n; k++) + dst[k] = sum[k] / left; +} + +static void srow1(byte *src, byte *dst, int w, int denom) +{ + srown(src, dst, w, denom, 1); +} + +static void srow2(byte *src, byte *dst, int w, int denom) +{ + srown(src, dst, w, denom, 2); +} + +static void srow4(byte *src, byte *dst, int w, int denom) +{ + srown(src, dst, w, denom, 4); +} + +static void srow5(byte *src, byte *dst, int w, int denom) +{ + srown(src, dst, w, denom, 5); +} + +static void scoln(byte *src, byte *dst, int w, int denom, int n) +{ + 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] / denom; + 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_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; + + 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); + } + + ydenom = src->h - y; + if (ydenom) + { + 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); + } + } + + 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); + } + + ydenom = src->h - y; + if (ydenom) + { + 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); + } + } + + fz_free(buf); + *dstp = dst; + return nil; +} + diff --git a/render/optunpack.c b/render/optunpack.c new file mode 100644 index 00000000..1c77a787 --- /dev/null +++ b/render/optunpack.c @@ -0,0 +1,183 @@ +#include + +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 useless = 1; + byte *p = pix->samples; + int n = pix->n; + int wh = pix->w * pix->h; + int i; + + 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]; + if (min[i] != 0 || max[i] != 255) + useless = 0; + } + + if (useless) + return; + + 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 *src, int sw, byte *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 \ + while (h--) \ + { \ + byte *dp = dst; \ + for (x = 0; x < w; x++) \ + { \ + if ((x % pad) == 0) \ + *dp++ = 255; \ + *dp++ = getf(src, x); \ + } \ + src += sw; \ + dst += dw; \ + } \ +} + +static void loadtile2(byte *src, int sw, byte *dst, int dw, int w, int h, int pad) + TILE(ttwo) +static void loadtile4(byte *src, int sw, byte *dst, int dw, int w, int h, int pad) + TILE(tnib) +static void loadtile8(byte *src, int sw, byte *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/render/pathfill.c b/render/pathfill.c new file mode 100644 index 00000000..d25f78b1 --- /dev/null +++ b/render/pathfill.c @@ -0,0 +1,132 @@ +#include + +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 nil; +} + diff --git a/render/pathscan.c b/render/pathscan.c new file mode 100644 index 00000000..7dd6397d --- /dev/null +++ b/render/pathscan.c @@ -0,0 +1,454 @@ +#include + +/* + * 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->xmin = gel->ymin = INT_MAX; + gel->xmax = gel->ymax = INT_MIN; + gel->hs = 1; + gel->vs = 1; + + return nil; +} + +void +fz_resetgel(fz_gel *gel, int hs, int vs) +{ + gel->xmin = gel->ymin = INT_MAX; + gel->xmax = gel->ymax = INT_MIN; + gel->hs = hs; + gel->vs = vs; + 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.min.x = fz_idiv(gel->xmin, gel->hs); + bbox.min.y = fz_idiv(gel->ymin, gel->vs); + bbox.max.x = fz_idiv(gel->xmax, gel->hs) + 1; + bbox.max.y = fz_idiv(gel->ymax, gel->vs) + 1; + return bbox; +} + +fz_error * +fz_insertgel(fz_gel *gel, float fx0, float fy0, float fx1, float fy1) +{ + fz_edge *edge; + int x0, y0, x1, y1; + int dx, dy; + int winding; + int width; + int tmp; + + fx0 *= gel->hs; + fy0 *= gel->vs; + fx1 *= gel->hs; + fy1 *= gel->vs; + + /* TODO: should we round or truncate? */ + x0 = fx0 < 0 ? fx0 - 0.5 : fx0 + 0.5; + y0 = fy0 < 0 ? fy0 - 0.5 : fy0 + 0.5; + x1 = fx1 < 0 ? fx1 - 0.5 : fx1 + 0.5; + y1 = fy1 < 0 ? fy1 - 0.5 : fy1 + 0.5; + + if (y0 == y1) + return nil; + + if (y0 > y1) { + winding = -1; + tmp = x0; x0 = x1; x1 = tmp; + tmp = y0; y0 = y1; y1 = tmp; + } + else + winding = 1; + + if (x0 < gel->xmin) gel->xmin = x0; + if (x0 > gel->xmax) gel->xmax = x0; + if (x1 < gel->xmin) gel->xmin = x1; + if (x1 > gel->xmax) gel->xmax = x1; + + if (y0 < gel->ymin) gel->ymin = y0; + if (y1 > gel->ymax) gel->ymax = 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 nil; +} + +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 nil; +} + +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 nil; +} + +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 hs) +{ + int x0pix, x0sub; + int x1pix, x1sub; + + if (x0 == x1) + return; + + /* x between 0 and width of bbox */ + x0 -= xofs; + x1 -= xofs; + + x0pix = x0 / hs; + x0sub = x0 % hs; + x1pix = x1 / hs; + x1sub = x1 % hs; + + if (x0pix == x1pix) + { + list[x0pix] += x1sub - x0sub; + list[x0pix+1] += x0sub - x1sub; + } + + else + { + list[x0pix] += hs - x0sub; + list[x0pix+1] += x0sub; + list[x1pix] += x1sub - hs; + list[x1pix+1] += -x1sub; + } +} + +static inline void +nonzerowinding(fz_ael *ael, unsigned char *list, int xofs, int hs) +{ + 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, hs); + winding += ael->edges[i]->ydir; + } +} + +static inline void +evenodd(fz_ael *ael, unsigned char *list, int xofs, int hs) +{ + 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, hs); + even = !even; + } +} + +static void toalpha(unsigned char *list, int n) +{ + int d = 0; + while (n--) + { + d += *list; + *list++ = d; + } +} + +fz_error * +fz_scanconvert(fz_gel *gel, fz_ael *ael, int eofill, int y0, int y1, + void (*blitfunc)(int,int,int,unsigned char*,void*), void *blitdata) +{ + fz_error *error; + unsigned char *deltas; + int y, e; + int yd, yc; + + int xmin = fz_idiv(gel->xmin, gel->hs); + int xmax = fz_idiv(gel->xmax, gel->hs) + 1; + + int xofs = xmin * gel->hs; + int hs = gel->hs; + int vs = gel->vs; + + if (gel->len == 0) + return nil; + + 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, vs); + yd = yc; + + while (ael->len > 0 || e < gel->len) + { + yc = fz_idiv(y, vs); + if (yc != yd) { + if (yd >= y0 && yd < y1) + { + toalpha(deltas, xmax - xmin); + blitfunc(yd, xmin, xmax - xmin, deltas, blitdata); + memset(deltas, 0, xmax - xmin + 1); + } + } + yd = yc; + + error = insertael(ael, gel, y, &e); + if (error) { + fz_free(deltas); + return error; + } + + if (yd >= y0 && yd < y1) + { + if (eofill) + evenodd(ael, deltas, xofs, hs); + else + nonzerowinding(ael, deltas, xofs, hs); + } + + advanceael(ael); + + if (ael->len > 0) + y ++; + else if (e < gel->len) + y = gel->edges[e].y; + } + + if (yd >= y0 && yd < y1) + { + toalpha(deltas, xmax - xmin); + blitfunc(yd, xmin, xmax - xmin, deltas, blitdata); + } + + fz_free(deltas); + return nil; +} + diff --git a/render/pathstroke.c b/render/pathstroke.c new file mode 100644 index 00000000..2527e6ad --- /dev/null +++ b/render/pathstroke.c @@ -0,0 +1,725 @@ +#include + +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 nil; +} + +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 nil; +} + +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 nil; + if (dx1 * dx1 + dy1 * dy1 < FLT_EPSILON) + return nil; + + 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 nil; +} + +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 nil; +} + +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 nil; +} + +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 nil; +} + +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 nil; +} + +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 nil; + } + + 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 nil; +} + +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 nil; +} + +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) +{ + 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 = path->linewidth * 0.5; + s.miterlimit = path->miterlimit; + s.sn = 0; + s.bn = 0; + s.dot = 0; + + i = 0; + + 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 nil; +} + +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 nil; +} + +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) +{ + 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 = path->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; + + 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/render/rastport.c b/render/rastport.c deleted file mode 100644 index 3eb89e43..00000000 --- a/render/rastport.c +++ /dev/null @@ -1,570 +0,0 @@ -#include - -typedef unsigned char byte; - -/* - * General Porter-Duff compositing -- blit image regions - * - * duff_NoN - * duff_NiM - * duff_NiMoN - */ - -/* dst = src over dst */ -static void -duff_NoN(byte *sp0, int sw, int sn, byte *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 *sp0, int sw, int sn, byte *mp0, int mw, int mn, byte *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 *sp0, int sw, int sn, byte *mp0, int mw, int mn, byte *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 *sp0, int sw, byte *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 *sp0, int sw, byte *mp0, int mw, byte *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 *sp0, int sw, byte *mp0, int mw, byte *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 *sp0, int sw, byte *mp0, int mw, byte *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 *sp0, int sw, byte *mp0, int mw, byte *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; - } -} - -/* - * Mask -- blit one scanline of mask - * - * msk_1c1 - * msk_1o1 - * msk_1i1c1 - * msk_1i1o1 - * msk_w3i1o4 - * msk_w3i1i1o4 - */ - -static void msk_1c1(byte *src, byte *dst, int w) -{ - memcpy(dst, src, w); -} - -static void msk_1o1(byte *src, byte *dst, int w) -{ - while (w--) - { - dst[0] = src[0] + fz_mul255(dst[0], 255 - src[0]); - src++; - dst++; - } -} - -static void msk_w3i1o4(byte *rgb, byte *src, byte *dst, int n) -{ - byte rgb0 = rgb[0]; - byte rgb1 = rgb[1]; - byte rgb2 = rgb[2]; - byte sa, ssa; - while (n--) - { - sa = src[0]; - ssa = 255 - sa; - dst[0] = sa + fz_mul255(dst[0], ssa); - dst[1] = rgb0 + fz_mul255((short)dst[1] - rgb0, ssa); - dst[2] = rgb1 + fz_mul255((short)dst[2] - rgb1, ssa); - dst[3] = rgb2 + fz_mul255((short)dst[3] - rgb2, ssa); - src ++; - dst += 4; - } -} - -/* - * Image -- draw transformed image - * - */ - -#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); -} - -/* - * img_NcN - * img_1c1 - * img_4c4 - * img_1o1 - * img_4o4 - * img_1i1c1 - * img_1i1o1 - * img_4i1c4 - * img_4i1o4 - * img_w3i1o4 - * img_w3i1i1o4 - */ - -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_w3i1o4(byte *rgb, FZ_PSRC, FZ_PDST, FZ_PCTM) -{ - byte rgb0 = rgb[0]; - byte rgb1 = rgb[1]; - byte rgb2 = rgb[2]; - byte sa, ssa; - while (h--) - { - byte *dstp = dst0; - int u = u0; - int v = v0; - int w = w0; - while (w--) - { - sa = samplemask(src, srcw, srch, u, v); - ssa = 255 - sa; - dstp[0] = sa + fz_mul255(dstp[0], ssa); - dstp[1] = rgb0 + fz_mul255((short)dstp[1] - rgb0, ssa); - dstp[2] = rgb1 + fz_mul255((short)dstp[2] - rgb1, ssa); - dstp[3] = rgb2 + fz_mul255((short)dstp[3] - rgb2, ssa); - dstp += 4; - u += fa; - v += fb; - } - dst0 += dstw; - u0 += fc; - v0 += fd; - } -} - -/* - * Fill in the big fat vtable - */ - -static fz_rastfuncs deftab = -{ - duff_NoN, - duff_NiMcN, - duff_NiMoN, - duff_1o1, - duff_4o4, - duff_1i1c1, - duff_4i1c4, - duff_1i1o1, - duff_4i1o4, - - msk_1c1, - msk_1o1, - msk_w3i1o4, - - nil, - nil, - nil, - - img_NcN, - img_1c1, - img_4c4, - img_1o1, - img_4o4, - img_w3i1o4 -}; - -void -fz_loadrastfuncs(fz_rastfuncs *tab) -{ - *tab = deftab; -#ifdef HAVE_CPUDEP - fz_accelrastfuncs(tab); -#endif -} - diff --git a/render/rastppc.c b/render/rastppc.c deleted file mode 100644 index b693b2d7..00000000 --- a/render/rastppc.c +++ /dev/null @@ -1,23 +0,0 @@ -/* - * PowerPC specific render optims live here - */ - -#include - -#ifdef HAVE_ALTIVEC - -#endif /* HAVE_ALTIVEC */ - -#if defined (ARCH_PPC) -void -fz_accelrastfuncs(fz_rastfuncs *tab) -{ -# ifdef HAVE_ALTIVEC - if (fz_cpuflags & HAVE_ALTIVEC) - { - /* ... */ - } -# endif -} -#endif - diff --git a/render/rastsparc.c b/render/rastsparc.c deleted file mode 100644 index c18db9a5..00000000 --- a/render/rastsparc.c +++ /dev/null @@ -1,21 +0,0 @@ -/* -SPARC specific render optims live here -*/ -#include - -#ifdef HAVE_VIS - -#endif - -#if defined (ARCH_SPARC) -void -fz_accelrastfuncs(fz_rastfuncs *tab) -{ -# ifdef HAVE_VIS - if (fz_cpuflags & HAVE_VIS) - { - } -# endif -} -#endif - diff --git a/render/rastx86.c b/render/rastx86.c deleted file mode 100644 index 9360b5e2..00000000 --- a/render/rastx86.c +++ /dev/null @@ -1,225 +0,0 @@ -/* -x86 specific render optims live here -*/ -#include - -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 = 254 - 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 >> 17; - int iv = v >> 17; - - 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(s0, s1); - ms2s3 = _mm_set_pi32(s2, s3); - } - 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_unpackhi_pi8(ms0s1, mzero); - __m64 ms1 = _mm_unpacklo_pi8(ms0s1, mzero); - __m64 ms2 = _mm_unpackhi_pi8(ms2s3, mzero); - __m64 ms3 = _mm_unpacklo_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); - __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); - __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); - __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_accelrastfuncs(fz_rastfuncs *tab) -{ -# ifdef HAVE_MMX - if (fz_cpuflags & HAVE_MMX) - { - tab->duff_4i1o4 = duff_4i1o4mmx; - tab->img_4o4 = img_4o4mmx; - } -# endif -} -#endif diff --git a/render/render.c b/render/render.c index 92ab519f..424d8c1a 100644 --- a/render/render.c +++ b/render/render.c @@ -39,8 +39,6 @@ fz_newrenderer(fz_renderer **gcp, fz_colorspace *pcm, int maskonly, int gcmem) if (error) goto cleanup; - fz_loadrastfuncs(&gc->rast); - gc->dest = nil; gc->over = nil; gc->rgb[0] = 0; @@ -150,7 +148,6 @@ enum { HS = 17, VS = 15, SF = 1 }; struct spandata { - fz_rastfuncs *rast; int x, n; fz_pixmap *dst; unsigned char *rgb; @@ -160,7 +157,6 @@ struct spandata static void spanfunc(int y, int x, int n, unsigned char *path, void *userdata) { struct spandata *user = userdata; - fz_rastfuncs *rast = user->rast; fz_pixmap *dst = user->dst; unsigned char *dstp; @@ -173,13 +169,13 @@ static void spanfunc(int y, int x, int n, unsigned char *path, void *userdata) { case FNONE: assert(dst->n == 1); - rast->msk_1c1(path, dstp, user->n); break; + fz_path_1c1(path, dstp, user->n); break; case FOVER: assert(dst->n == 1); - rast->msk_1o1(path, dstp, user->n); break; + fz_path_1o1(path, dstp, user->n); break; case FOVER | FRGB: assert(dst->n == 4); - rast->msk_w3i1o4(user->rgb, path, dstp, user->n); break; + fz_path_w3i1o4(user->rgb, path, dstp, user->n); break; default: assert(!"impossible flag in path span function"); } @@ -222,7 +218,6 @@ renderpath(fz_renderer *gc, fz_pathnode *path, fz_matrix ctm) DEBUG("path %s;\n", path->paint == FZ_STROKE ? "stroke" : "fill"); - user.rast = &gc->rast; user.x = clip.min.x - gbox.min.x; user.n = clip.max.x - clip.min.x; user.flag = gc->flag; @@ -290,32 +285,17 @@ static void drawglyph(fz_renderer *gc, fz_pixmap *dst, fz_glyph *src, int xorig, { case FNONE: assert(dst->n == 1); - while (h--) - { - gc->rast.msk_1c1(sp, dp, w); - sp += src->w; - dp += dst->w; - } + fz_text_1c1(sp, src->w, dp, dst->w, w, h); break; case FOVER: assert(dst->n == 1); - while (h--) - { - gc->rast.msk_1o1(sp, dp, w); - sp += src->w; - dp += dst->w; - } + fz_text_1o1(sp, src->w, dp, dst->w, w, h); break; case FOVER | FRGB: assert(dst->n == 4); - while (h--) - { - gc->rast.msk_w3i1o4(gc->rgb, sp, dp, w); - sp += src->w; - dp += dst->w * 4; - } + fz_text_w3i1o4(gc->rgb, sp, src->w, dp, dst->w * 4, w, h); break; default: @@ -499,9 +479,9 @@ DEBUG(" fnone %d x %d\n", w, h); goto cleanup; if (image->cs) - gc->rast.img_4c4(PSRC, PDST(gc->dest), PCTM); + fz_img_4c4(PSRC, PDST(gc->dest), PCTM); else - gc->rast.img_1c1(PSRC, PDST(gc->dest), PCTM); + fz_img_1c1(PSRC, PDST(gc->dest), PCTM); } break; @@ -509,15 +489,15 @@ DEBUG(" fnone %d x %d\n", w, h); { DEBUG(" fover %d x %d\n", w, h); if (image->cs) - gc->rast.img_4o4(PSRC, PDST(gc->over), PCTM); + fz_img_4o4(PSRC, PDST(gc->over), PCTM); else - gc->rast.img_1o1(PSRC, PDST(gc->over), PCTM); + fz_img_1o1(PSRC, PDST(gc->over), PCTM); } break; case FOVER | FRGB: DEBUG(" fover+rgb %d x %d\n", w, h); - gc->rast.img_w3i1o4(gc->rgb, PSRC, PDST(gc->over), PCTM); + fz_img_w3i1o4(gc->rgb, PSRC, PDST(gc->over), PCTM); break; default: @@ -590,11 +570,11 @@ blendover(fz_renderer *gc, fz_pixmap *src, fz_pixmap *dst) dp = dst->samples + ((y - dst->y) * dst->w + (x - dst->x)) * dst->n; if (src->n == 1 && dst->n == 1) - gc->rast.duff_1o1(sp, src->w, dp, dst->w, w, h); + fz_duff_1o1(sp, src->w, dp, dst->w, w, h); else if (src->n == 4 && dst->n == 4) - gc->rast.duff_4o4(sp, src->w * 4, dp, dst->w * 4, w, h); + fz_duff_4o4(sp, src->w * 4, dp, dst->w * 4, w, h); else if (src->n == dst->n) - gc->rast.duff_NoN(sp, src->w * src->n, src->n, dp, dst->w * dst->n, w, h); + fz_duff_non(sp, src->w * src->n, src->n, dp, dst->w * dst->n, w, h); else assert(!"blendover src and dst mismatch"); } @@ -635,22 +615,22 @@ blendmask(fz_renderer *gc, fz_pixmap *src, fz_pixmap *msk, fz_pixmap *dst, int o if (over) { if (src->n == 1 && msk->n == 1 && dst->n == 1) - gc->rast.duff_1i1o1(sp, src->w, mp, msk->w, dp, dst->w, w, h); + 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) - gc->rast.duff_4i1o4(sp, src->w * 4, mp, msk->w, dp, dst->w * 4, w, h); + fz_duff_4i1o4(sp, src->w * 4, mp, msk->w, dp, dst->w * 4, w, h); else if (src->n == dst->n) - gc->rast.duff_NiMoN(sp, src->w * src->n, src->n, mp, msk->w * msk->n, msk->n, dp, dst->w * dst->n, w, h); + 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) - gc->rast.duff_1i1c1(sp, src->w, mp, msk->w, dp, dst->w, w, h); + 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) - gc->rast.duff_4i1c4(sp, src->w * 4, mp, msk->w, dp, dst->w * 4, w, h); + fz_duff_4i1c4(sp, src->w * 4, mp, msk->w, dp, dst->w * 4, w, h); else if (src->n == dst->n) - gc->rast.duff_NiMcN(sp, src->w * src->n, src->n, mp, msk->w * msk->n, msk->n, dp, dst->w * dst->n, w, h); + 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"); } diff --git a/render/scale.c b/render/scale.c deleted file mode 100644 index 01ebec2d..00000000 --- a/render/scale.c +++ /dev/null @@ -1,225 +0,0 @@ -#include - -/* TODO: these should go in fz_rastfuncs */ - -typedef void (*rowfunc)(unsigned char *src, unsigned char *dst, int w, int ncomp, int denom); -typedef void (*colfunc)(unsigned char *src, unsigned char *dst, int w, int ncomp, int denom); - -static void -scalerow(unsigned char *src, unsigned char *dst, int w, int ncomp, int denom) -{ - int x, left, k; - int sum[FZ_MAXCOLORS]; - - left = 0; - for (k = 0; k < ncomp; k++) - sum[k] = 0; - - for (x = 0; x < w; x++) - { - for (k = 0; k < ncomp; k++) - sum[k] += src[x * ncomp + k]; - if (++left == denom) - { - left = 0; - for (k = 0; k < ncomp; k++) - { - dst[k] = sum[k] / denom; - sum[k] = 0; - } - dst += ncomp; - } - } - - /* left overs */ - if (left) - for (k = 0; k < ncomp; k++) - dst[k] = sum[k] / left; -} - -static void -scalerow1(unsigned char *src, unsigned char *dst, int w, int ncomp, 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; - } - } - - /* left overs */ - if (left) - { - *dst++ = sum / left; - } -} - -static void -scalerow2(unsigned char *src, unsigned char *dst, int w, int ncomp, int denom) -{ - int x, left; - int sum0, sum1; - - left = 0; - sum0 = 0; - sum1 = 0; - - for (x = 0; x < w; x++) - { - sum0 += *src++; - sum1 += *src++; - if (++left == denom) - { - left = 0; - *dst++ = sum0 / denom; - *dst++ = sum1 / denom; - sum0 = 0; - sum1 = 0; - } - } - - /* left overs */ - if (left) - { - *dst++ = sum0 / left; - *dst++ = sum1 / left; - } -} - - -static void -scalecols(unsigned char *src, unsigned char *dst, int w, int ncomp, int denom) -{ - int x, y, k; - unsigned char *s; - int sum[FZ_MAXCOLORS]; - - for (x = 0; x < w; x++) - { - s = src + (x * ncomp); - for (k = 0; k < ncomp; k++) - sum[k] = 0; - for (y = 0; y < denom; y++) - for (k = 0; k < ncomp; k++) - sum[k] += s[y * w * ncomp + k]; - for (k = 0; k < ncomp; k++) - dst[k] = sum[k] / denom; - dst += ncomp; - } -} - -static void -scalecols1(unsigned char *src, unsigned char *dst, int w, int ncomp, 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; - } -} - -static void -scalecols2(unsigned char *src, unsigned char *dst, int w, int ncomp, int denom) -{ - int x, y; - unsigned char *s; - int sum0, sum1; - - for (x = 0; x < w; x++) - { - s = src + (x * 2); - sum0 = 0; - sum1 = 0; - for (y = 0; y < denom; y++) - { - sum0 += s[y * w * 2 + 0]; - sum1 += s[y * w * 2 + 1]; - } - *dst++ = sum0 / denom; - *dst++ = sum1 / denom; - } -} - -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; - rowfunc rowfunc; - colfunc colfunc; - - 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: - rowfunc = scalerow1; - colfunc = scalecols1; - break; - case 2: - rowfunc = scalerow2; - colfunc = scalecols2; - break; - default: - rowfunc = scalerow; - colfunc = scalecols; - break; - } - - for (y = 0, oy = 0; y < (src->h / ydenom) * ydenom; y += ydenom, oy++) - { - for (iy = 0; iy < ydenom; iy++) - rowfunc(src->samples + (y + iy) * src->w * n, - buf + iy * ow * n, - src->w, n, xdenom); - colfunc(buf, dst->samples + oy * dst->w * n, dst->w, n, ydenom); - } - - ydenom = src->h - y; - if (ydenom) - { - for (iy = 0; iy < ydenom; iy++) - rowfunc(src->samples + (y + iy) * src->w * n, - buf + iy * ow * n, - src->w, n, xdenom); - colfunc(buf, dst->samples + oy * dst->w * n, dst->w, n, ydenom); - } - - fz_free(buf); - *dstp = dst; - return nil; -} - diff --git a/render/scanconv.c b/render/scanconv.c deleted file mode 100644 index 662a4cdb..00000000 --- a/render/scanconv.c +++ /dev/null @@ -1,152 +0,0 @@ -#include - -static inline void -addspan(unsigned char *list, int x0, int x1, int xofs, int hs) -{ - int x0pix, x0sub; - int x1pix, x1sub; - - if (x0 == x1) - return; - - /* x between 0 and width of bbox */ - x0 -= xofs; - x1 -= xofs; - - x0pix = x0 / hs; - x0sub = x0 % hs; - x1pix = x1 / hs; - x1sub = x1 % hs; - - if (x0pix == x1pix) - { - list[x0pix] += x1sub - x0sub; - list[x0pix+1] += x0sub - x1sub; - } - - else - { - list[x0pix] += hs - x0sub; - list[x0pix+1] += x0sub; - list[x1pix] += x1sub - hs; - list[x1pix+1] += -x1sub; - } -} - -static inline void -nonzerowinding(fz_ael *ael, unsigned char *list, int xofs, int hs) -{ - 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, hs); - winding += ael->edges[i]->ydir; - } -} - -static inline void -evenodd(fz_ael *ael, unsigned char *list, int xofs, int hs) -{ - 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, hs); - even = !even; - } -} - -static void toalpha(unsigned char *list, int n) -{ - int d = 0; - while (n--) - { - d += *list; - *list++ = d; - } -} - -fz_error * -fz_scanconvert(fz_gel *gel, fz_ael *ael, int eofill, int y0, int y1, - void (*blitfunc)(int,int,int,unsigned char*,void*), void *blitdata) -{ - fz_error *error; - unsigned char *deltas; - int y, e; - int yd, yc; - - int xmin = fz_idiv(gel->xmin, gel->hs); - int xmax = fz_idiv(gel->xmax, gel->hs) + 1; - - int xofs = xmin * gel->hs; - int hs = gel->hs; - int vs = gel->vs; - - if (gel->len == 0) - return nil; - - 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, vs); - yd = yc; - - while (ael->len > 0 || e < gel->len) - { - yc = fz_idiv(y, vs); - if (yc != yd) { - if (yd >= y0 && yd < y1) - { - toalpha(deltas, xmax - xmin); - blitfunc(yd, xmin, xmax - xmin, deltas, blitdata); - memset(deltas, 0, xmax - xmin + 1); - } - } - yd = yc; - - error = fz_insertael(ael, gel, y, &e); - if (error) { - fz_free(deltas); - return error; - } - - if (yd >= y0 && yd < y1) - { - if (eofill) - evenodd(ael, deltas, xofs, hs); - else - nonzerowinding(ael, deltas, xofs, hs); - } - - fz_advanceael(ael); - - if (ael->len > 0) - y ++; - else if (e < gel->len) - y = gel->edges[e].y; - } - - if (yd >= y0 && yd < y1) - { - toalpha(deltas, xmax - xmin); - blitfunc(yd, xmin, xmax - xmin, deltas, blitdata); - } - - fz_free(deltas); - return nil; -} - diff --git a/render/stroke.c b/render/stroke.c deleted file mode 100644 index 2527e6ad..00000000 --- a/render/stroke.c +++ /dev/null @@ -1,725 +0,0 @@ -#include - -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 nil; -} - -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 nil; -} - -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 nil; - if (dx1 * dx1 + dy1 * dy1 < FLT_EPSILON) - return nil; - - 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 nil; -} - -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 nil; -} - -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 nil; -} - -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 nil; -} - -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 nil; -} - -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 nil; - } - - 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 nil; -} - -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 nil; -} - -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) -{ - 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 = path->linewidth * 0.5; - s.miterlimit = path->miterlimit; - s.sn = 0; - s.bn = 0; - s.dot = 0; - - i = 0; - - 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 nil; -} - -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 nil; -} - -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) -{ - 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 = path->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; - - 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/test/pdfrip.c b/test/pdfrip.c index f5f762da..6e3f6bef 100644 --- a/test/pdfrip.c +++ b/test/pdfrip.c @@ -87,6 +87,9 @@ int main(int argc, char **argv) char *password = ""; + fz_cpudetect(); + fz_accelerate(); + while ((c = getopt(argc, argv, "dz:p:")) != -1) { switch (c) diff --git a/test/x11pdf.c b/test/x11pdf.c index 46e95632..88aebe47 100644 --- a/test/x11pdf.c +++ b/test/x11pdf.c @@ -242,6 +242,8 @@ static void dumptext() fz_error *error; pdf_textline *line; + printf("----"); + error = pdf_loadtextfromtree(&line, page->tree); if (error) fz_abort(error); @@ -363,6 +365,7 @@ int main(int argc, char **argv) usage(); fz_cpudetect(); + fz_accelerate(); filename = argv[optind++]; diff --git a/test/ximage.c b/test/ximage.c index 3b4a9b8b..1e56fa2e 100644 --- a/test/ximage.c +++ b/test/ximage.c @@ -20,9 +20,9 @@ typedef void (*ximage_convert_func_t) int h ); -#define POOLSIZE 6 +#define POOLSIZE 4 #define WIDTH 256 -#define HEIGHT 64 +#define HEIGHT 256 enum { ARGB8888, diff --git a/tree/optimize.c b/tree/optimize.c index b65a37ca..cbb9ad31 100644 --- a/tree/optimize.c +++ b/tree/optimize.c @@ -181,6 +181,14 @@ retry: 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)) -- cgit v1.2.3