summaryrefslogtreecommitdiff
path: root/render/render.c
diff options
context:
space:
mode:
Diffstat (limited to 'render/render.c')
-rw-r--r--render/render.c511
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;