diff options
Diffstat (limited to 'render/render.c')
-rw-r--r-- | render/render.c | 511 |
1 files changed, 381 insertions, 130 deletions
diff --git a/render/render.c b/render/render.c index 62bce18d..672f312f 100644 --- a/render/render.c +++ b/render/render.c @@ -1,30 +1,27 @@ #include <fitz.h> -fz_error *fz_rendercolortext(fz_renderer*, fz_textnode*, fz_colornode*, fz_matrix); -fz_error *fz_rendercolorpath(fz_renderer*, fz_pathnode*, fz_colornode*, fz_matrix); -fz_error *fz_rendertext(fz_renderer*, fz_textnode*, fz_matrix); -fz_error *fz_renderpath(fz_renderer*, fz_pathnode*, fz_matrix); +#define FNONE 0 +#define FOVER 1 +#define FMASK 2 +#define FRGB 4 -fz_error *fz_rendercolorimage(fz_renderer*, fz_imagenode*, fz_colornode*, fz_matrix); -fz_error *fz_renderimage(fz_renderer*, fz_imagenode*, fz_matrix); +static fz_error *rendernode(fz_renderer *gc, fz_node *node, fz_matrix ctm); fz_error * -fz_newrenderer(fz_renderer **gcp, fz_colorspace *processcolormodel, int gcmem) +fz_newrenderer(fz_renderer **gcp, fz_colorspace *pcm, int maskonly, int gcmem) { fz_error *error; fz_renderer *gc; - gc = *gcp = fz_malloc(sizeof(fz_renderer)); + gc = fz_malloc(sizeof(fz_renderer)); if (!gc) return fz_outofmem; - gc->model = processcolormodel; + gc->maskonly = maskonly; + gc->model = pcm; gc->cache = nil; gc->gel = nil; gc->ael = nil; - gc->tmp = nil; - gc->acc = nil; - gc->hasrgb = 0; error = fz_newglyphcache(&gc->cache, gcmem / 32, gcmem); if (error) @@ -38,230 +35,483 @@ fz_newrenderer(fz_renderer **gcp, fz_colorspace *processcolormodel, int gcmem) if (error) goto cleanup; + fz_defaultrastfuncs(&gc->rast); + + gc->dest = nil; + gc->mask = nil; + gc->over = nil; + gc->rgb[0] = 0; + gc->rgb[1] = 0; + gc->rgb[2] = 0; + gc->flag = 0; + + *gcp = gc; return nil; cleanup: - if (gc->cache) - fz_dropglyphcache(gc->cache); - if (gc->gel) - fz_dropgel(gc->gel); - if (gc->ael) - fz_dropael(gc->ael); + if (gc->model) fz_dropcolorspace(gc->model); + if (gc->cache) fz_dropglyphcache(gc->cache); + if (gc->gel) fz_dropgel(gc->gel); + if (gc->ael) fz_dropael(gc->ael); fz_free(gc); - return error; } void fz_droprenderer(fz_renderer *gc) { - if (gc->cache) - fz_dropglyphcache(gc->cache); - if (gc->gel) - fz_dropgel(gc->gel); - if (gc->ael) - fz_dropael(gc->ael); - if (gc->tmp) - fz_droppixmap(gc->tmp); - if (gc->acc) - fz_droppixmap(gc->acc); + if (gc->dest) fz_droppixmap(gc->dest); + if (gc->mask) fz_droppixmap(gc->mask); + if (gc->over) fz_droppixmap(gc->over); + + if (gc->model) fz_dropcolorspace(gc->model); + if (gc->cache) fz_dropglyphcache(gc->cache); + if (gc->gel) fz_dropgel(gc->gel); + if (gc->ael) fz_dropael(gc->ael); fz_free(gc); } -fz_error * -fz_rendercolor(fz_renderer *gc, fz_colornode *color, fz_matrix ctm) +/* + * Transform + */ + +static fz_error * +rendertransform(fz_renderer *gc, fz_transformnode *transform, fz_matrix ctm) +{ + fz_error *error; +printf("transform [%g %g %g %g %g %g]\n", +transform->m.a, transform->m.b, +transform->m.c, transform->m.d, +transform->m.e, transform->m.f); +puts("{"); + ctm = fz_concat(transform->m, ctm); + error = rendernode(gc, transform->super.first, ctm); +puts("}"); + return error; +} + +/* + * Color + */ + +static fz_error * +rendercolor(fz_renderer *gc, fz_colornode *color, fz_matrix ctm) { fz_error *error; - int x, y, w, h; float rgb[3]; unsigned char *p; + int n; - assert(gc->model); + if (gc->maskonly) + return fz_throw("assert: mask only renderer"); + if (gc->model->n != 3) + return fz_throw("assert: non-rgb renderer"); fz_convertcolor(color->cs, color->samples, gc->model, rgb); - gc->r = rgb[0] * 255; - gc->g = rgb[1] * 255; - gc->b = rgb[2] * 255; + gc->rgb[0] = rgb[0] * 255; + gc->rgb[1] = rgb[1] * 255; + gc->rgb[2] = rgb[2] * 255; - x = gc->clip.min.x; - y = gc->clip.min.y; - w = gc->clip.max.x - gc->clip.min.x; - h = gc->clip.max.y - gc->clip.min.y; +printf("color %s [%d %d %d]\n", color->cs->name, gc->rgb[0], gc->rgb[1], gc->rgb[2]); - error = fz_newpixmap(&gc->tmp, x, y, w, h, 4); + error = fz_newpixmapwithrect(&gc->dest, gc->clip, 4); if (error) return error; - p = gc->tmp->samples; + p = gc->dest->samples; + n = gc->dest->w * gc->dest->h; + + while (n--) + { + p[0] = 255; + p[1] = gc->rgb[0]; + p[2] = gc->rgb[1]; + p[3] = gc->rgb[2]; + p += 4; + } + + return nil; +} + +/* + * Path + */ + +enum { HS = 17, VS = 15, SF = 1 }; + +struct spandata +{ + fz_rastfuncs *rast; + int x, n; + fz_pixmap *dst; + fz_pixmap *msk; + unsigned char *rgb; + int flag; +}; + +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; + fz_pixmap *msk = user->msk; + unsigned char *d; + unsigned char *m = nil; - for (y = 0; y < gc->tmp->h; y++) + path += user->x; + + d = dst->samples + ( (y - dst->y) * dst->w + (x - dst->x) ) * dst->n; + if (msk) + m = msk->samples + ( (y - msk->y) * msk->w + (x - msk->x) ) * msk->n; + + switch (user->flag) { - for (x = 0; x < gc->tmp->w; x++) + case FNONE: + rast->mask_g(user->n, path, d); break; + case FOVER: + rast->mask_o1(user->n, path, d); break; + case FOVER | FMASK: + rast->mask_i1o1(user->n, path, m, d); break; + case FOVER | FRGB: + rast->mask_o4w3(user->n, path, d, user->rgb); break; + case FOVER | FMASK | FRGB: + rast->mask_i1o4w3(user->n, path, m, d, user->rgb); break; + default: + assert(!"impossible flag in path span function"); + } +} + +static fz_error * +renderpath(fz_renderer *gc, fz_pathnode *path, fz_matrix ctm) +{ + struct spandata user; + fz_error *error; + float flatness; + fz_irect gbox; + fz_irect clip; + + flatness = 0.3 / fz_matrixexpansion(ctm); + if (flatness < 0.1) + flatness = 0.1; + + fz_resetgel(gc->gel, HS, VS); + + if (path->paint == FZ_STROKE) + { + if (path->dash) + error = fz_dashpath(gc->gel, path, ctm, flatness); + else + error = fz_strokepath(gc->gel, path, ctm, flatness); + } + else + error = fz_fillpath(gc->gel, path, ctm, flatness); + if (error) + return error; + + fz_sortgel(gc->gel); + + gbox = fz_boundgel(gc->gel); + clip = fz_intersectirects(gc->clip, gbox); + +//printf("path clip[%d %d %d %d]\n", clip.min.x, clip.min.y, clip.max.x, clip.max.y); + + user.rast = &gc->rast; + user.x = clip.min.x - gbox.min.x; + user.n = clip.max.x - clip.min.x; + user.flag = gc->flag; + + if (gc->flag == FNONE) + { + error = fz_newpixmapwithrect(&gc->dest, clip, 1); + if (error) + return error; + fz_clearpixmap(gc->dest); + user.dst = gc->dest; + user.msk = nil; + user.rgb = gc->rgb; + } + else + { + user.dst = gc->over; + user.msk = gc->mask; + user.rgb = gc->rgb; + } + + error = fz_scanconvert(gc->gel, gc->ael, path->paint == FZ_EOFILL, + clip.min.y, clip.max.y, spanfunc, &user); + if (error) + return error; + + return nil; +} + +/* + * Text + */ + +static void copyglyph(fz_renderer *gc, fz_pixmap *dst, fz_glyph *src, int xorig, int yorig) +{ + int x, y; + + xorig += src->x; + yorig += src->y; + + for (y = 0; y < src->h; y++) + for (x = 0; x < src->w; x++) { - *p++ = 255; - *p++ = gc->r; - *p++ = gc->g; - *p++ = gc->b; + int dx = xorig + x - dst->x; + int dy = yorig + y - dst->y; + + if (dx < 0) {puts("dx<0");continue;} + if (dy < 0) {puts("dy<0");continue;} + if (dx >= dst->w) {puts("dx>w");continue;} + if (dy >= dst->h) {puts("dy>h");continue;} + + int a = src->bitmap[x + y * src->w]; + int b = dst->samples[dx + dy * dst->w]; + int c = a + fz_mul255(b, 255 - a); + dst->samples[dx + dy * dst->w] = a; } +} + +static fz_error * +rendertext(fz_renderer *gc, fz_textnode *text, fz_matrix ctm) +{ + fz_error *error; + fz_irect tbox; + fz_irect clip; + fz_matrix tm, trm; + fz_glyph glyph; + int i, x, y, cid; + + tbox = fz_roundrect(fz_boundnode((fz_node*)text, ctm)); + clip = fz_intersectirects(gc->clip, tbox); + +printf("text %s n=%d [%g %g %g %g] clip[%d %d %d %d]\n", + text->font->name, text->len, + text->trm.a, text->trm.b, text->trm.c, text->trm.d, + clip.min.x, clip.min.y, clip.max.x, clip.max.y); +fflush(stdout); + + clip.min.x ++; + clip.min.y ++; + clip.max.x ++; + clip.max.y ++; + + error = fz_newpixmapwithrect(&gc->dest, clip, 1); + if (error) + return error; + + fz_clearpixmap(gc->dest); + + tm = text->trm; + + for (i = 0; i < text->len; i++) + { + cid = text->els[i].cid; + tm.e = text->els[i].x; + tm.f = text->els[i].y; + trm = fz_concat(tm, ctm); + x = fz_floor(trm.e); + y = fz_floor(trm.f); + trm.e = (trm.e - fz_floor(trm.e)); + trm.f = (trm.f - fz_floor(trm.f)); + + error = fz_renderglyph(gc->cache, &glyph, text->font, cid, trm); + if (error) + return error; + + copyglyph(gc, gc->dest, &glyph, x, y); } return nil; } -fz_error * -fz_renderover(fz_renderer *gc, fz_overnode *over, fz_matrix ctm) +/* + * Image + */ + +static fz_error * +renderimage(fz_renderer *gc, fz_imagenode *image, fz_matrix ctm) +{ + return nil; +} + +/* + * Over, Mask and Blend + */ + +static fz_error * +renderover(fz_renderer *gc, fz_overnode *over, fz_matrix ctm) { fz_error *error; fz_node *child; int cluster = 0;; - if (!gc->acc) - { - int x = gc->clip.min.x; - int y = gc->clip.min.y; - int w = gc->clip.max.x - gc->clip.min.x; - int h = gc->clip.max.y - gc->clip.min.y; +printf("over\n{\n"); - error = fz_newpixmap(&gc->acc, x, y, w, h, gc->model ? 4 : 1); + if (!gc->over) + { +printf(" alloc dest!\n"); + error = fz_newpixmapwithrect(&gc->over, gc->clip, gc->maskonly ? 1 : 4); if (error) return error; - - fz_clearpixmap(gc->acc); - + fz_clearpixmap(gc->over); cluster = 1; } for (child = over->super.first; child; child = child->next) { - error = fz_rendernode(gc, child, ctm); + error = rendernode(gc, child, ctm); if (error) return error; - - if (gc->tmp) + if (gc->dest) { - fz_blendover(gc->tmp, gc->acc); - fz_droppixmap(gc->tmp); - gc->tmp = nil; + fz_blendover(gc->dest, gc->over); + fz_droppixmap(gc->dest); + gc->dest = nil; } } if (cluster) { - gc->tmp = gc->acc; - gc->acc = nil; + gc->dest = gc->over; + gc->over = nil; } +printf("}\n"); + return nil; } -fz_error * -fz_rendermask(fz_renderer *gc, fz_masknode *mask, fz_matrix ctm) +static fz_error * +rendermask(fz_renderer *gc, fz_masknode *mask, fz_matrix ctm) { fz_error *error; - fz_pixmap *oldacc; - fz_pixmap *colorpix; + fz_pixmap *oldover; + fz_pixmap *oldmask; + fz_irect oldclip; + fz_irect newclip; fz_pixmap *shapepix; - fz_node *color; + fz_pixmap *colorpix; fz_node *shape; - fz_irect newclip; - fz_irect oldclip; - int x, y, w, h; + fz_node *color; + float rgb[3]; shape = mask->super.first; color = shape->next; - if (gc->acc) + /* special case black voodo */ + if (gc->flag & FOVER) { - if (fz_ispathnode(shape) && fz_iscolornode(color)) - return fz_rendercolorpath(gc, (fz_pathnode*)shape, (fz_colornode*)color, ctm); - if (fz_istextnode(shape) && fz_iscolornode(color)) - return fz_rendercolortext(gc, (fz_textnode*)shape, (fz_colornode*)color, ctm); - if (fz_isimagenode(shape) && fz_iscolornode(color)) - return fz_rendercolorimage(gc, (fz_imagenode*)shape, (fz_colornode*)color, ctm); + if (fz_iscolornode(color)) + { + fz_colornode *colorn = (fz_colornode*)color; + + fz_convertcolor(colorn->cs, colorn->samples, gc->model, rgb); + gc->rgb[0] = rgb[0] * 255; + gc->rgb[1] = rgb[1] * 255; + gc->rgb[2] = rgb[2] * 255; + gc->flag |= FRGB; + + /* we know these handle FOVER | FRGB */ + if (fz_ispathnode(shape)) + return renderpath(gc, (fz_pathnode*)shape, ctm); + if (fz_istextnode(shape)) + return rendertext(gc, (fz_textnode*)shape, ctm); + if (fz_isimagenode(shape)) + return renderimage(gc, (fz_imagenode*)shape, ctm); + } } - oldacc = gc->acc; oldclip = gc->clip; + oldover = gc->over; + oldmask = gc->mask; + newclip = fz_roundrect(fz_boundnode(shape, ctm)); newclip = fz_intersectirects(newclip, gc->clip); - gc->acc = nil; gc->clip = newclip; + gc->over = nil; + gc->mask = nil; - gc->tmp = nil; - error = fz_rendernode(gc, color, ctm); +printf("mask\n{\n"); + + error = rendernode(gc, color, ctm); if (error) return error; - colorpix = gc->tmp; + colorpix = gc->dest; + gc->dest = nil; - gc->tmp = nil; - error = fz_rendernode(gc, shape, ctm); + error = rendernode(gc, shape, ctm); if (error) return error; - shapepix = gc->tmp; - - x = gc->clip.min.x; - y = gc->clip.min.y; - w = gc->clip.max.x - gc->clip.min.x; - h = gc->clip.max.y - gc->clip.min.y; + shapepix = gc->dest; + gc->dest = nil; - error = fz_newpixmap(&gc->tmp, x, y, w, h, colorpix->n); + error = fz_newpixmapwithrect(&gc->dest, gc->clip, colorpix->n); if (error) return error; - fz_clearpixmap(gc->tmp); + fz_clearpixmap(gc->dest); + + fz_blendmask(gc->dest, colorpix, shapepix); - fz_blendmask(gc->tmp, colorpix, shapepix); +//fz_debugpixmap(gc->dest);getchar(); fz_droppixmap(shapepix); fz_droppixmap(colorpix); - gc->acc = oldacc; + gc->over = oldover; + gc->mask = oldmask; gc->clip = oldclip; +printf("}\n"); + return nil; } -fz_error * -fz_rendertransform(fz_renderer *gc, fz_transformnode *transform, fz_matrix ctm) -{ - ctm = fz_concat(transform->m, ctm); - return fz_rendernode(gc, transform->super.first, ctm); -} +/* + * Dispatch + */ -fz_error * -fz_rendernode(fz_renderer *gc, fz_node *node, fz_matrix ctm) +static fz_error * +rendernode(fz_renderer *gc, fz_node *node, fz_matrix ctm) { - assert(gc->tmp == nil); - if (!node) return nil; + gc->flag = FNONE; + if (gc->over) gc->flag |= FOVER; + if (gc->mask) gc->flag |= FMASK; + switch (node->kind) { case FZ_NOVER: - return fz_renderover(gc, (fz_overnode*)node, ctm); + return renderover(gc, (fz_overnode*)node, ctm); case FZ_NMASK: - return fz_rendermask(gc, (fz_masknode*)node, ctm); + return rendermask(gc, (fz_masknode*)node, ctm); case FZ_NTRANSFORM: - return fz_rendertransform(gc, (fz_transformnode*)node, ctm); + return rendertransform(gc, (fz_transformnode*)node, ctm); case FZ_NCOLOR: - return fz_rendercolor(gc, (fz_colornode*)node, ctm); + return rendercolor(gc, (fz_colornode*)node, ctm); case FZ_NPATH: - return fz_renderpath(gc, (fz_pathnode*)node, ctm); + return renderpath(gc, (fz_pathnode*)node, ctm); case FZ_NTEXT: - return fz_rendertext(gc, (fz_textnode*)node, ctm); + return rendertext(gc, (fz_textnode*)node, ctm); case FZ_NIMAGE: - return fz_renderimage(gc, (fz_imagenode*)node, ctm); + return renderimage(gc, (fz_imagenode*)node, ctm); case FZ_NLINK: - return fz_rendernode(gc, ((fz_linknode*)node)->tree->root, ctm); - default: - return nil; + return rendernode(gc, ((fz_linknode*)node)->tree->root, ctm); } + + return nil; } fz_error * -fz_rendertree(fz_pixmap **outp, fz_renderer *gc, fz_tree *tree, fz_matrix ctm, fz_irect bbox, int white) +fz_rendertree(fz_pixmap **outp, + fz_renderer *gc, fz_tree *tree, fz_matrix ctm, + fz_irect bbox, int white) { fz_error *error; @@ -269,27 +519,28 @@ fz_rendertree(fz_pixmap **outp, fz_renderer *gc, fz_tree *tree, fz_matrix ctm, f if (white) { - error = fz_newpixmap(&gc->acc, - bbox.min.x, bbox.min.y, - bbox.max.x - bbox.min.x, bbox.max.y - bbox.min.y, 4); + assert(gc->maskonly == 0); + + error = fz_newpixmapwithrect(&gc->over, bbox, 4); if (error) return error; - memset(gc->acc->samples, 0xff, gc->acc->w * gc->acc->h * gc->acc->n); + + memset(gc->over->samples, 0xff, gc->over->w * gc->over->h * gc->over->n); } - error = fz_rendernode(gc, tree->root, ctm); + error = rendernode(gc, tree->root, ctm); if (error) return error; if (white) { - *outp = gc->acc; - gc->acc = nil; + *outp = gc->over; + gc->over = nil; } else { - *outp = gc->tmp; - gc->tmp = nil; + *outp = gc->dest; + gc->dest = nil; } return nil; |