static fz_error * addinvisibleshape(pdf_gstate *gs, fz_node *shape) { fz_error *error; fz_node *mask; fz_pathnode *path; error = fz_newmasknode(&mask); if (error) return fz_rethrow(error, "cannot create mask node"); error = fz_newpathnode(&path); if (error) { fz_dropnode(mask); return fz_rethrow(error, "cannot create path node"); } error = fz_endpath(path, FZ_FILL, nil, nil); if (error) { fz_dropnode(mask); fz_dropnode((fz_node*)path); return fz_rethrow(error, "cannot finish path node"); } fz_insertnodelast(mask, (fz_node*)path); fz_insertnodelast(mask, shape); fz_insertnodelast(gs->head, mask); return fz_okay; }
fz_error * pdf_showimage(pdf_csi *csi, pdf_image *img) { fz_error *error; fz_node *mask; fz_node *color; fz_node *shape; error = fz_newimagenode(&color, (fz_image*)img); if (error) return fz_rethrow(error, "cannot create image node"); if (img->super.n == 0 && img->super.a == 1) { error = pdf_addfillshape(csi->gstate + csi->gtop, color); if (error) { fz_dropnode(color); return fz_rethrow(error, "cannot add filled image mask"); } } else { if (img->mask) { error = fz_newimagenode(&shape, (fz_image*)img->mask); if (error) { fz_dropnode(color); return fz_rethrow(error, "cannot create image node for image mask"); } error = fz_newmasknode(&mask); if (error) { fz_dropnode(shape); fz_dropnode(color); return fz_rethrow(error, "cannot create mask node for image mask"); } fz_insertnodelast(mask, shape); fz_insertnodelast(mask, color); fz_insertnodelast(csi->gstate[csi->gtop].head, mask); } else { fz_insertnodelast(csi->gstate[csi->gtop].head, color); } } return fz_okay; }
fz_error * pdf_addclipmask(pdf_gstate *gs, fz_node *shape) { fz_error *error; fz_node *mask; fz_node *over; error = fz_newmasknode(&mask); if (error) return fz_rethrow(error, "cannot create mask node"); error = pdf_newovernode(&over, gs); if (error) { fz_dropnode(mask); return fz_rethrow(error, "cannot create over node"); } fz_insertnodelast(mask, shape); fz_insertnodelast(mask, over); fz_insertnodelast(gs->head, mask); gs->head = over; return fz_okay; }
void fz_droptree(fz_tree *tree) { if (--tree->refs == 0) { if (tree->root) fz_dropnode(tree->root); fz_free(tree); } }
static void cleanmasks(fz_node *node) { fz_node *prev; fz_node *current; fz_node *shape; fz_node *color; fz_rect bbox; for (current = node->first; current; current = current->next) cleanmasks(current); prev = nil; for (current = node->first; current; current = current->next) { retry: if (!current) break; if (fz_ismasknode(current)) { 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)) { if (fitsinside(color, bbox)) { fz_removenode(current); if (prev) fz_insertnodeafter(prev, color); else fz_insertnodefirst(node, color); /* cf. http://bugs.ghostscript.com/show_bug.cgi?id=690679 */ current->first->next = nil; fz_dropnode(current); current = color; goto retry; } } } } prev = current; } }
static int cleanwhite(fz_node *node) { fz_node *current; fz_node *next; fz_node *shape; fz_node *color; for (current = node->first; current; current = next) { next = current->next; if (fz_islinknode(current)) return 1; else if (fz_isimagenode(current)) return 1; else if (fz_isshadenode(current)) return 1; else if (fz_issolidnode(current)) { if (!iswhitenode((fz_solidnode*)current)) return 1; } else if (fz_ismasknode(current)) { shape = current->first; color = shape->next; if (fz_issolidnode(color)) { if (iswhitenode((fz_solidnode*)color)) fz_removenode(current); else return 1; fz_dropnode(current); /* cf. http://bugs.ghostscript.com/show_bug.cgi?id=690679 */ } else { if (cleanwhite(current)) return 1; } } else { if (cleanwhite(current)) return 1; } } return 0; }
static void cleanovers(fz_node *node) { fz_node *prev; fz_node *next; fz_node *current; fz_node *child; prev = nil; for (current = node->first; current; current = next) { next = current->next; if (fz_isovernode(current)) { if (current->first == current->last && /* HACK: We seem to leek the prev node, if a childless node is removed here * http://bugs.ghostscript.com/show_bug.cgi?id=690679 */ (current->first || !prev)) { child = current->first; fz_removenode(current); /* cf. http://bugs.ghostscript.com/show_bug.cgi?id=690679 */ current->first = nil; fz_dropnode(current); if (child) { if (prev) fz_insertnodeafter(prev, child); else fz_insertnodefirst(node, child); } current = child; } } if (current) prev = current; } for (current = node->first; current; current = current->next) cleanovers(current); }
void fz_dropnode(fz_node *node) { fz_node *next; while (node) { if (node->first) fz_dropnode(node->first); switch (node->kind) { case FZ_NTRANSFORM: case FZ_NOVER: case FZ_NMASK: case FZ_NBLEND: break; case FZ_NCOLOR: fz_dropsolidnode((fz_solidnode *) node); break; case FZ_NPATH: fz_droppathnode((fz_pathnode *) node); break; case FZ_NTEXT: fz_droptextnode((fz_textnode *) node); break; case FZ_NIMAGE: fz_dropimagenode((fz_imagenode *) node); break; case FZ_NSHADE: fz_dropshadenode((fz_shadenode *) node); break; case FZ_NLINK: fz_droplinknode((fz_linknode *) node); break; } next = node->next; fz_free(node); node = next; } }
static fz_error * addcolorshape(pdf_gstate *gs, fz_node *shape, float alpha, fz_colorspace *cs, float *v) { fz_error *error; fz_node *mask; fz_node *solid; error = fz_newmasknode(&mask); if (error) return fz_rethrow(error, "cannot create mask node"); error = fz_newsolidnode(&solid, alpha, cs, cs->n, v); if (error) { fz_dropnode(mask); return fz_rethrow(error, "cannot create color node"); } fz_insertnodelast(mask, shape); fz_insertnodelast(mask, solid); fz_insertnodelast(gs->head, mask); return fz_okay; }
fz_error * pdf_flushtext(pdf_csi *csi) { pdf_gstate *gstate = csi->gstate + csi->gtop; fz_error *error; if (csi->text) { switch (csi->textmode) { case 0: /* fill */ case 1: /* stroke */ case 2: /* stroke + fill */ error = pdf_addfillshape(gstate, (fz_node*)csi->text); if (error) return fz_rethrow(error, "cannot add filled text"); break; case 3: /* invisible */ error = addinvisibleshape(gstate, (fz_node*)csi->text); if (error) return fz_rethrow(error, "cannot add invisible text"); break; case 4: /* fill + clip */ case 5: /* stroke + clip */ case 6: /* stroke + fill + clip */ { fz_textnode *temp; error = fz_clonetextnode(&temp, csi->text); if (error) return fz_rethrow(error, "cannot duplicate text"); error = pdf_addfillshape(gstate, (fz_node*)temp); if (error) { fz_dropnode((fz_node*)temp); return fz_rethrow(error, "cannot add filled text"); } /* FIXME stroked text */ } /* fall through */ case 7: /* invisible clip ( + fallthrough clips ) */ if (!csi->textclip) { error = pdf_newovernode(&csi->textclip, gstate); if (error) return fz_rethrow(error, "cannot create over node"); } fz_insertnodelast(csi->textclip, (fz_node*)csi->text); break; } csi->text = nil; } return fz_okay; }
fz_error * pdf_showpath(pdf_csi *csi, int doclose, int dofill, int dostroke, int evenodd) { pdf_gstate *gstate = csi->gstate + csi->gtop; fz_error *error; char *reason; fz_pathnode *spath = nil; fz_pathnode *fpath = nil; fz_pathnode *clip = nil; /* TODO review memory cleanup code cleanup... */ if (doclose) { error = fz_closepath(csi->path); if (error) return fz_rethrow(error, "cannot create path node"); } /* * Prepare the various copies of the path node. */ if (csi->clip) { error = fz_clonepathnode(&clip, csi->path); if (error) return fz_rethrow(error, "cannot copy path node for clip mask"); } if (dofill && dostroke) { fpath = csi->path; error = fz_clonepathnode(&spath, fpath); if (error) return fz_rethrow(error, "cannot duplicate path node"); } else if (dofill) { fpath = csi->path; } else if (dostroke) { spath = csi->path; } else { fz_dropnode((fz_node*)csi->path); } csi->path = nil; /* * Add nodes to the tree. */ if (dofill) { error = pdf_buildfillpath(gstate, fpath, evenodd); if (error) { reason = "cannot finish fill path"; goto cleanup; } error = pdf_addfillshape(gstate, (fz_node*)fpath); if (error) { reason = "cannot add filled path"; goto cleanup; } } if (dostroke) { error = pdf_buildstrokepath(gstate, spath); if (error) { reason = "cannot finish stroke path"; goto cleanup; } error = pdf_addstrokeshape(gstate, (fz_node*)spath); if (error) { reason = "cannot add stroked path"; goto cleanup; } } if (csi->clip) { error = fz_endpath(clip, evenodd ? FZ_EOFILL : FZ_FILL, nil, nil); if (error) { reason = "cannot finish clip path"; goto cleanupclip; } error = pdf_addclipmask(gstate, (fz_node*)clip); if (error) { reason = "cannot add clip mask"; goto cleanupclip; } csi->clip = 0; } error = fz_newpathnode(&csi->path); if (error) return fz_rethrow(error, "cannot create path node");; return fz_okay; cleanup: if (spath) fz_dropnode((fz_node *)spath); if (fpath) fz_dropnode((fz_node *)fpath); cleanupclip: if (clip) fz_dropnode((fz_node *)clip); return fz_rethrow(error, reason); }
static fz_error * addshadeshape(pdf_gstate *gs, fz_node *shape, fz_shade *shade) { fz_error *error; fz_node *mask; fz_node *color; fz_node *xform; fz_node *over; fz_node *bgnd; fz_matrix ctm; fz_matrix inv; ctm = getmatrix(gs->head); inv = fz_invertmatrix(ctm); error = fz_newtransformnode(&xform, inv); if (error) return fz_rethrow(error, "cannot create transform node"); error = fz_newmasknode(&mask); if (error) { fz_dropnode(xform); return fz_rethrow(error, "cannot create mask node"); } error = fz_newshadenode(&color, shade); if (error) { fz_dropnode(mask); fz_dropnode(xform); return fz_rethrow(error, "cannot create shade node"); } if (shade->usebackground) { error = pdf_newovernode(&over, gs); if (error) { fz_dropnode(color); fz_dropnode(mask); fz_dropnode(xform); return fz_rethrow(error, "cannot create over node for background color"); } error = fz_newsolidnode(&bgnd, 1.0f, shade->cs, shade->cs->n, shade->background); if (error) { fz_dropnode(over); fz_dropnode(color); fz_dropnode(mask); fz_dropnode(xform); return fz_rethrow(error, "cannot create solid node for background color");; } fz_insertnodelast(mask, shape); fz_insertnodelast(over, bgnd); fz_insertnodelast(over, color); fz_insertnodelast(xform, over); fz_insertnodelast(mask, xform); fz_insertnodelast(gs->head, mask); } else { fz_insertnodelast(mask, shape); fz_insertnodelast(xform, color); fz_insertnodelast(mask, xform); fz_insertnodelast(gs->head, mask); } return fz_okay; }
static fz_error * addpatternshape(pdf_gstate *gs, fz_node *shape, pdf_pattern *pat, fz_colorspace *cs, float *v) { fz_error *error; fz_node *xform; fz_node *over; fz_node *mask; fz_node *link; fz_matrix ctm; fz_matrix inv; fz_matrix ptm; fz_rect bbox; int x, y, x0, y0, x1, y1; /* patterns are painted in user space */ ctm = getmatrix(gs->head); inv = fz_invertmatrix(ctm); error = fz_newmasknode(&mask); if (error) return fz_rethrow(error, "cannot create mask node"); ptm = fz_concat(pat->matrix, fz_invertmatrix(ctm)); error = fz_newtransformnode(&xform, ptm); if (error) { fz_dropnode(mask); return fz_rethrow(error, "cannot create transform node"); } error = pdf_newovernode(&over, gs); if (error) { fz_dropnode(xform); fz_dropnode(mask); return fz_rethrow(error, "cannot create over node"); } fz_insertnodelast(mask, shape); fz_insertnodelast(mask, xform); fz_insertnodelast(xform, over); xform = nil; /* over, xform, mask are now owned by the tree */ /* get bbox of shape in pattern space for stamping */ ptm = fz_concat(ctm, fz_invertmatrix(pat->matrix)); bbox = fz_boundnode(shape, ptm); /* expand bbox by pattern bbox */ bbox.x0 += pat->bbox.x0; bbox.y0 += pat->bbox.y0; bbox.x1 += pat->bbox.x1; bbox.y1 += pat->bbox.y1; x0 = fz_floor(bbox.x0 / pat->xstep); y0 = fz_floor(bbox.y0 / pat->ystep); x1 = fz_ceil(bbox.x1 / pat->xstep); y1 = fz_ceil(bbox.y1 / pat->ystep); for (y = y0; y <= y1; y++) { for (x = x0; x <= x1; x++) { ptm = fz_translate(x * pat->xstep, y * pat->ystep); error = fz_newtransformnode(&xform, ptm); if (error) return fz_rethrow(error, "cannot create transform node for stamp"); error = fz_newlinknode(&link, pat->tree); if (error) { fz_dropnode(xform); return fz_rethrow(error, "cannot create link node for stamp"); } fz_insertnodelast(xform, link); fz_insertnodelast(over, xform); } } if (pat->ismask) { error = addcolorshape(gs, mask, 1.0, cs, v); if (error) return fz_rethrow(error, "cannot add colored shape"); return fz_okay; } fz_insertnodelast(gs->head, mask); return fz_okay; }