diff options
author | Tor Andersson <tor.andersson@artifex.com> | 2011-04-04 17:44:27 +0200 |
---|---|---|
committer | Tor Andersson <tor.andersson@artifex.com> | 2011-04-04 17:44:27 +0200 |
commit | 6a87014ff020538841d7f5a0dd1adef8a6ce9e79 (patch) | |
tree | a98e917471df377a3e2ef852652ebb1535bec0be | |
parent | e77893b29cf53a9d6933cab0f9ae9e78b30a6592 (diff) | |
download | mupdf-6a87014ff020538841d7f5a0dd1adef8a6ce9e79.tar.xz |
Add device interface functions to draw tiled patterns.
-rw-r--r-- | draw/porterduff.c | 30 | ||||
-rw-r--r-- | fitz/dev_draw.c | 82 | ||||
-rw-r--r-- | fitz/dev_list.c | 55 | ||||
-rw-r--r-- | fitz/dev_null.c | 5 | ||||
-rw-r--r-- | fitz/dev_trace.c | 20 | ||||
-rw-r--r-- | fitz/fitz.h | 6 | ||||
-rw-r--r-- | mupdf/pdf_build.c | 56 | ||||
-rw-r--r-- | xps/xps_tile.c | 13 |
8 files changed, 246 insertions, 21 deletions
diff --git a/draw/porterduff.c b/draw/porterduff.c index b8130ab6..69df467a 100644 --- a/draw/porterduff.c +++ b/draw/porterduff.c @@ -347,6 +347,36 @@ fz_paintspan(byte * restrict dp, byte * restrict sp, int n, int w, int alpha) */ void +fz_paintpixmapbbox(fz_pixmap *dst, fz_pixmap *src, int alpha, fz_bbox bbox) +{ + unsigned char *sp, *dp; + int x, y, w, h, n; + + assert(dst->n == src->n); + + bbox = fz_intersectbbox(bbox, fz_boundpixmap(dst)); + bbox = fz_intersectbbox(bbox, fz_boundpixmap(src)); + + x = bbox.x0; + y = bbox.y0; + w = bbox.x1 - bbox.x0; + h = bbox.y1 - bbox.y0; + if ((w | h) == 0) + return; + + n = src->n; + sp = src->samples + ((y - src->y) * src->w + (x - src->x)) * src->n; + dp = dst->samples + ((y - dst->y) * dst->w + (x - dst->x)) * dst->n; + + while (h--) + { + fz_paintspan(dp, sp, n, w, alpha); + sp += src->w * n; + dp += dst->w * n; + } +} + +void fz_paintpixmap(fz_pixmap *dst, fz_pixmap *src, int alpha) { unsigned char *sp, *dp; diff --git a/fitz/dev_draw.c b/fitz/dev_draw.c index e0a12492..fb8c4c72 100644 --- a/fitz/dev_draw.c +++ b/fitz/dev_draw.c @@ -27,6 +27,9 @@ struct fz_drawdevice_s fz_blendmode blendmode; int luminosity; float alpha; + fz_matrix ctm; + float xstep, ystep; + fz_rect area; } stack[STACKSIZE]; }; @@ -928,6 +931,82 @@ fz_drawendgroup(void *user) } static void +fz_drawbegintile(void *user, fz_rect area, fz_rect view, float xstep, float ystep, fz_matrix ctm) +{ + fz_drawdevice *dev = user; + fz_colorspace *model = dev->dest->colorspace; + fz_pixmap *dest; + fz_bbox bbox; + + /* area, view, xstep, ystep are in pattern space */ + /* ctm maps from pattern space to device space */ + + if (dev->top == STACKSIZE) + { + fz_warn("assert: too many buffers on stack"); + return; + } + + bbox = fz_roundrect(fz_transformrect(ctm, view)); + dest = fz_newpixmapwithrect(model, bbox); + fz_clearpixmap(dest); + + dev->stack[dev->top].scissor = dev->scissor; + dev->stack[dev->top].dest = dev->dest; + dev->stack[dev->top].xstep = xstep; + dev->stack[dev->top].ystep = ystep; + dev->stack[dev->top].area = area; + dev->stack[dev->top].ctm = ctm; + dev->top++; + + dev->scissor = bbox; + dev->dest = dest; +} + +static void +fz_drawendtile(void *user) +{ + fz_drawdevice *dev = user; + fz_pixmap *tile = dev->dest; + float xstep, ystep; + fz_matrix ctm, ttm; + fz_rect area; + int x0, y0, x1, y1, x, y; + + if (dev->top > 0) + { + dev->top--; + xstep = dev->stack[dev->top].xstep; + ystep = dev->stack[dev->top].ystep; + area = dev->stack[dev->top].area; + ctm = dev->stack[dev->top].ctm; + dev->scissor = dev->stack[dev->top].scissor; + dev->dest = dev->stack[dev->top].dest; + + x0 = floorf(area.x0 / xstep); + y0 = floorf(area.y0 / ystep); + x1 = ceilf(area.x1 / xstep); + y1 = ceilf(area.y1 / ystep); + + ctm.e = tile->x; + ctm.f = tile->y; + + for (y = y0; y < y1; y++) + { + for (x = x0; x < x1; x++) + { + ttm = fz_concat(fz_translate(x * xstep, y * ystep), ctm); + tile->x = roundf(ttm.e); + tile->y = roundf(ttm.f); + fz_paintpixmapbbox(dev->dest, tile, 255, dev->scissor); + } + } + + fz_droppixmap(tile); + } +} + +static void fz_drawfreeuser(void *user) { fz_drawdevice *dev = user; @@ -979,5 +1058,8 @@ fz_newdrawdevice(fz_glyphcache *cache, fz_pixmap *dest) dev->begingroup = fz_drawbegingroup; dev->endgroup = fz_drawendgroup; + dev->begintile = fz_drawbegintile; + dev->endtile = fz_drawendtile; + return dev; } diff --git a/fitz/dev_list.c b/fitz/dev_list.c index bfa4ddf1..2bba6ed3 100644 --- a/fitz/dev_list.c +++ b/fitz/dev_list.c @@ -90,6 +90,8 @@ fz_freedisplaynode(fz_displaynode *node) case FZ_CMDENDMASK: case FZ_CMDBEGINGROUP: case FZ_CMDENDGROUP: + case FZ_CMDBEGINTILE: + case FZ_CMDENDTILE: break; } if (node->stroke) @@ -291,6 +293,29 @@ fz_listendgroup(void *user) fz_appenddisplaynode(user, node); } +static void +fz_listbegintile(void *user, fz_rect area, fz_rect view, float xstep, float ystep, fz_matrix ctm) +{ + fz_displaynode *node; + node = fz_newdisplaynode(FZ_CMDBEGINTILE, ctm, nil, nil, 0); + node->rect = area; + node->color[0] = xstep; + node->color[1] = ystep; + node->color[2] = view.x0; + node->color[3] = view.y0; + node->color[4] = view.x1; + node->color[5] = view.y1; + fz_appenddisplaynode(user, node); +} + +static void +fz_listendtile(void *user) +{ + fz_displaynode *node; + node = fz_newdisplaynode(FZ_CMDENDTILE, fz_identity, nil, nil, 0); + fz_appenddisplaynode(user, node); +} + fz_device * fz_newlistdevice(fz_displaylist *list) { @@ -319,6 +344,9 @@ fz_newlistdevice(fz_displaylist *list) dev->begingroup = fz_listbegingroup; dev->endgroup = fz_listendgroup; + dev->begintile = fz_listbegintile; + dev->endtile = fz_listendtile; + return dev; } @@ -350,6 +378,7 @@ fz_executedisplaylist(fz_displaylist *list, fz_device *dev, fz_matrix topctm, fz fz_displaynode *node; fz_rect bbox; int clipped = 0; + int tiled = 0; if (!fz_isinfinitebbox(bounds)) { @@ -364,11 +393,21 @@ fz_executedisplaylist(fz_displaylist *list, fz_device *dev, fz_matrix topctm, fz fz_matrix ctm = fz_concat(node->ctm, topctm); fz_rect rect = fz_transformrect(topctm, node->rect); + /* never skip tiles */ + if (tiled) + goto visible; + /* cull objects to draw using a quick visibility test */ if (clipped || fz_isemptybbox(fz_intersectbbox(fz_roundrect(rect), bounds))) { switch (node->cmd) { + case FZ_CMDBEGINTILE: + tiled++; + goto visible; + case FZ_CMDENDTILE: + tiled--; + goto visible; case FZ_CMDCLIPPATH: case FZ_CMDCLIPSTROKEPATH: case FZ_CMDCLIPTEXT: @@ -381,18 +420,19 @@ fz_executedisplaylist(fz_displaylist *list, fz_device *dev, fz_matrix topctm, fz case FZ_CMDPOPCLIP: case FZ_CMDENDGROUP: if (!clipped) - break; + goto visible; clipped--; continue; case FZ_CMDENDMASK: if (!clipped) - break; + goto visible; continue; default: continue; } } +visible: switch (node->cmd) { case FZ_CMDFILLPATH: @@ -458,6 +498,17 @@ fz_executedisplaylist(fz_displaylist *list, fz_device *dev, fz_matrix topctm, fz case FZ_CMDENDGROUP: dev->endgroup(dev->user); break; + case FZ_CMDBEGINTILE: + bbox.x0 = node->color[2]; + bbox.y0 = node->color[3]; + bbox.x1 = node->color[4]; + bbox.y1 = node->color[5]; + dev->begintile(dev->user, node->rect, bbox, + node->color[0], node->color[1], ctm); + break; + case FZ_CMDENDTILE: + dev->endtile(dev->user); + break; } } } diff --git a/fitz/dev_null.c b/fitz/dev_null.c index 7c80b0ff..2d20a966 100644 --- a/fitz/dev_null.c +++ b/fitz/dev_null.c @@ -19,6 +19,8 @@ static void fz_nullbeginmask(void *user, fz_rect r, int luminosity, fz_colorspac static void fz_nullendmask(void *user) {} static void fz_nullbegingroup(void *user, fz_rect r, int isolated, int knockout, fz_blendmode blendmode, float alpha) {} static void fz_nullendgroup(void *user) {} +static void fz_nullbegintile(void *user, fz_rect area, fz_rect view, float xstep, float ystep, fz_matrix ctm) {} +static void fz_nullendtile(void *user) {} fz_device * fz_newdevice(void *user) @@ -54,6 +56,9 @@ fz_newdevice(void *user) dev->begingroup = fz_nullbegingroup; dev->endgroup = fz_nullendgroup; + dev->begintile = fz_nullbegintile; + dev->endtile = fz_nullendtile; + return dev; } diff --git a/fitz/dev_trace.c b/fitz/dev_trace.c index 50ba02f3..f8a94b43 100644 --- a/fitz/dev_trace.c +++ b/fitz/dev_trace.c @@ -253,6 +253,23 @@ fz_traceendgroup(void *user) printf("</group>\n"); } +static void +fz_tracebegintile(void *user, fz_rect area, fz_rect view, float xstep, float ystep, fz_matrix ctm) +{ + printf("<tile "); + printf("area=\"%g %g %g %g\" ", area.x0, area.y0, area.x1, area.y1); + printf("view=\"%g %g %g %g\" ", view.x0, view.y0, view.x1, view.y1); + printf("xstep=\"%g\" ystep=\"%g\" ", xstep, ystep); + fz_tracematrix(ctm); + printf(">\n"); +} + +static void +fz_traceendtile(void *user) +{ + printf("</tile>\n"); +} + fz_device *fz_newtracedevice(void) { fz_device *dev = fz_newdevice(nil); @@ -280,5 +297,8 @@ fz_device *fz_newtracedevice(void) dev->begingroup = fz_tracebegingroup; dev->endgroup = fz_traceendgroup; + dev->begintile = fz_tracebegintile; + dev->endtile = fz_traceendtile; + return dev; } diff --git a/fitz/fitz.h b/fitz/fitz.h index 4a91c90d..9af91a3f 100644 --- a/fitz/fitz.h +++ b/fitz/fitz.h @@ -1026,6 +1026,9 @@ struct fz_device_s void (*endmask)(void *); void (*begingroup)(void *, fz_rect, int isolated, int knockout, fz_blendmode blendmode, float alpha); void (*endgroup)(void *); + + void (*begintile)(void *, fz_rect area, fz_rect view, float xstep, float ystep, fz_matrix ctm); + void (*endtile)(void *); }; fz_device *fz_newdevice(void *user); @@ -1095,6 +1098,8 @@ typedef enum fz_displaycommand_e FZ_CMDENDMASK, FZ_CMDBEGINGROUP, FZ_CMDENDGROUP, + FZ_CMDBEGINTILE, + FZ_CMDENDTILE } fz_displaycommand; struct fz_displaynode_s @@ -1194,6 +1199,7 @@ void fz_paintimagecolor(fz_pixmap *dst, fz_bbox scissor, fz_pixmap *img, fz_matr void fz_paintpixmap(fz_pixmap *dst, fz_pixmap *src, int alpha); void fz_paintpixmapmask(fz_pixmap *dst, fz_pixmap *src, fz_pixmap *msk); +void fz_paintpixmapbbox(fz_pixmap *dst, fz_pixmap *src, int alpha, fz_bbox bbox); void fz_blendpixmap(fz_pixmap *dst, fz_pixmap *src, int alpha, fz_blendmode blendmode); diff --git a/mupdf/pdf_build.c b/mupdf/pdf_build.c index 4e19db92..616f1c86 100644 --- a/mupdf/pdf_build.c +++ b/mupdf/pdf_build.c @@ -1,6 +1,8 @@ #include "fitz.h" #include "mupdf.h" +#define TILE + void pdf_initgstate(pdf_gstate *gs, fz_matrix ctm) { @@ -150,13 +152,13 @@ pdf_setshade(pdf_csi *csi, int what, fz_shade *shade) } static void -pdf_showpattern(pdf_csi *csi, pdf_pattern *pat, fz_rect bbox, int what) +pdf_showpattern(pdf_csi *csi, pdf_pattern *pat, fz_rect area, int what) { pdf_gstate *gstate; fz_matrix ptm, invptm; fz_matrix oldtopctm; fz_error error; - int x, y, x0, y0, x1, y1; + int x0, y0, x1, y1; int oldtop; pdf_gsave(csi); @@ -197,33 +199,51 @@ pdf_showpattern(pdf_csi *csi, pdf_pattern *pat, fz_rect bbox, int what) /* patterns are painted using the ctm in effect at the beginning of the content stream */ /* get bbox of shape in pattern space for stamping */ - bbox = fz_transformrect(invptm, bbox); - x0 = floorf(bbox.x0 / pat->xstep); - y0 = floorf(bbox.y0 / pat->ystep); - x1 = ceilf(bbox.x1 / pat->xstep); - y1 = ceilf(bbox.y1 / pat->ystep); + area = fz_transformrect(invptm, area); + x0 = floorf(area.x0 / pat->xstep); + y0 = floorf(area.y0 / pat->ystep); + x1 = ceilf(area.x1 / pat->xstep); + y1 = ceilf(area.y1 / pat->ystep); oldtopctm = csi->topctm; oldtop = csi->gtop; - for (y = y0; y < y1; y++) +#ifdef TILE + if ((x1 - x0) * (y1 - y0) > 0) + { + csi->dev->begintile(csi->dev->user, area, pat->bbox, pat->xstep, pat->ystep, ptm); + gstate->ctm = ptm; + csi->topctm = gstate->ctm; + error = pdf_runcsibuffer(csi, pat->resources, pat->contents); + if (error) + fz_catch(error, "cannot render pattern tile"); + while (oldtop < csi->gtop) + pdf_grestore(csi); + csi->dev->endtile(csi->dev->user); + } +#else { - for (x = x0; x < x1; x++) + int x, y; + for (y = y0; y < y1; y++) { - gstate->ctm = fz_concat(fz_translate(x * pat->xstep, y * pat->ystep), ptm); - csi->topctm = gstate->ctm; - error = pdf_runcsibuffer(csi, pat->resources, pat->contents); - while (oldtop < csi->gtop) - pdf_grestore(csi); - if (error) + for (x = x0; x < x1; x++) { - fz_catch(error, "cannot render pattern tile"); - goto cleanup; + gstate->ctm = fz_concat(fz_translate(x * pat->xstep, y * pat->ystep), ptm); + csi->topctm = gstate->ctm; + error = pdf_runcsibuffer(csi, pat->resources, pat->contents); + while (oldtop < csi->gtop) + pdf_grestore(csi); + if (error) + { + fz_catch(error, "cannot render pattern tile"); + goto cleanup; + } } } } - cleanup: +#endif + csi->topctm = oldtopctm; pdf_grestore(csi); diff --git a/xps/xps_tile.c b/xps/xps_tile.c index 2ddc190e..0f9c6c89 100644 --- a/xps/xps_tile.c +++ b/xps/xps_tile.c @@ -1,6 +1,8 @@ #include "fitz.h" #include "muxps.h" +#define TILE + /* * Parse a tiling brush (visual and image brushes at this time) common * properties. Use the callback to draw the individual tiles. @@ -171,8 +173,16 @@ xps_parse_tiling_brush(xps_context *ctx, fz_matrix ctm, fz_rect area, int y0 = floorf(bbox.y0 / ystep); int x1 = ceilf(bbox.x1 / xstep); int y1 = ceilf(bbox.y1 / ystep); +#ifdef TILE + int ntile = (x1 - x0) * (y1 - y0); + if (ntile > 1) + ctx->dev->begintile(ctx->dev->user, bbox, viewbox, xstep, ystep, ctm); + if (ntile > 0) + xps_paint_tiling_brush(ctx, ctm, viewbox, tile_mode, &c); + if (ntile > 1) + ctx->dev->endtile(ctx->dev->user); +#else int x, y; - for (y = y0; y < y1; y++) { for (x = x0; x < x1; x++) @@ -181,6 +191,7 @@ xps_parse_tiling_brush(xps_context *ctx, fz_matrix ctm, fz_rect area, xps_paint_tiling_brush(ctx, ttm, viewbox, tile_mode, &c); } } +#endif } else { |