<commit_before>#include "fitz.h"
#include "mupdf.h"

static pdf_csi *
pdf_newcsi(pdf_xref *xref, fz_device *dev, fz_matrix ctm)
{
	pdf_csi *csi;

	csi = fz_malloc(sizeof(pdf_csi));
	csi->xref = xref;
	csi->dev = dev;

	csi->top = 0;
	csi->xbalance = 0;
	csi->array = nil;

	csi->path = fz_newpath();
	csi->clip = 0;
	csi->clipevenodd = 0;

	csi->text = nil;
	csi->tlm = fz_identity;
	csi->tm = fz_identity;
	csi->textmode = 0;
	csi->accumulate = 1;

	csi->topctm = ctm;
	pdf_initgstate(&csi->gstate[0], ctm);
	csi->gtop = 0;

	return csi;
}

static void
pdf_clearstack(pdf_csi *csi)
{
	int i;
	for (i = 0; i < csi->top; i++)
		fz_dropobj(csi->stack[i]);
	csi->top = 0;
}

pdf_material *
pdf_keepmaterial(pdf_material *mat)
{
	if (mat->cs)
		fz_keepcolorspace(mat->cs);
	if (mat->pattern)
		pdf_keeppattern(mat->pattern);
	if (mat->shade)
		fz_keepshade(mat->shade);
	return mat;
}

pdf_material *
pdf_dropmaterial(pdf_material *mat)
{
	if (mat->cs)
		fz_dropcolorspace(mat->cs);
	if (mat->pattern)
		pdf_droppattern(mat->pattern);
	if (mat->shade)
		fz_dropshade(mat->shade);
	return mat;
}

void
pdf_gsave(pdf_csi *csi)
{
	pdf_gstate *gs = csi->gstate + csi->gtop;

	if (csi->gtop == nelem(csi->gstate) - 1)
	{
		fz_warn("gstate overflow in content stream");
		return;
	}

	memcpy(&csi->gstate[csi->gtop + 1], &csi->gstate[csi->gtop], sizeof(pdf_gstate));

	csi->gtop ++;

	pdf_keepmaterial(&gs->stroke);
	pdf_keepmaterial(&gs->fill);
	if (gs->font)
		pdf_keepfont(gs->font);
	if (gs->softmask)
		pdf_keepxobject(gs->softmask);
}

void
pdf_grestore(pdf_csi *csi)
{
	pdf_gstate *gs = csi->gstate + csi->gtop;
	int clipdepth = gs->clipdepth;

	if (csi->gtop == 0)
	{
		fz_warn("gstate underflow in content stream");
		return;
	}

	pdf_dropmaterial(&gs->stroke);
	pdf_dropmaterial(&gs->fill);
	if (gs->font)
		pdf_dropfont(gs->font);
	if (gs->softmask)
		pdf_dropxobject(gs->softmask);

	csi->gtop --;

	gs = csi->gstate + csi->gtop;
	while (clipdepth > gs->clipdepth)
	{
		csi->dev->popclip(csi->dev->user);
		clipdepth--;
	}
}

static void
pdf_freecsi(pdf_csi *csi)
{
	while (csi->gtop)
		pdf_grestore(csi);

	pdf_dropmaterial(&csi->gstate[0].fill);
	pdf_dropmaterial(&csi->gstate[0].stroke);
	if (csi->gstate[0].font)
		pdf_dropfont(csi->gstate[0].font);

	while (csi->gstate[0].clipdepth--)
		csi->dev->popclip(csi->dev->user);

	if (csi->path) fz_freepath(csi->path);
	if (csi->text) fz_freetext(csi->text);
	if (csi->array) fz_dropobj(csi->array);

	pdf_clearstack(csi);

	fz_free(csi);
}

fz_error
pdf_runxobject(pdf_csi *csi, fz_obj *resources, pdf_xobject *xobj)
{
	fz_error error;
	pdf_gstate *gstate;
	fz_matrix oldtopctm;
	int oldtop;
	int popmask;

	pdf_gsave(csi);

	gstate = csi->gstate + csi->gtop;
	oldtop = csi->gtop;
	popmask = 0;

	/* apply xobject's transform matrix */
	gstate->ctm = fz_concat(xobj->matrix, gstate->ctm);

	/* apply soft mask, create transparency group and reset state */
	if (xobj->transparency)
	{
		if (gstate->softmask)
		{
			pdf_xobject *softmask = gstate->softmask;
			fz_rect bbox = fz_transformrect(gstate->ctm, xobj->bbox);

			gstate->softmask = nil;
			popmask = 1;

			csi->dev->beginmask(csi->dev->user, bbox, gstate->luminosity, nil, nil);
			pdf_runxobject(csi, nil, softmask);
			csi->dev->endmask(csi->dev->user);

			pdf_dropxobject(softmask);
		}

		csi->dev->begingroup(csi->dev->user,
			fz_transformrect(gstate->ctm, xobj->bbox),
			xobj->isolated, xobj->knockout, gstate->blendmode, gstate->fill.alpha);

		gstate->blendmode = FZ_BNORMAL;
		gstate->stroke.alpha = 1;
		gstate->fill.alpha = 1;
	}

	/* clip to the bounds */

	fz_moveto(csi->path, xobj->bbox.x0, xobj->bbox.y0);
	fz_lineto(csi->path, xobj->bbox.x1, xobj->bbox.y0);
	fz_lineto(csi->path, xobj->bbox.x1, xobj->bbox.y1);
	fz_lineto(csi->path, xobj->bbox.x0, xobj->bbox.y1);
	fz_closepath(csi->path);
	csi->clip = 1;
	pdf_showpath(csi, 0, 0, 0, 0);

	/* run contents */<commit_msg>Test return code from runxobject on softmasks.<commit_after>#include "fitz.h"
#include "mupdf.h"

static pdf_csi *
pdf_newcsi(pdf_xref *xref, fz_device *dev, fz_matrix ctm)
{
	pdf_csi *csi;

	csi = fz_malloc(sizeof(pdf_csi));
	csi->xref = xref;
	csi->dev = dev;

	csi->top = 0;
	csi->xbalance = 0;
	csi->array = nil;

	csi->path = fz_newpath();
	csi->clip = 0;
	csi->clipevenodd = 0;

	csi->text = nil;
	csi->tlm = fz_identity;
	csi->tm = fz_identity;
	csi->textmode = 0;
	csi->accumulate = 1;

	csi->topctm = ctm;
	pdf_initgstate(&csi->gstate[0], ctm);
	csi->gtop = 0;

	return csi;
}

static void
pdf_clearstack(pdf_csi *csi)
{
	int i;
	for (i = 0; i < csi->top; i++)
		fz_dropobj(csi->stack[i]);
	csi->top = 0;
}

pdf_material *
pdf_keepmaterial(pdf_material *mat)
{
	if (mat->cs)
		fz_keepcolorspace(mat->cs);
	if (mat->pattern)
		pdf_keeppattern(mat->pattern);
	if (mat->shade)
		fz_keepshade(mat->shade);
	return mat;
}

pdf_material *
pdf_dropmaterial(pdf_material *mat)
{
	if (mat->cs)
		fz_dropcolorspace(mat->cs);
	if (mat->pattern)
		pdf_droppattern(mat->pattern);
	if (mat->shade)
		fz_dropshade(mat->shade);
	return mat;
}

void
pdf_gsave(pdf_csi *csi)
{
	pdf_gstate *gs = csi->gstate + csi->gtop;

	if (csi->gtop == nelem(csi->gstate) - 1)
	{
		fz_warn("gstate overflow in content stream");
		return;
	}

	memcpy(&csi->gstate[csi->gtop + 1], &csi->gstate[csi->gtop], sizeof(pdf_gstate));

	csi->gtop ++;

	pdf_keepmaterial(&gs->stroke);
	pdf_keepmaterial(&gs->fill);
	if (gs->font)
		pdf_keepfont(gs->font);
	if (gs->softmask)
		pdf_keepxobject(gs->softmask);
}

void
pdf_grestore(pdf_csi *csi)
{
	pdf_gstate *gs = csi->gstate + csi->gtop;
	int clipdepth = gs->clipdepth;

	if (csi->gtop == 0)
	{
		fz_warn("gstate underflow in content stream");
		return;
	}

	pdf_dropmaterial(&gs->stroke);
	pdf_dropmaterial(&gs->fill);
	if (gs->font)
		pdf_dropfont(gs->font);
	if (gs->softmask)
		pdf_dropxobject(gs->softmask);

	csi->gtop --;

	gs = csi->gstate + csi->gtop;
	while (clipdepth > gs->clipdepth)
	{
		csi->dev->popclip(csi->dev->user);
		clipdepth--;
	}
}

static void
pdf_freecsi(pdf_csi *csi)
{
	while (csi->gtop)
		pdf_grestore(csi);

	pdf_dropmaterial(&csi->gstate[0].fill);
	pdf_dropmaterial(&csi->gstate[0].stroke);
	if (csi->gstate[0].font)
		pdf_dropfont(csi->gstate[0].font);

	while (csi->gstate[0].clipdepth--)
		csi->dev->popclip(csi->dev->user);

	if (csi->path) fz_freepath(csi->path);
	if (csi->text) fz_freetext(csi->text);
	if (csi->array) fz_dropobj(csi->array);

	pdf_clearstack(csi);

	fz_free(csi);
}

fz_error
pdf_runxobject(pdf_csi *csi, fz_obj *resources, pdf_xobject *xobj)
{
	fz_error error;
	pdf_gstate *gstate;
	fz_matrix oldtopctm;
	int oldtop;
	int popmask;

	pdf_gsave(csi);

	gstate = csi->gstate + csi->gtop;
	oldtop = csi->gtop;
	popmask = 0;

	/* apply xobject's transform matrix */
	gstate->ctm = fz_concat(xobj->matrix, gstate->ctm);

	/* apply soft mask, create transparency group and reset state */
	if (xobj->transparency)
	{
		if (gstate->softmask)
		{
			pdf_xobject *softmask = gstate->softmask;
			fz_rect bbox = fz_transformrect(gstate->ctm, xobj->bbox);

			gstate->softmask = nil;
			popmask = 1;

			csi->dev->beginmask(csi->dev->user, bbox, gstate->luminosity, nil, nil);
			error = pdf_runxobject(csi, nil, softmask);
			if (error)
				return fz_rethrow(error, "cannot run softmask");
			csi->dev->endmask(csi->dev->user);

			pdf_dropxobject(softmask);
		}

		csi->dev->begingroup(csi->dev->user,
			fz_transformrect(gstate->ctm, xobj->bbox),
			xobj->isolated, xobj->knockout, gstate->blendmode, gstate->fill.alpha);

		gstate->blendmode = FZ_BNORMAL;
		gstate->stroke.alpha = 1;
		gstate->fill.alpha = 1;
	}

	/* clip to the bounds */

	fz_moveto(csi->path, xobj->bbox.x0, xobj->bbox.y0);
	fz_lineto(csi->path, xobj->bbox.x1, xobj->bbox.y0);
	fz_lineto(csi->path, xobj->bbox.x1, xobj->bbox.y1);
	fz_lineto(csi->path, xobj->bbox.x0, xobj->bbox.y1);
	fz_closepath(csi->path);
	csi->clip = 1;
	pdf_showpath(csi, 0, 0, 0, 0);

	/* run contents */
{'fraction_non_alphanumeric': 0.18246146070255242, 'fraction_numerical': 0.008845084660096033, 'mean_word_length': 4.241721854304636, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 261, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7110914', 'n_tokens_mistral': 3828, 'n_tokens_neox': 3615, 'n_words': 595}