#include struct fz_renderer_s { fz_glyphcache *cache; fz_gel *gel; fz_ael *ael; }; fz_error * fz_newrenderer(fz_renderer **gcp) { fz_error *error; fz_renderer *gc; gc = *gcp = fz_malloc(sizeof(fz_renderer)); if (!gc) return fz_outofmem; gc->cache = nil; gc->gel = nil; gc->ael = nil; error = fz_newglyphcache(&gc->cache, 1024, 65536); if (error) goto cleanup; error = fz_newgel(&gc->gel); if (error) goto cleanup; error = fz_newael(&gc->ael); if (error) goto cleanup; return nil; cleanup: if (gc->cache) fz_freeglyphcache(gc->cache); if (gc->gel) fz_freegel(gc->gel); if (gc->ael) fz_freeael(gc->ael); fz_free(gc); return error; } void fz_freerenderer(fz_renderer *gc) { if (gc->cache) fz_freeglyphcache(gc->cache); if (gc->gel) fz_freegel(gc->gel); if (gc->ael) fz_freeael(gc->ael); fz_free(gc); } fz_error * fz_renderover(fz_renderer *gc, fz_overnode *over, fz_matrix ctm, fz_pixmap *out) { fz_error *error; fz_node *node; for (node = over->super.child; node; node = node->next) { error = fz_rendernode(gc, node, ctm, out); if (error) return error; } return nil; } fz_error * fz_rendermask(fz_renderer *gc, fz_masknode *mask, fz_matrix ctm, fz_pixmap *out) { fz_error *error; fz_node *node; for (node = mask->super.child; node; node = node->next) { error = fz_rendernode(gc, node, ctm, out); if (error) return error; } return nil; } fz_error * fz_rendertransform(fz_renderer *gc, fz_transformnode *transform, fz_matrix ctm, fz_pixmap *out) { ctm = fz_concat(ctm, transform->m); return fz_rendernode(gc, transform->super.child, ctm, out); } void composite(fz_pixmap *out, fz_glyph *gl, int xo, int yo) { int sx, sy, dx, dy, a, b, c; for (sy = 0; sy < gl->h; sy++) { for (sx = 0; sx < gl->w; sx++) { dx = xo + sx + gl->lsb; dy = yo - sy + gl->top; if (dx < 0) continue; if (dy < 0) continue; if (dx >= out->w) continue; if (dy >= out->h) continue; a = gl->bitmap[sx + sy * gl->w]; b = out->samples[dx + dy * out->stride]; c = MAX(a, b); out->samples[dx + dy * out->stride] = c; } } } fz_error * fz_rendertext(fz_renderer *gc, fz_textnode *text, fz_matrix ctm, fz_pixmap *out) { fz_error *error; fz_glyph gl; float x, y; int g, i, ix, iy; fz_matrix tm, trm; tm = text->trm; for (i = 0; i < text->len; i++) { g = text->els[i].g; x = text->els[i].x; y = text->els[i].y; tm.e = x; tm.f = y; trm = fz_concat(tm, ctm); ix = floor(trm.e); iy = floor(trm.f); trm.e = (trm.e - floor(trm.e)); trm.f = (trm.f - floor(trm.f)); error = fz_renderglyph(gc->cache, &gl, text->font, g, trm); if (error) return error; composite(out, &gl, ix, iy); } return nil; } fz_error * fz_rendernode(fz_renderer *gc, fz_node *node, fz_matrix ctm, fz_pixmap *out) { if (!node) return nil; switch (node->kind) { case FZ_NOVER: return fz_renderover(gc, (fz_overnode*)node, ctm, out); case FZ_NMASK: return fz_rendermask(gc, (fz_masknode*)node, ctm, out); case FZ_NTRANSFORM: return fz_rendertransform(gc, (fz_transformnode*)node, ctm, out); case FZ_NTEXT: return fz_rendertext(gc, (fz_textnode*)node, ctm, out); default: return nil; } }