Esempio n. 1
0
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;
}
Esempio n. 2
0
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;
}
Esempio n. 3
0
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;
}
Esempio n. 4
0
void
fz_droptree(fz_tree *tree)
{
	if (--tree->refs == 0)
	{
		if (tree->root)
			fz_dropnode(tree->root);
		fz_free(tree);
	}
}
Esempio n. 5
0
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;
    }
}
Esempio n. 6
0
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;
}
Esempio n. 7
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);
}
Esempio n. 8
0
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;
	}
}
Esempio n. 9
0
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;
}
Esempio n. 10
0
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;
}
Esempio n. 11
0
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);
}
Esempio n. 12
0
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;
}
Esempio n. 13
0
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;
}