Example #1
0
static void
fz_draw_clip_path(fz_device *devp, fz_path *path, fz_rect rect, int even_odd, fz_matrix ctm)
{
	fz_draw_device *dev = devp->user;
	float expansion = fz_matrix_expansion(ctm);
	float flatness = 0.3f / expansion;
	fz_bbox bbox;
	fz_draw_state *state = &dev->stack[dev->top];
	fz_colorspace *model;
	fz_context *ctx = dev->ctx;

	fz_reset_gel(dev->gel, state->scissor);
	fz_flatten_fill_path(dev->gel, path, ctm, flatness);
	fz_sort_gel(dev->gel);

	state = push_stack(dev);
	model = state->dest->colorspace;

	bbox = fz_bound_gel(dev->gel);
	bbox = fz_intersect_bbox(bbox, state->scissor);
	bbox = fz_intersect_bbox(bbox, fz_bbox_from_rect(rect));
	/* SumatraPDF: try to match rendering with and without display list */
	if (fz_is_infinite_rect(rect))
		bbox = fz_intersect_bbox(bbox, fz_bbox_from_rect(fz_bound_path(ctx, path, NULL, ctm)));

	if (fz_is_empty_rect(bbox) || fz_is_rect_gel(dev->gel))
	{
		state[1].scissor = bbox;
		state[1].mask = NULL;
#ifdef DUMP_GROUP_BLENDS
		dump_spaces(dev->top-1, "Clip (rectangular) begin\n");
#endif
		return;
	}

	fz_try(ctx)
	{
		state[1].mask = fz_new_pixmap_with_bbox(dev->ctx, NULL, bbox);
		fz_clear_pixmap(dev->ctx, state[1].mask);
		state[1].dest = fz_new_pixmap_with_bbox(dev->ctx, model, bbox);
		fz_clear_pixmap(dev->ctx, state[1].dest);
		if (state[1].shape)
		{
			state[1].shape = fz_new_pixmap_with_bbox(dev->ctx, NULL, bbox);
			fz_clear_pixmap(dev->ctx, state[1].shape);
		}

		fz_scan_convert(dev->gel, even_odd, bbox, state[1].mask, NULL);

		state[1].blendmode |= FZ_BLEND_ISOLATED;
		state[1].scissor = bbox;
#ifdef DUMP_GROUP_BLENDS
		dump_spaces(dev->top-1, "Clip (non-rectangular) begin\n");
#endif
	}
	fz_catch(ctx)
	{
		emergency_pop_stack(dev, state);
	}
}
Example #2
0
static fz_draw_state *
fz_knockout_begin(fz_draw_device *dev)
{
	fz_context *ctx = dev->ctx;
	fz_bbox bbox;
	fz_pixmap *dest, *shape;
	fz_draw_state *state = &dev->stack[dev->top];
	int isolated = state->blendmode & FZ_BLEND_ISOLATED;

	if ((state->blendmode & FZ_BLEND_KNOCKOUT) == 0)
		return state;

	state = push_stack(dev);

	bbox = fz_pixmap_bbox(dev->ctx, state->dest);
	bbox = fz_intersect_bbox(bbox, state->scissor);
	dest = fz_new_pixmap_with_bbox(dev->ctx, state->dest->colorspace, bbox);

	if (isolated)
	{
		fz_clear_pixmap(ctx, dest);
	}
	else
	{
		/* Find the last but one destination to copy */
		int i = dev->top-1; /* i = the one on entry (i.e. the last one) */
		fz_pixmap *prev = state->dest;
		while (i > 0)
		{
			prev = dev->stack[--i].dest;
			if (prev != state->dest)
				break;
		}
		if (prev)
			fz_copy_pixmap_rect(ctx, dest, prev, bbox);
		else
			fz_clear_pixmap(ctx, dest);
	}

	if (state->blendmode == 0 && isolated)
	{
		/* We can render direct to any existing shape plane. If there
		 * isn't one, we don't need to make one. */
		shape = state->shape;
	}
	else
	{
		shape = fz_new_pixmap_with_bbox(dev->ctx, NULL, bbox);
		fz_clear_pixmap(dev->ctx, shape);
	}
#ifdef DUMP_GROUP_BLENDS
	dump_spaces(dev->top-1, "Knockout begin\n");
#endif
	state[1].scissor = bbox;
	state[1].dest = dest;
	state[1].shape = shape;
	state[1].blendmode &= ~FZ_BLEND_MODEMASK;

	return &state[1];
}
Example #3
0
static void
fz_draw_clip_stroke_path(fz_context *ctx, void *user, fz_path *path, fz_rect *rect, fz_stroke_state *stroke, fz_matrix ctm)
{
	fz_draw_device *dev = user;
	fz_colorspace *model = dev->dest->colorspace;
	float expansion = fz_matrix_expansion(ctm);
	float flatness = 0.3f / expansion;
	float linewidth = stroke->linewidth;
	fz_pixmap *mask, *dest, *shape;
	fz_bbox bbox;

	if (dev->top == dev->stack_max)
		fz_grow_stack(dev);

	if (linewidth * expansion < 0.1f)
		linewidth = 1 / expansion;

	fz_reset_gel(dev->gel, dev->scissor);
	if (stroke->dash_len > 0)
		fz_flatten_dash_path(ctx, dev->gel, path, stroke, ctm, flatness, linewidth);
	else
		fz_flatten_stroke_path(ctx, dev->gel, path, stroke, ctm, flatness, linewidth);
	fz_sort_gel(dev->gel);

	bbox = fz_bound_gel(dev->gel);
	bbox = fz_intersect_bbox(bbox, dev->scissor);
	if (rect)
		bbox = fz_intersect_bbox(bbox, fz_round_rect(*rect));

	mask = fz_new_pixmap_with_rect(ctx, NULL, bbox);
	fz_clear_pixmap(mask);
	dest = fz_new_pixmap_with_rect(ctx, model, bbox);
	/* FIXME: See note #1 */
	fz_clear_pixmap(dest);
	if (dev->shape)
	{
		shape = fz_new_pixmap_with_rect(ctx, NULL, bbox);
		fz_clear_pixmap(shape);
	}
	else
		shape = NULL;

	if (!fz_is_empty_rect(bbox))
		fz_scan_convert(dev->gel, 0, bbox, mask, NULL);

	dev->stack[dev->top].scissor = dev->scissor;
	dev->stack[dev->top].mask = mask;
	dev->stack[dev->top].dest = dev->dest;
	dev->stack[dev->top].shape = dev->shape;
	/* FIXME: See note #1 */
	dev->stack[dev->top].blendmode = dev->blendmode | FZ_BLEND_ISOLATED;
	dev->scissor = bbox;
	dev->dest = dest;
	dev->shape = shape;
#ifdef DUMP_GROUP_BLENDS
	dump_spaces(dev->top, "Clip (stroke) begin\n");
#endif
	dev->top++;
}
Example #4
0
static void
fz_draw_clip_stroke_path(fz_device *devp, fz_path *path, fz_rect *rect, fz_stroke_state *stroke, fz_matrix ctm)
{
	fz_draw_device *dev = devp->user;
	float expansion = fz_matrix_expansion(ctm);
	float flatness = 0.3f / expansion;
	float linewidth = stroke->linewidth;
	fz_bbox bbox;
	fz_draw_state *state = &dev->stack[dev->top];
	fz_colorspace *model;
	fz_context *ctx = dev->ctx;

	if (linewidth * expansion < 0.1f)
		linewidth = 1 / expansion;

	fz_reset_gel(dev->gel, state->scissor);
	if (stroke->dash_len > 0)
		fz_flatten_dash_path(dev->gel, path, stroke, ctm, flatness, linewidth);
	else
		fz_flatten_stroke_path(dev->gel, path, stroke, ctm, flatness, linewidth);
	fz_sort_gel(dev->gel);

	state = push_stack(dev);
	model = state->dest->colorspace;

	bbox = fz_bound_gel(dev->gel);
	bbox = fz_intersect_bbox(bbox, state->scissor);
	if (rect)
		bbox = fz_intersect_bbox(bbox, fz_bbox_covering_rect(*rect));
	/* SumatraPDF: try to match rendering with and without display list */
	else
		bbox = fz_intersect_bbox(bbox, fz_bbox_covering_rect(fz_bound_path(ctx, path, stroke, ctm)));

	fz_try(ctx)
	{
		state[1].mask = fz_new_pixmap_with_bbox(dev->ctx, NULL, bbox);
		fz_clear_pixmap(dev->ctx, state[1].mask);
		state[1].dest = fz_new_pixmap_with_bbox(dev->ctx, model, bbox);
		fz_clear_pixmap(dev->ctx, state[1].dest);
		if (state->shape)
		{
			state[1].shape = fz_new_pixmap_with_bbox(dev->ctx, NULL, bbox);
			fz_clear_pixmap(dev->ctx, state[1].shape);
		}

		if (!fz_is_empty_rect(bbox))
			fz_scan_convert(dev->gel, 0, bbox, state[1].mask, NULL);

		state[1].blendmode |= FZ_BLEND_ISOLATED;
		state[1].scissor = bbox;
#ifdef DUMP_GROUP_BLENDS
		dump_spaces(dev->top-1, "Clip (stroke) begin\n");
#endif
	}
	fz_catch(ctx)
	{
		emergency_pop_stack(dev, state);
	}
}
Example #5
0
static void fz_knockout_begin(fz_context *ctx, void *user)
{
	fz_draw_device *dev = user;
	fz_bbox bbox;
	fz_pixmap *dest, *shape;
	int isolated = dev->blendmode & FZ_BLEND_ISOLATED;

	if ((dev->blendmode & FZ_BLEND_KNOCKOUT) == 0)
		return;

	if (dev->top == dev->stack_max)
		fz_grow_stack(dev);

	bbox = fz_bound_pixmap(dev->dest);
	bbox = fz_intersect_bbox(bbox, dev->scissor);
	dest = fz_new_pixmap_with_rect(ctx, dev->dest->colorspace, bbox);

	if (isolated)
	{
		fz_clear_pixmap(dest);
	}
	else
	{
		fz_pixmap *prev;
		int i  = dev->top;
		do
			prev = dev->stack[--i].dest;
		while (prev == NULL);
		fz_copy_pixmap_rect(dest, prev, bbox);
	}

	if (dev->blendmode == 0 && isolated || 1 /* SumatraPDF: disable crashy shape code */)
	{
		/* We can render direct to any existing shape plane. If there
		 * isn't one, we don't need to make one. */
		shape = dev->shape;
	}
	else
	{
		shape = fz_new_pixmap_with_rect(dev->ctx, NULL, bbox);
		fz_clear_pixmap(shape);
	}
	dev->stack[dev->top].blendmode = dev->blendmode;
	dev->stack[dev->top].scissor = dev->scissor;
	dev->stack[dev->top].dest = dev->dest;
	dev->stack[dev->top].shape = dev->shape;
#ifdef DUMP_GROUP_BLENDS
	dump_spaces(dev->top, "Knockout begin\n");
#endif
	dev->top++;

	dev->scissor = bbox;
	dev->dest = dest;
	dev->shape = shape;
	dev->blendmode &= ~FZ_BLEND_MODEMASK;
}
Example #6
0
static void
fz_draw_begin_mask(fz_context *ctx, void *user, fz_rect rect, int luminosity, fz_colorspace *colorspace, float *colorfv)
{
	fz_draw_device *dev = user;
	fz_pixmap *dest;
	fz_pixmap *shape = dev->shape;
	fz_bbox bbox;

	if (dev->top == dev->stack_max)
		fz_grow_stack(dev);

	bbox = fz_round_rect(rect);
	bbox = fz_intersect_bbox(bbox, dev->scissor);
	dest = fz_new_pixmap_with_rect(ctx, fz_device_gray, bbox);
	if (dev->shape)
	{
		/* FIXME: If we ever want to support AIS true, then we
		 * probably want to create a shape pixmap here, using:
		 *     shape = fz_new_pixmap_with_rect(NULL, bbox);
		 * then, in the end_mask code, we create the mask from this
		 * rather than dest.
		 */
		shape = NULL;
	}

	if (luminosity)
	{
		float bc;
		if (!colorspace)
			colorspace = fz_device_gray;
		fz_convert_color(ctx, colorspace, colorfv, fz_device_gray, &bc);
		fz_clear_pixmap_with_color(dest, bc * 255);
		if (shape)
			fz_clear_pixmap_with_color(shape, 255);
	}
	else
	{
		fz_clear_pixmap(dest);
		if (shape)
			fz_clear_pixmap(shape);
	}

	dev->stack[dev->top].scissor = dev->scissor;
	dev->stack[dev->top].dest = dev->dest;
	dev->stack[dev->top].luminosity = luminosity;
	dev->stack[dev->top].shape = dev->shape;
	dev->stack[dev->top].blendmode = dev->blendmode;
#ifdef DUMP_GROUP_BLENDS
	dump_spaces(dev->top, "Mask begin\n");
#endif
	dev->top++;

	dev->scissor = bbox;
	dev->dest = dest;
	dev->shape = shape;
}
Example #7
0
static void
fz_draw_begin_tile(fz_device *devp, fz_rect area, fz_rect view, float xstep, float ystep, fz_matrix ctm)
{
	fz_draw_device *dev = devp->user;
	fz_pixmap *dest = NULL;
	fz_pixmap *shape;
	fz_bbox bbox;
	fz_context *ctx = dev->ctx;
	fz_draw_state *state = &dev->stack[dev->top];
	fz_colorspace *model = state->dest->colorspace;

	/* area, view, xstep, ystep are in pattern space */
	/* ctm maps from pattern space to device space */

	if (state->blendmode & FZ_BLEND_KNOCKOUT)
		fz_knockout_begin(dev);

	state = push_stack(dev);
	bbox = fz_bbox_covering_rect(fz_transform_rect(ctm, view));
	/* We should never have a bbox that entirely covers our destination.
	 * If we do, then the check for only 1 tile being visible above has
	 * failed. Actually, this *can* fail due to the round_rect, at extreme
	 * resolutions, so disable this assert.
	 * assert(bbox.x0 > state->dest->x || bbox.x1 < state->dest->x + state->dest->w ||
	 *	bbox.y0 > state->dest->y || bbox.y1 < state->dest->y + state->dest->h);
	 */
	dest = fz_new_pixmap_with_bbox(dev->ctx, model, bbox);
	fz_clear_pixmap(ctx, dest);
	shape = state[0].shape;
	if (shape)
	{
		fz_var(shape);
		fz_try(ctx)
		{
			shape = fz_new_pixmap_with_bbox(dev->ctx, NULL, bbox);
			fz_clear_pixmap(ctx, shape);
		}
		fz_catch(ctx)
		{
			fz_drop_pixmap(ctx, dest);
			fz_rethrow(ctx);
		}
	}
	state[1].blendmode |= FZ_BLEND_ISOLATED;
	state[1].xstep = xstep;
	state[1].ystep = ystep;
	state[1].area = area;
	state[1].ctm = ctm;
#ifdef DUMP_GROUP_BLENDS
	dump_spaces(dev->top-1, "Tile begin\n");
#endif

	state[1].scissor = bbox;
	state[1].dest = dest;
	state[1].shape = shape;
}
Example #8
0
static void
fz_draw_end_mask(fz_context *ctx, void *user)
{
	fz_draw_device *dev = user;
	fz_pixmap *mask = dev->dest;
	fz_pixmap *maskshape = dev->shape;
	fz_pixmap *temp, *dest;
	fz_bbox bbox;
	int luminosity;

	if (dev->top == dev->stack_max)
		fz_grow_stack(dev);

	if (dev->top > 0)
	{
		/* pop soft mask buffer */
		dev->top--;
		luminosity = dev->stack[dev->top].luminosity;
		dev->scissor = dev->stack[dev->top].scissor;
		dev->dest = dev->stack[dev->top].dest;
		dev->shape = dev->stack[dev->top].shape;

		/* convert to alpha mask */
		temp = fz_alpha_from_gray(ctx, mask, luminosity);
		fz_drop_pixmap(ctx, mask);
		fz_drop_pixmap(ctx, maskshape);

		/* create new dest scratch buffer */
		bbox = fz_bound_pixmap(temp);
		dest = fz_new_pixmap_with_rect(ctx, dev->dest->colorspace, bbox);
		/* FIXME: See note #1 */
		fz_clear_pixmap(dest);

		/* push soft mask as clip mask */
		dev->stack[dev->top].scissor = dev->scissor;
		dev->stack[dev->top].mask = temp;
		dev->stack[dev->top].dest = dev->dest;
		/* FIXME: See note #1 */
		dev->stack[dev->top].blendmode = dev->blendmode | FZ_BLEND_ISOLATED;
		/* If we have a shape, then it'll need to be masked with the
		 * clip mask when we pop. So create a new shape now. */
		if (dev->shape)
		{
			dev->stack[dev->top].shape = dev->shape;
			dev->shape = fz_new_pixmap_with_rect(ctx, NULL, bbox);
			fz_clear_pixmap(dev->shape);
		}
		dev->scissor = bbox;
		dev->dest = dest;
#ifdef DUMP_GROUP_BLENDS
		dump_spaces(dev->top, "Mask -> Clip\n");
#endif
		dev->top++;
	}
}
Example #9
0
static void
fz_draw_end_mask(fz_device *devp)
{
	fz_draw_device *dev = devp->user;
	fz_pixmap *temp, *dest;
	fz_bbox bbox;
	int luminosity;
	fz_context *ctx = dev->ctx;
	fz_draw_state *state;

	if (dev->top == 0)
	{
		fz_warn(ctx, "Unexpected draw_end_mask");
		return;
	}
	state = &dev->stack[dev->top-1];
	/* pop soft mask buffer */
	luminosity = state[1].luminosity;

#ifdef DUMP_GROUP_BLENDS
	dump_spaces(dev->top-1, "Mask -> Clip\n");
#endif
	/* convert to alpha mask */
	temp = fz_alpha_from_gray(dev->ctx, state[1].dest, luminosity);
	if (state[1].dest != state[0].dest)
		fz_drop_pixmap(dev->ctx, state[1].dest);
	state[1].dest = NULL;
	if (state[1].shape != state[0].shape)
		fz_drop_pixmap(dev->ctx, state[1].shape);
	state[1].shape = NULL;
	if (state[1].mask != state[0].mask)
		fz_drop_pixmap(dev->ctx, state[1].mask);
	state[1].mask = NULL;

	/* create new dest scratch buffer */
	bbox = fz_pixmap_bbox(ctx, temp);
	dest = fz_new_pixmap_with_bbox(dev->ctx, state->dest->colorspace, bbox);
	fz_clear_pixmap(dev->ctx, dest);

	/* push soft mask as clip mask */
	state[1].mask = temp;
	state[1].dest = dest;
	state[1].blendmode |= FZ_BLEND_ISOLATED;
	/* If we have a shape, then it'll need to be masked with the
	 * clip mask when we pop. So create a new shape now. */
	if (state[0].shape)
	{
		state[1].shape = fz_new_pixmap_with_bbox(dev->ctx, NULL, bbox);
		fz_clear_pixmap(dev->ctx, state[1].shape);
	}
	state[1].scissor = bbox;
}
Example #10
0
static void
fz_draw_clip_path(void *user, fz_path *path, fz_rect *rect, int even_odd, fz_matrix ctm)
{
	fz_draw_device *dev = user;
	fz_colorspace *model = dev->dest->colorspace;
	float expansion = fz_matrix_expansion(ctm);
	float flatness = 0.3f / expansion;
	fz_pixmap *mask, *dest;
	fz_bbox bbox;

	if (dev->top == STACK_SIZE)
	{
		fz_warn("assert: too many buffers on stack");
		return;
	}

	fz_reset_gel(dev->gel, dev->scissor);
	fz_flatten_fill_path(dev->gel, path, ctm, flatness);
	fz_sort_gel(dev->gel);

	bbox = fz_bound_gel(dev->gel);
	bbox = fz_intersect_bbox(bbox, dev->scissor);
	if (rect) {
		bbox = fz_intersect_bbox(bbox, fz_round_rect(*rect));
	}

	if (fz_is_empty_rect(bbox) || fz_is_rect_gel(dev->gel))
	{
		dev->stack[dev->top].scissor = dev->scissor;
		dev->stack[dev->top].mask = NULL;
		dev->stack[dev->top].dest = NULL;
		dev->scissor = bbox;
		dev->top++;
		return;
	}

	mask = fz_new_pixmap_with_rect(NULL, bbox);
	dest = fz_new_pixmap_with_rect(model, bbox);

	fz_clear_pixmap(mask);
	fz_clear_pixmap(dest);

	fz_scan_convert(dev->gel, even_odd, bbox, mask, NULL);

	dev->stack[dev->top].scissor = dev->scissor;
	dev->stack[dev->top].mask = mask;
	dev->stack[dev->top].dest = dev->dest;
	dev->scissor = bbox;
	dev->dest = dest;
	dev->top++;
}
Example #11
0
static void
fz_draw_begin_mask(fz_device *devp, fz_rect rect, int luminosity, fz_colorspace *colorspace, float *colorfv)
{
	fz_draw_device *dev = devp->user;
	fz_pixmap *dest;
	fz_bbox bbox;
	fz_draw_state *state = push_stack(dev);
	fz_pixmap *shape = state->shape;

	bbox = fz_bbox_covering_rect(rect);
	bbox = fz_intersect_bbox(bbox, state->scissor);
	dest = fz_new_pixmap_with_bbox(dev->ctx, fz_device_gray, bbox);
	if (state->shape)
	{
		/* FIXME: If we ever want to support AIS true, then we
		 * probably want to create a shape pixmap here, using:
		 * shape = fz_new_pixmap_with_bbox(NULL, bbox);
		 * then, in the end_mask code, we create the mask from this
		 * rather than dest.
		 */
		shape = NULL;
	}

	if (luminosity)
	{
		float bc;
		if (!colorspace)
			colorspace = fz_device_gray;
		fz_convert_color(dev->ctx, fz_device_gray, &bc, colorspace, colorfv);
		fz_clear_pixmap_with_value(dev->ctx, dest, bc * 255);
		if (shape)
			fz_clear_pixmap_with_value(dev->ctx, shape, 255);
	}
	else
	{
		fz_clear_pixmap(dev->ctx, dest);
		if (shape)
			fz_clear_pixmap(dev->ctx, shape);
	}

#ifdef DUMP_GROUP_BLENDS
	dump_spaces(dev->top-1, "Mask begin\n");
#endif
	state[1].scissor = bbox;
	state[1].dest = dest;
	state[1].shape = shape;
	state[1].luminosity = luminosity;
}
Example #12
0
static void
fz_draw_clip_stroke_path(void *user, fz_path *path, fz_rect *rect, fz_stroke_state *stroke, fz_matrix ctm)
{
	fz_draw_device *dev = user;
	fz_colorspace *model = dev->dest->colorspace;
	float expansion = fz_matrix_expansion(ctm);
	float flatness = 0.3f / expansion;
	float linewidth = stroke->linewidth;
	fz_pixmap *mask, *dest;
	fz_bbox bbox;

	if (dev->top == STACK_SIZE)
	{
		fz_warn("assert: too many buffers on stack");
		return;
	}

	if (linewidth * expansion < 0.1f)
		linewidth = 1 / expansion;

	fz_reset_gel(dev->gel, dev->scissor);
	if (stroke->dash_len > 0)
		fz_flatten_dash_path(dev->gel, path, stroke, ctm, flatness, linewidth);
	else
		fz_flatten_stroke_path(dev->gel, path, stroke, ctm, flatness, linewidth);
	fz_sort_gel(dev->gel);

	bbox = fz_bound_gel(dev->gel);
	bbox = fz_intersect_bbox(bbox, dev->scissor);
	if (rect)
		bbox = fz_intersect_bbox(bbox, fz_round_rect(*rect));

	mask = fz_new_pixmap_with_rect(NULL, bbox);
	dest = fz_new_pixmap_with_rect(model, bbox);

	fz_clear_pixmap(mask);
	fz_clear_pixmap(dest);

	if (!fz_is_empty_rect(bbox))
		fz_scan_convert(dev->gel, 0, bbox, mask, NULL);

	dev->stack[dev->top].scissor = dev->scissor;
	dev->stack[dev->top].mask = mask;
	dev->stack[dev->top].dest = dev->dest;
	dev->scissor = bbox;
	dev->dest = dest;
	dev->top++;
}
Example #13
0
static void
fz_draw_begin_tile(void *user, fz_rect area, fz_rect view, float xstep, float ystep, fz_matrix ctm)
{
	fz_draw_device *dev = user;
	fz_colorspace *model = dev->dest->colorspace;
	fz_pixmap *dest;
	fz_bbox bbox;

	/* area, view, xstep, ystep are in pattern space */
	/* ctm maps from pattern space to device space */

	if (dev->top == STACK_SIZE)
	{
		fz_warn("assert: too many buffers on stack");
		return;
	}

	bbox = fz_round_rect(fz_transform_rect(ctm, view));
	dest = fz_new_pixmap_with_rect(model, bbox);
	fz_clear_pixmap(dest);

	dev->stack[dev->top].scissor = dev->scissor;
	dev->stack[dev->top].dest = dev->dest;
	dev->stack[dev->top].xstep = xstep;
	dev->stack[dev->top].ystep = ystep;
	dev->stack[dev->top].area = area;
	dev->stack[dev->top].ctm = ctm;
	dev->top++;

	dev->scissor = bbox;
	dev->dest = dest;
}
Example #14
0
static void
fz_draw_begin_group(void *user, fz_rect rect, int isolated, int knockout, int blendmode, float alpha)
{
	fz_draw_device *dev = user;
	fz_colorspace *model = dev->dest->colorspace;
	fz_bbox bbox;
	fz_pixmap *dest;

	if (dev->top == STACK_SIZE)
	{
		fz_warn("assert: too many buffers on stack");
		return;
	}

	bbox = fz_round_rect(rect);
	bbox = fz_intersect_bbox(bbox, dev->scissor);
	dest = fz_new_pixmap_with_rect(model, bbox);

	fz_clear_pixmap(dest);

	dev->stack[dev->top].alpha = alpha;
	dev->stack[dev->top].blendmode = blendmode;
	dev->stack[dev->top].scissor = dev->scissor;
	dev->stack[dev->top].dest = dev->dest;
	dev->top++;

	dev->scissor = bbox;
	dev->dest = dest;
}
Example #15
0
fz_pixmap *
fz_new_pixmap_from_display_list(fz_context *ctx, fz_display_list *list, const fz_matrix *ctm, fz_colorspace *cs, int background)
{
	fz_rect rect;
	fz_irect irect;
	fz_pixmap *pix;
	fz_device *dev;

	fz_bound_display_list(ctx, list, &rect);
	fz_transform_rect(&rect, ctm);
	fz_round_rect(&irect, &rect);

	pix = fz_new_pixmap_with_bbox(ctx, cs, &irect);
	if (background)
		fz_clear_pixmap_with_value(ctx, pix, 0xFF);
	else
		fz_clear_pixmap(ctx, pix);

	fz_try(ctx)
	{
		dev = fz_new_draw_device(ctx, pix);
		fz_run_display_list(ctx, list, dev, ctm, NULL, NULL);
	}
	fz_always(ctx)
	{
		fz_drop_device(ctx, dev);
	}
	fz_catch(ctx)
	{
		fz_drop_pixmap(ctx, pix);
		fz_rethrow(ctx);
	}

	return pix;
}
Example #16
0
fz_pixmap *
fz_new_pixmap_from_annot(fz_context *ctx, fz_page *page, fz_annot *annot, const fz_matrix *ctm, fz_colorspace *cs)
{
	fz_rect rect;
	fz_irect irect;
	fz_pixmap *pix;
	fz_device *dev;

	fz_bound_annot(ctx, page, annot, &rect);
	fz_transform_rect(&rect, ctm);
	fz_round_rect(&irect, &rect);

	pix = fz_new_pixmap_with_bbox(ctx, cs, &irect);
	fz_clear_pixmap(ctx, pix);

	fz_try(ctx)
	{
		dev = fz_new_draw_device(ctx, pix);
		fz_run_annot(ctx, page, annot, dev, ctm, NULL);
	}
	fz_always(ctx)
	{
		fz_drop_device(ctx, dev);
	}
	fz_catch(ctx)
	{
		fz_drop_pixmap(ctx, pix);
		fz_rethrow(ctx);
	}

	return pix;
}
Example #17
0
File: util.c Project: Enzime/mupdf
fz_pixmap *
fz_new_pixmap_from_page_contents(fz_context *ctx, fz_page *page, const fz_matrix *ctm, fz_colorspace *cs, int alpha)
{
	fz_rect rect;
	fz_irect irect;
	fz_pixmap *pix;
	fz_device *dev;

	fz_bound_page(ctx, page, &rect);
	fz_transform_rect(&rect, ctm);
	fz_round_rect(&irect, &rect);

	pix = fz_new_pixmap_with_bbox(ctx, cs, &irect, alpha);
	if (alpha)
		fz_clear_pixmap(ctx, pix);
	else
		fz_clear_pixmap_with_value(ctx, pix, 0xFF);

	fz_try(ctx)
	{
		dev = fz_new_draw_device(ctx, ctm, pix);
		fz_run_page_contents(ctx, page, dev, &fz_identity, NULL);
	}
	fz_always(ctx)
	{
		fz_drop_device(ctx, dev);
	}
	fz_catch(ctx)
	{
		fz_drop_pixmap(ctx, pix);
		fz_rethrow(ctx);
	}

	return pix;
}
Example #18
0
static void
fz_draw_clip_path(fz_device *devp, fz_path *path, fz_rect *rect, int even_odd, fz_matrix ctm)
{
	fz_draw_device *dev = devp->user;
	float expansion = fz_matrix_expansion(ctm);
	float flatness = 0.3f / expansion;
	fz_bbox bbox;
	fz_draw_state *state = push_stack(dev);
	fz_colorspace *model = state->dest->colorspace;

	fz_reset_gel(dev->gel, state->scissor);
	fz_flatten_fill_path(dev->gel, path, ctm, flatness);
	fz_sort_gel(dev->gel);

	bbox = fz_bound_gel(dev->gel);
	bbox = fz_intersect_bbox(bbox, state->scissor);
	if (rect)
		bbox = fz_intersect_bbox(bbox, fz_bbox_covering_rect(*rect));

	if (fz_is_empty_rect(bbox) || fz_is_rect_gel(dev->gel))
	{
		state[1].scissor = bbox;
		state[1].mask = NULL;
#ifdef DUMP_GROUP_BLENDS
		dump_spaces(dev->top-1, "Clip (rectangular) begin\n");
#endif
		return;
	}

	state[1].mask = fz_new_pixmap_with_bbox(dev->ctx, NULL, bbox);
	fz_clear_pixmap(dev->ctx, state[1].mask);
	state[1].dest = fz_new_pixmap_with_bbox(dev->ctx, model, bbox);
	fz_clear_pixmap(dev->ctx, state[1].dest);
	if (state[1].shape)
	{
		state[1].shape = fz_new_pixmap_with_bbox(dev->ctx, NULL, bbox);
		fz_clear_pixmap(dev->ctx, state[1].shape);
	}

	fz_scan_convert(dev->gel, even_odd, bbox, state[1].mask, NULL);

	state[1].blendmode |= FZ_BLEND_ISOLATED;
	state[1].scissor = bbox;
#ifdef DUMP_GROUP_BLENDS
	dump_spaces(dev->top-1, "Clip (non-rectangular) begin\n");
#endif
}
Example #19
0
static void
fz_draw_begin_tile(fz_context *ctx, void *user, fz_rect area, fz_rect view, float xstep, float ystep, fz_matrix ctm)
{
	fz_draw_device *dev = user;
	fz_colorspace *model = dev->dest->colorspace;
	fz_pixmap *dest;
	fz_bbox bbox;

	/* area, view, xstep, ystep are in pattern space */
	/* ctm maps from pattern space to device space */

	if (dev->top == dev->stack_max)
		fz_grow_stack(dev);

	if (dev->blendmode & FZ_BLEND_KNOCKOUT)
		fz_knockout_begin(ctx, dev);

	bbox = fz_round_rect(fz_transform_rect(ctm, view));
	/* We should never have a bbox that entirely covers our destination.
	 * If we do, then the check for only 1 tile being visible above has
	 * failed. */
	/* SumatraPDF: assertion intentionally disabled
	assert(bbox.x0 > dev->dest->x || bbox.x1 < dev->dest->x + dev->dest->w ||
		bbox.y0 > dev->dest->y || bbox.y1 < dev->dest->y + dev->dest->h);
	/* cf. http://bugs.ghostscript.com/show_bug.cgi?id=692418 */
	dest = fz_new_pixmap_with_limit(ctx, model, bbox.x1 - bbox.x0, bbox.y1 - bbox.y0);
	if (dest)
	{
		dest->x = bbox.x0;
		dest->y = bbox.y0;
	}
	else
	{
		bbox.x1 = bbox.x0;
		bbox.y1 = bbox.y0;
		dest = fz_new_pixmap_with_rect(ctx, model, bbox);
	}
	/* FIXME: See note #1 */
	fz_clear_pixmap(dest);

	dev->stack[dev->top].scissor = dev->scissor;
	dev->stack[dev->top].dest = dev->dest;
	dev->stack[dev->top].shape = dev->shape;
	/* FIXME: See note #1 */
	dev->stack[dev->top].blendmode = dev->blendmode | FZ_BLEND_ISOLATED;
	dev->stack[dev->top].xstep = xstep;
	dev->stack[dev->top].ystep = ystep;
	dev->stack[dev->top].area = area;
	dev->stack[dev->top].ctm = ctm;
#ifdef DUMP_GROUP_BLENDS
	dump_spaces(dev->top, "Tile begin\n");
#endif
	dev->top++;

	dev->scissor = bbox;
	dev->dest = dest;
}
Example #20
0
void
fz_paint_shade(fz_shade *shade, fz_matrix ctm, fz_pixmap *dest, fz_bbox bbox)
{
	unsigned char clut[256][FZ_MAX_COLORS];
	fz_pixmap *temp, *conv;
	float color[FZ_MAX_COLORS];
	int i, k;

		ctm = fz_concat(shade->matrix, ctm);

		if (shade->use_function)
		{
			for (i = 0; i < 256; i++)
			{
			fz_convert_color(shade->colorspace, shade->function[i], dest->colorspace, color);
				for (k = 0; k < dest->colorspace->n; k++)
					clut[i][k] = color[k] * 255;
				clut[i][k] = shade->function[i][shade->colorspace->n] * 255;
			}
		conv = fz_new_pixmap_with_rect(dest->colorspace, bbox);
		temp = fz_new_pixmap_with_rect(fz_device_gray, bbox);
		fz_clear_pixmap(temp);
		}
		else
		{
			temp = dest;
		}

		switch (shade->type)
		{
		case FZ_LINEAR: fz_paint_linear(shade, ctm, temp, bbox); break;
		case FZ_RADIAL: fz_paint_radial(shade, ctm, temp, bbox); break;
	case FZ_MESH: fz_paint_mesh(shade, ctm, temp, bbox); break;
		}

		if (shade->use_function)
		{
			unsigned char *s = temp->samples;
			unsigned char *d = conv->samples;
			int len = temp->w * temp->h;
			while (len--)
			{
				int v = *s++;
				int a = fz_mul255(*s++, clut[v][conv->n - 1]);
				for (k = 0; k < conv->n - 1; k++)
					*d++ = fz_mul255(clut[v][k], a);
				*d++ = a;
			}
			fz_paint_pixmap(dest, conv, 255);
		fz_drop_pixmap(conv);
		fz_drop_pixmap(temp);
	}
}
Example #21
0
	QImage Document::RenderPage (int num, double xRes, double yRes)
	{
		auto page = WrapPage (pdf_load_page (MuDoc_, num), MuDoc_);
		if (!page)
			return QImage ();

#if MUPDF_VERSION < 0x0102
		const auto& rect = pdf_bound_page (MuDoc_, page.get ());
#else
		fz_rect rect;
		pdf_bound_page (MuDoc_, page.get (), &rect);
#endif

		auto px = fz_new_pixmap (MuCtx_, fz_device_bgr, xRes * (rect.x1 - rect.x0), yRes * (rect.y1 - rect.y0));
		fz_clear_pixmap (MuCtx_, px);
		auto dev = fz_new_draw_device (MuCtx_, px);
#if MUPDF_VERSION < 0x0102
		pdf_run_page (MuDoc_, page.get (), dev, fz_scale (xRes, yRes), NULL);
#else
		fz_matrix matrix;
		pdf_run_page (MuDoc_, page.get (), dev, fz_scale (&matrix, xRes, yRes), NULL);
#endif
		fz_free_device (dev);

		const int pxWidth = fz_pixmap_width (MuCtx_, px);
		const int pxHeight = fz_pixmap_height (MuCtx_, px);

		auto samples = fz_pixmap_samples (MuCtx_, px);

		QImage temp (samples, pxWidth, pxHeight, QImage::Format_ARGB32);
		QImage img (QSize (pxWidth, pxHeight), QImage::Format_ARGB32);

		for (int y = 0; y < pxHeight; ++y)
		{
			auto target = reinterpret_cast<QRgb*> (img.scanLine (y));
			const auto source = reinterpret_cast<QRgb*> (temp.scanLine (y));
			std::memcpy (target, source, sizeof (source [0]) * pxWidth);
		}
		fz_drop_pixmap (MuCtx_, px);

		temp = QImage (QSize (pxWidth, pxHeight), QImage::Format_ARGB32);

		QPainter p;
		p.begin (&temp);
		p.fillRect (QRect (QPoint (0, 0), temp.size ()), Qt::white);
		p.drawImage (0, 0, img);
		p.end ();
		return temp;
	}
Example #22
0
static void
svg_dev_fill_shade(fz_context *ctx, fz_device *dev, fz_shade *shade, const fz_matrix *ctm, float alpha)
{
	svg_device *sdev = (svg_device*)dev;
	fz_output *out = sdev->out;

	fz_rect rect;
	fz_irect bbox;
	fz_pixmap *pix;
	fz_buffer *buf = NULL;

	fz_var(buf);

	if (dev->container_len == 0)
		return;

	fz_round_rect(&bbox, fz_intersect_rect(fz_bound_shade(ctx, shade, ctm, &rect), &dev->container[dev->container_len-1].scissor));
	if (fz_is_empty_irect(&bbox))
		return;
	pix = fz_new_pixmap_with_bbox(ctx, fz_device_rgb(ctx), &bbox);
	fz_clear_pixmap(ctx, pix);

	fz_try(ctx)
	{
		fz_paint_shade(ctx, shade, ctm, pix, &bbox);
		buf = fz_new_buffer_from_pixmap_as_png(ctx, pix);
		if (alpha != 1.0f)
			fz_printf(ctx, out, "<g opacity=\"%g\">", alpha);
		fz_printf(ctx, out, "<image x=\"%dpx\" y=\"%dpx\" width=\"%dpx\" height=\"%dpx\" xlink:href=\"data:image/png;base64,", pix->x, pix->y, pix->w, pix->h);
		send_data_base64(ctx, out, buf);
		fz_printf(ctx, out, "\"/>\n");
		if (alpha != 1.0f)
			fz_printf(ctx, out, "</g>");
	}
	fz_always(ctx)
	{
		fz_drop_buffer(ctx, buf);
		fz_drop_pixmap(ctx, pix);
	}
	fz_catch(ctx)
	{
		fz_rethrow(ctx);
	}
}
Example #23
0
static void
fz_draw_end_mask(void *user)
{
	fz_draw_device *dev = user;
	fz_pixmap *mask = dev->dest;
	fz_pixmap *temp, *dest;
	fz_bbox bbox;
	int luminosity;

	if (dev->top == STACK_SIZE)
	{
		fz_warn("assert: too many buffers on stack");
		return;
	}

	if (dev->top > 0)
	{
		/* pop soft mask buffer */
		dev->top--;
		luminosity = dev->stack[dev->top].luminosity;
		dev->scissor = dev->stack[dev->top].scissor;
		dev->dest = dev->stack[dev->top].dest;

		/* convert to alpha mask */
		temp = fz_alpha_from_gray(mask, luminosity);
		fz_drop_pixmap(mask);

		/* create new dest scratch buffer */
		bbox = fz_bound_pixmap(temp);
		dest = fz_new_pixmap_with_rect(dev->dest->colorspace, bbox);
		fz_clear_pixmap(dest);

		/* push soft mask as clip mask */
		dev->stack[dev->top].scissor = dev->scissor;
		dev->stack[dev->top].mask = temp;
		dev->stack[dev->top].dest = dev->dest;
		dev->scissor = bbox;
		dev->dest = dest;
		dev->top++;
	}
}
Example #24
0
static void
fz_draw_begin_mask(void *user, fz_rect rect, int luminosity, fz_colorspace *colorspace, float *colorfv)
{
	fz_draw_device *dev = user;
	fz_pixmap *dest;
	fz_bbox bbox;

	if (dev->top == STACK_SIZE)
	{
		fz_warn("assert: too many buffers on stack");
		return;
	}

	bbox = fz_round_rect(rect);
	bbox = fz_intersect_bbox(bbox, dev->scissor);
	dest = fz_new_pixmap_with_rect(fz_device_gray, bbox);

	if (luminosity)
	{
		float bc;
		if (!colorspace)
			colorspace = fz_device_gray;
		fz_convert_color(colorspace, colorfv, fz_device_gray, &bc);
		fz_clear_pixmap_with_color(dest, bc * 255);
	}
	else
		fz_clear_pixmap(dest);

	dev->stack[dev->top].scissor = dev->scissor;
	dev->stack[dev->top].dest = dev->dest;
	dev->stack[dev->top].luminosity = luminosity;
	dev->top++;

	dev->scissor = bbox;
	dev->dest = dest;
}
Example #25
0
static void
fz_draw_fill_shade(fz_context *ctx, void *user, fz_shade *shade, fz_matrix ctm, float alpha)
{
	fz_draw_device *dev = user;
	fz_colorspace *model = dev->dest->colorspace;
	fz_pixmap *dest = dev->dest;
	fz_rect bounds;
	fz_bbox bbox, scissor;
	float colorfv[FZ_MAX_COLORS];
	unsigned char colorbv[FZ_MAX_COLORS + 1];

	bounds = fz_bound_shade(shade, ctm);
	bbox = fz_intersect_bbox(fz_round_rect(bounds), dev->scissor);
	scissor = dev->scissor;

	// TODO: proper clip by shade->bbox

	if (fz_is_empty_rect(bbox))
		return;

	if (!model)
	{
		fz_warn(ctx, "cannot render shading directly to an alpha mask");
		return;
	}

	if (alpha < 1)
	{
		dest = fz_new_pixmap_with_rect(ctx, dev->dest->colorspace, bbox);
		fz_clear_pixmap(dest);
	}

	if (dev->blendmode & FZ_BLEND_KNOCKOUT)
		fz_knockout_begin(ctx, dev);

	if (shade->use_background)
	{
		unsigned char *s;
		int x, y, n, i;
		fz_convert_color(ctx, shade->colorspace, shade->background, model, colorfv);
		for (i = 0; i < model->n; i++)
			colorbv[i] = colorfv[i] * 255;
		colorbv[i] = 255;

		n = dest->n;
		for (y = scissor.y0; y < scissor.y1; y++)
		{
			s = dest->samples + ((scissor.x0 - dest->x) + (y - dest->y) * dest->w) * dest->n;
			for (x = scissor.x0; x < scissor.x1; x++)
			{
				for (i = 0; i < n; i++)
					*s++ = colorbv[i];
			}
		}
		if (dev->shape)
		{
			for (y = scissor.y0; y < scissor.y1; y++)
			{
				s = dev->shape->samples + (scissor.x0 - dev->shape->x) + (y - dev->shape->y) * dev->shape->w;
				for (x = scissor.x0; x < scissor.x1; x++)
				{
					*s++ = 255;
				}
			}
		}
	}

	fz_paint_shade(ctx, shade, ctm, dest, bbox);
	if (dev->shape)
		fz_clear_pixmap_rect_with_color(dev->shape, 255, bbox);

	if (alpha < 1)
	{
		fz_paint_pixmap(dev->dest, dest, alpha * 255);
		fz_drop_pixmap(ctx, dest);
	}

	if (dev->blendmode & FZ_BLEND_KNOCKOUT)
		fz_knockout_end(ctx, dev);
}
Example #26
0
static void
fz_draw_clip_stroke_text(fz_context *ctx, void *user, fz_text *text, fz_stroke_state *stroke, fz_matrix ctm)
{
	fz_draw_device *dev = user;
	fz_colorspace *model = dev->dest->colorspace;
	fz_bbox bbox;
	fz_pixmap *mask, *dest, *shape;
	fz_matrix tm, trm;
	fz_pixmap *glyph;
	int i, x, y, gid;

	if (dev->top == dev->stack_max)
		fz_grow_stack(dev);

	/* make the mask the exact size needed */
	bbox = fz_round_rect(fz_bound_text(text, ctm));
	bbox = fz_intersect_bbox(bbox, dev->scissor);

	mask = fz_new_pixmap_with_rect(ctx, NULL, bbox);
	fz_clear_pixmap(mask);
	dest = fz_new_pixmap_with_rect(ctx, model, bbox);
	/* FIXME: See note #1 */
	fz_clear_pixmap(dest);
	if (dev->shape)
	{
		shape = fz_new_pixmap_with_rect(ctx, NULL, bbox);
		fz_clear_pixmap(shape);
	}
	else
		shape = dev->shape;

	dev->stack[dev->top].scissor = dev->scissor;
	dev->stack[dev->top].mask = mask;
	dev->stack[dev->top].dest = dev->dest;
	dev->stack[dev->top].shape = dev->shape;
	/* FIXME: See note #1 */
	dev->stack[dev->top].blendmode = dev->blendmode | FZ_BLEND_ISOLATED;
	dev->scissor = bbox;
	dev->dest = dest;
	dev->shape = shape;
#ifdef DUMP_GROUP_BLENDS
	dump_spaces(dev->top, "Clip (stroke text) begin\n");
#endif
	dev->top++;

	if (!fz_is_empty_rect(bbox))
	{
		tm = text->trm;

		for (i = 0; i < text->len; i++)
		{
			gid = text->items[i].gid;
			if (gid < 0)
				continue;

			tm.e = text->items[i].x;
			tm.f = text->items[i].y;
			trm = fz_concat(tm, ctm);
			x = floorf(trm.e);
			y = floorf(trm.f);
			trm.e = QUANT(trm.e - floorf(trm.e), HSUBPIX);
			trm.f = QUANT(trm.f - floorf(trm.f), VSUBPIX);

			glyph = fz_render_stroked_glyph(ctx, dev->cache, text->font, gid, trm, ctm, stroke);
			if (glyph)
			{
				draw_glyph(NULL, mask, glyph, x, y, bbox);
				if (dev->shape)
					draw_glyph(NULL, dev->shape, glyph, x, y, bbox);
				fz_drop_pixmap(ctx, glyph);
			}
		}
	}
}
Example #27
0
static void
fz_draw_clip_text(fz_context *ctx, void *user, fz_text *text, fz_matrix ctm, int accumulate)
{
	fz_draw_device *dev = user;
	fz_colorspace *model = dev->dest->colorspace;
	fz_bbox bbox;
	fz_pixmap *mask, *dest, *shape;
	fz_matrix tm, trm;
	fz_pixmap *glyph;
	int i, x, y, gid;

	/* If accumulate == 0 then this text object is guaranteed complete */
	/* If accumulate == 1 then this text object is the first (or only) in a sequence */
	/* If accumulate == 2 then this text object is a continuation */

	if (dev->top == dev->stack_max)
		fz_grow_stack(dev);

	if (accumulate == 0)
	{
		/* make the mask the exact size needed */
		bbox = fz_round_rect(fz_bound_text(text, ctm));
		bbox = fz_intersect_bbox(bbox, dev->scissor);
	}
	else
	{
		/* be conservative about the size of the mask needed */
		bbox = dev->scissor;
	}

	if (accumulate == 0 || accumulate == 1)
	{
		mask = fz_new_pixmap_with_rect(ctx, NULL, bbox);
		fz_clear_pixmap(mask);
		dest = fz_new_pixmap_with_rect(ctx, model, bbox);
		/* FIXME: See note #1 */
		fz_clear_pixmap(dest);
		if (dev->shape)
		{
			shape = fz_new_pixmap_with_rect(ctx, NULL, bbox);
			fz_clear_pixmap(shape);
		}
		else
			shape = NULL;

		dev->stack[dev->top].scissor = dev->scissor;
		dev->stack[dev->top].mask = mask;
		dev->stack[dev->top].dest = dev->dest;
		dev->stack[dev->top].shape = dev->shape;
		/* FIXME: See note #1 */
		dev->stack[dev->top].blendmode = dev->blendmode | FZ_BLEND_ISOLATED;
		dev->scissor = bbox;
		dev->dest = dest;
		dev->shape = shape;
#ifdef DUMP_GROUP_BLENDS
		dump_spaces(dev->top, "Clip (text) begin\n");
#endif
		dev->top++;
	}
	else
	{
		mask = dev->stack[dev->top-1].mask;
	}

	if (!fz_is_empty_rect(bbox))
	{
		tm = text->trm;

		for (i = 0; i < text->len; i++)
		{
			gid = text->items[i].gid;
			if (gid < 0)
				continue;

			tm.e = text->items[i].x;
			tm.f = text->items[i].y;
			trm = fz_concat(tm, ctm);
			x = floorf(trm.e);
			y = floorf(trm.f);
			trm.e = QUANT(trm.e - floorf(trm.e), HSUBPIX);
			trm.f = QUANT(trm.f - floorf(trm.f), VSUBPIX);

			glyph = fz_render_glyph(ctx, dev->cache, text->font, gid, trm, model);
			if (glyph)
			{
				draw_glyph(NULL, mask, glyph, x, y, bbox);
				if (dev->shape)
					draw_glyph(NULL, dev->shape, glyph, x, y, bbox);
				fz_drop_pixmap(ctx, glyph);
			}
		}
	}
}
Example #28
0
static void
fz_draw_clip_path(fz_context *ctx, void *user, fz_path *path, fz_rect *rect, int even_odd, fz_matrix ctm)
{
	fz_draw_device *dev = user;
	fz_colorspace *model = dev->dest->colorspace;
	float expansion = fz_matrix_expansion(ctm);
	float flatness = 0.3f / expansion;
	fz_pixmap *mask, *dest, *shape;
	fz_bbox bbox;

	if (dev->top == dev->stack_max)
		fz_grow_stack(dev);

	fz_reset_gel(dev->gel, dev->scissor);
	fz_flatten_fill_path(ctx, dev->gel, path, ctm, flatness);
	fz_sort_gel(dev->gel);

	bbox = fz_bound_gel(dev->gel);
	bbox = fz_intersect_bbox(bbox, dev->scissor);
	if (rect)
		bbox = fz_intersect_bbox(bbox, fz_round_rect(*rect));

	if (fz_is_empty_rect(bbox) || fz_is_rect_gel(dev->gel))
	{
		dev->stack[dev->top].scissor = dev->scissor;
		dev->stack[dev->top].mask = NULL;
		dev->stack[dev->top].dest = NULL;
		dev->stack[dev->top].shape = dev->shape;
		dev->stack[dev->top].blendmode = dev->blendmode;
		dev->scissor = bbox;
#ifdef DUMP_GROUP_BLENDS
		dump_spaces(dev->top, "Clip (rectangular) begin\n");
#endif
		dev->top++;
		return;
	}

	mask = fz_new_pixmap_with_rect(ctx, NULL, bbox);
	fz_clear_pixmap(mask);
	dest = fz_new_pixmap_with_rect(ctx, model, bbox);
	/* FIXME: See note #1 */
	fz_clear_pixmap(dest);
	if (dev->shape)
	{
		shape = fz_new_pixmap_with_rect(ctx, NULL, bbox);
		fz_clear_pixmap(shape);
	}
	else
		shape = NULL;

	fz_scan_convert(dev->gel, even_odd, bbox, mask, NULL);

	dev->stack[dev->top].scissor = dev->scissor;
	dev->stack[dev->top].mask = mask;
	dev->stack[dev->top].dest = dev->dest;
	dev->stack[dev->top].shape = dev->shape;
	/* FIXME: See note #1 */
	dev->stack[dev->top].blendmode = dev->blendmode | FZ_BLEND_ISOLATED;
	dev->scissor = bbox;
	dev->dest = dest;
	dev->shape = shape;
#ifdef DUMP_GROUP_BLENDS
	dump_spaces(dev->top, "Clip (non-rectangular) begin\n");
#endif
	dev->top++;
}
Example #29
0
static void
fz_draw_begin_group(fz_context *ctx, void *user, fz_rect rect, int isolated, int knockout, int blendmode, float alpha)
{
	fz_draw_device *dev = user;
	fz_colorspace *model = dev->dest->colorspace;
	fz_bbox bbox;
	fz_pixmap *dest, *shape;

	if (dev->top == dev->stack_max)
	{
		fz_warn(ctx, "assert: too many buffers on stack");
		return;
	}

	if (dev->blendmode & FZ_BLEND_KNOCKOUT)
		fz_knockout_begin(ctx, dev);

	bbox = fz_round_rect(rect);
	bbox = fz_intersect_bbox(bbox, dev->scissor);
	dest = fz_new_pixmap_with_rect(ctx, model, bbox);

#ifndef ATTEMPT_KNOCKOUT_AND_ISOLATED
	knockout = 0;
	isolated = 1;
#endif

	if (isolated)
	{
		fz_clear_pixmap(dest);
	}
	else
	{
		fz_copy_pixmap_rect(dest, dev->dest, bbox);
	}

	if (blendmode == 0 && alpha == 1.0 && isolated || 1 /* SumatraPDF: disable crashy shape code */)
	{
		/* We can render direct to any existing shape plane. If there
		 * isn't one, we don't need to make one. */
		shape = dev->shape;
	}
	else
	{
		shape = fz_new_pixmap_with_rect(ctx, NULL, bbox);
		fz_clear_pixmap(shape);
	}

	dev->stack[dev->top].alpha = alpha;
	dev->stack[dev->top].blendmode = dev->blendmode;
	dev->stack[dev->top].scissor = dev->scissor;
	dev->stack[dev->top].dest = dev->dest;
	dev->stack[dev->top].shape = dev->shape;
#ifdef DUMP_GROUP_BLENDS
	dump_spaces(dev->top, "Group Begin\n");
#endif
	dev->top++;

	dev->scissor = bbox;
	dev->dest = dest;
	dev->shape = shape;
	dev->blendmode = blendmode | (isolated ? FZ_BLEND_ISOLATED : 0) | (knockout ? FZ_BLEND_KNOCKOUT : 0);
}
Example #30
0
static void
fz_draw_clip_image_mask(fz_context *ctx, void *user, fz_pixmap *image, fz_rect *rect, fz_matrix ctm)
{
	fz_draw_device *dev = user;
	fz_colorspace *model = dev->dest->colorspace;
	fz_bbox bbox;
	fz_pixmap *mask, *dest, *shape;
	fz_pixmap *scaled = NULL;
	int dx, dy;

	if (dev->top == dev->stack_max)
		fz_grow_stack(dev);

#ifdef DUMP_GROUP_BLENDS
	dump_spaces(dev->top, "Clip (image mask) begin\n");
#endif

	if (image->w == 0 || image->h == 0)
	{
		dev->stack[dev->top].scissor = dev->scissor;
		dev->stack[dev->top].mask = NULL;
		dev->stack[dev->top].dest = NULL;
		dev->stack[dev->top].blendmode = dev->blendmode;
		dev->scissor = fz_empty_bbox;
		dev->top++;
		return;
	}

	bbox = fz_round_rect(fz_transform_rect(ctm, fz_unit_rect));
	bbox = fz_intersect_bbox(bbox, dev->scissor);
	if (rect)
		bbox = fz_intersect_bbox(bbox, fz_round_rect(*rect));

	mask = fz_new_pixmap_with_rect(ctx, NULL, bbox);
	fz_clear_pixmap(mask);
	dest = fz_new_pixmap_with_rect(ctx, model, bbox);
	/* FIXME: See note #1 */
	fz_clear_pixmap(dest);
	if (dev->shape)
	{
		shape = fz_new_pixmap_with_rect(ctx, NULL, bbox);
		fz_clear_pixmap(shape);
	}
	else
		shape = NULL;

	dx = sqrtf(ctm.a * ctm.a + ctm.b * ctm.b);
	dy = sqrtf(ctm.c * ctm.c + ctm.d * ctm.d);
	if (dx < image->w && dy < image->h)
	{
		int gridfit = !(dev->flags & FZ_DRAWDEV_FLAGS_TYPE3);
		scaled = fz_transform_pixmap(ctx, image, &ctm, dev->dest->x, dev->dest->y, dx, dy, gridfit);
		if (scaled == NULL)
		{
			if (dx < 1)
				dx = 1;
			if (dy < 1)
				dy = 1;
			scaled = fz_scale_pixmap(ctx, image, image->x, image->y, dx, dy);
		}
		if (scaled != NULL)
			image = scaled;
	}

	fz_paint_image(mask, bbox, dev->shape, image, ctm, 255);

	if (scaled)
		fz_drop_pixmap(ctx, scaled);

	dev->stack[dev->top].scissor = dev->scissor;
	dev->stack[dev->top].mask = mask;
	dev->stack[dev->top].dest = dev->dest;
	dev->stack[dev->top].shape = dev->shape;
	/* FIXME: See note #1 */
	dev->stack[dev->top].blendmode = dev->blendmode | FZ_BLEND_ISOLATED;
	dev->scissor = bbox;
	dev->dest = dest;
	dev->shape = shape;
	dev->top++;
}