Exemple #1
0
static int
xps_gradient_stops_have_transparency(xps_context_t *ctx, char *base_uri, xps_item_t *root)
{
    xps_item_t *node;
    gs_color_space *colorspace;
    char *color_att;
    float samples[32];

    for (node = xps_down(root); node; node = xps_next(node))
    {
        if (!strcmp(xps_tag(node), "GradientStop"))
        {
            color_att = xps_att(node, "Color");
            if (color_att)
            {
                xps_parse_color(ctx, base_uri, color_att, &colorspace, samples);
                if (samples[0] < 1.0)
                {
                    //dmputs(ctx->memory, "page has transparency: GradientStop has alpha\n");
                    return 1;
                }
            }
        }
    }

    return 0;
}
Exemple #2
0
void
xps_begin_opacity(fz_context *ctx, xps_document *doc, const fz_matrix *ctm, const fz_rect *area,
	char *base_uri, xps_resource *dict,
	char *opacity_att, fz_xml *opacity_mask_tag)
{
	fz_device *dev = doc->dev;
	float opacity;

	if (!opacity_att && !opacity_mask_tag)
		return;

	opacity = 1;
	if (opacity_att)
		opacity = fz_atof(opacity_att);

	if (opacity_mask_tag && !strcmp(fz_xml_tag(opacity_mask_tag), "SolidColorBrush"))
	{
		char *scb_opacity_att = fz_xml_att(opacity_mask_tag, "Opacity");
		char *scb_color_att = fz_xml_att(opacity_mask_tag, "Color");
		if (scb_opacity_att)
			opacity = opacity * fz_atof(scb_opacity_att);
		if (scb_color_att)
		{
			fz_colorspace *colorspace;
			float samples[FZ_MAX_COLORS];
			xps_parse_color(ctx, doc, base_uri, scb_color_att, &colorspace, samples);
			opacity = opacity * samples[0];
		}
		opacity_mask_tag = NULL;
	}

	if (doc->opacity_top + 1 < nelem(doc->opacity))
	{
		doc->opacity[doc->opacity_top + 1] = doc->opacity[doc->opacity_top] * opacity;
		doc->opacity_top++;
	}

	if (opacity_mask_tag)
	{
		fz_begin_mask(ctx, dev, area, 0, NULL, NULL);
		xps_parse_brush(ctx, doc, ctm, area, base_uri, dict, opacity_mask_tag);
		fz_end_mask(ctx, dev);
	}
}
Exemple #3
0
void
xps_begin_opacity(xps_document *doc, fz_matrix ctm, fz_rect area,
	char *base_uri, xps_resource *dict,
	char *opacity_att, xml_element *opacity_mask_tag)
{
	float opacity;

	if (!opacity_att && !opacity_mask_tag)
		return;

	opacity = 1;
	if (opacity_att)
		opacity = fz_atof(opacity_att);

	if (opacity_mask_tag && !strcmp(xml_tag(opacity_mask_tag), "SolidColorBrush"))
	{
		char *scb_opacity_att = xml_att(opacity_mask_tag, "Opacity");
		char *scb_color_att = xml_att(opacity_mask_tag, "Color");
		if (scb_opacity_att)
			opacity = opacity * fz_atof(scb_opacity_att);
		if (scb_color_att)
		{
			fz_colorspace *colorspace;
			float samples[32];
			xps_parse_color(doc, base_uri, scb_color_att, &colorspace, samples);
			opacity = opacity * samples[0];
		}
		opacity_mask_tag = NULL;
	}

	if (doc->opacity_top + 1 < nelem(doc->opacity))
	{
		doc->opacity[doc->opacity_top + 1] = doc->opacity[doc->opacity_top] * opacity;
		doc->opacity_top++;
	}

	if (opacity_mask_tag)
	{
		fz_begin_mask(doc->dev, area, 0, NULL, NULL);
		xps_parse_brush(doc, ctm, area, base_uri, dict, opacity_mask_tag);
		fz_end_mask(doc->dev);
	}
}
Exemple #4
0
static int
xps_parse_gradient_stops(fz_context *ctx, xps_document *doc, char *base_uri, fz_xml *node,
	struct stop *stops, int maxcount)
{
	fz_colorspace *colorspace;
	float sample[FZ_MAX_COLORS];
	float rgb[3];
	int before, after;
	int count;
	int i;

	/* We may have to insert 2 extra stops when postprocessing */
	maxcount -= 2;

	count = 0;
	while (node && count < maxcount)
	{
		if (fz_xml_is_tag(node, "GradientStop"))
		{
			char *offset = fz_xml_att(node, "Offset");
			char *color = fz_xml_att(node, "Color");
			if (offset && color)
			{
				stops[count].offset = fz_atof(offset);
				stops[count].index = count;

				xps_parse_color(ctx, doc, base_uri, color, &colorspace, sample);

				fz_convert_color(ctx, fz_device_rgb(ctx), rgb, colorspace, sample + 1);

				stops[count].r = rgb[0];
				stops[count].g = rgb[1];
				stops[count].b = rgb[2];
				stops[count].a = sample[0];

				count ++;
			}
		}
		node = fz_xml_next(node);
	}

	if (count == 0)
	{
		fz_warn(ctx, "gradient brush has no gradient stops");
		stops[0].offset = 0;
		stops[0].r = 0;
		stops[0].g = 0;
		stops[0].b = 0;
		stops[0].a = 1;
		stops[1].offset = 1;
		stops[1].r = 1;
		stops[1].g = 1;
		stops[1].b = 1;
		stops[1].a = 1;
		return 2;
	}

	if (count == maxcount)
		fz_warn(ctx, "gradient brush exceeded maximum number of gradient stops");

	/* Postprocess to make sure the range of offsets is 0.0 to 1.0 */

	qsort(stops, count, sizeof(struct stop), cmp_stop);

	before = -1;
	after = -1;

	for (i = 0; i < count; i++)
	{
		if (stops[i].offset < 0)
			before = i;
		if (stops[i].offset > 1)
		{
			after = i;
			break;
		}
	}

	/* Remove all stops < 0 except the largest one */
	if (before > 0)
	{
		memmove(stops, stops + before, (count - before) * sizeof(struct stop));
		count -= before;
	}

	/* Remove all stops > 1 except the smallest one */
	if (after >= 0)
		count = after + 1;

	/* Expand single stop to 0 .. 1 */
	if (count == 1)
	{
		stops[1] = stops[0];
		stops[0].offset = 0;
		stops[1].offset = 1;
		return 2;
	}

	/* First stop < 0 -- interpolate value to 0 */
	if (stops[0].offset < 0)
	{
		float d = -stops[0].offset / (stops[1].offset - stops[0].offset);
		stops[0].offset = 0;
		stops[0].r = lerp(stops[0].r, stops[1].r, d);
		stops[0].g = lerp(stops[0].g, stops[1].g, d);
		stops[0].b = lerp(stops[0].b, stops[1].b, d);
		stops[0].a = lerp(stops[0].a, stops[1].a, d);
	}

	/* Last stop > 1 -- interpolate value to 1 */
	if (stops[count-1].offset > 1)
	{
		float d = (1 - stops[count-2].offset) / (stops[count-1].offset - stops[count-2].offset);
		stops[count-1].offset = 1;
		stops[count-1].r = lerp(stops[count-2].r, stops[count-1].r, d);
		stops[count-1].g = lerp(stops[count-2].g, stops[count-1].g, d);
		stops[count-1].b = lerp(stops[count-2].b, stops[count-1].b, d);
		stops[count-1].a = lerp(stops[count-2].a, stops[count-1].a, d);
	}

	/* First stop > 0 -- insert a duplicate at 0 */
	if (stops[0].offset > 0)
	{
		memmove(stops + 1, stops, count * sizeof(struct stop));
		stops[0] = stops[1];
		stops[0].offset = 0;
		count++;
	}

	/* Last stop < 1 -- insert a duplicate at 1 */
	if (stops[count-1].offset < 1)
	{
		stops[count] = stops[count-1];
		stops[count].offset = 1;
		count++;
	}

	return count;
}
void
xps_parse_path(xps_document *doc, const fz_matrix *ctm, char *base_uri, xps_resource *dict, fz_xml *root)
{
	fz_xml *node;

	char *fill_uri;
	char *stroke_uri;
	char *opacity_mask_uri;

	char *transform_att;
	char *clip_att;
	char *data_att;
	char *fill_att;
	char *stroke_att;
	char *opacity_att;
	char *opacity_mask_att;

	fz_xml *transform_tag = NULL;
	fz_xml *clip_tag = NULL;
	fz_xml *data_tag = NULL;
	fz_xml *fill_tag = NULL;
	fz_xml *stroke_tag = NULL;
	fz_xml *opacity_mask_tag = NULL;

	char *fill_opacity_att = NULL;
	char *stroke_opacity_att = NULL;

	char *stroke_dash_array_att;
	char *stroke_dash_cap_att;
	char *stroke_dash_offset_att;
	char *stroke_end_line_cap_att;
	char *stroke_start_line_cap_att;
	char *stroke_line_join_att;
	char *stroke_miter_limit_att;
	char *stroke_thickness_att;
	char *navigate_uri_att;

	fz_stroke_state *stroke = NULL;
	fz_matrix transform;
	float samples[32];
	fz_colorspace *colorspace;
	fz_path *path = NULL;
	fz_path *stroke_path = NULL;
	fz_rect area;
	int fill_rule;
	int dash_len = 0;
	fz_matrix local_ctm;

	/*
	 * Extract attributes and extended attributes.
	 */

	transform_att = fz_xml_att(root, "RenderTransform");
	clip_att = fz_xml_att(root, "Clip");
	data_att = fz_xml_att(root, "Data");
	fill_att = fz_xml_att(root, "Fill");
	stroke_att = fz_xml_att(root, "Stroke");
	opacity_att = fz_xml_att(root, "Opacity");
	opacity_mask_att = fz_xml_att(root, "OpacityMask");

	stroke_dash_array_att = fz_xml_att(root, "StrokeDashArray");
	stroke_dash_cap_att = fz_xml_att(root, "StrokeDashCap");
	stroke_dash_offset_att = fz_xml_att(root, "StrokeDashOffset");
	stroke_end_line_cap_att = fz_xml_att(root, "StrokeEndLineCap");
	stroke_start_line_cap_att = fz_xml_att(root, "StrokeStartLineCap");
	stroke_line_join_att = fz_xml_att(root, "StrokeLineJoin");
	stroke_miter_limit_att = fz_xml_att(root, "StrokeMiterLimit");
	stroke_thickness_att = fz_xml_att(root, "StrokeThickness");
	navigate_uri_att = fz_xml_att(root, "FixedPage.NavigateUri");

	for (node = fz_xml_down(root); node; node = fz_xml_next(node))
	{
		if (!strcmp(fz_xml_tag(node), "Path.RenderTransform"))
			transform_tag = fz_xml_down(node);
		if (!strcmp(fz_xml_tag(node), "Path.OpacityMask"))
			opacity_mask_tag = fz_xml_down(node);
		if (!strcmp(fz_xml_tag(node), "Path.Clip"))
			clip_tag = fz_xml_down(node);
		if (!strcmp(fz_xml_tag(node), "Path.Fill"))
			fill_tag = fz_xml_down(node);
		if (!strcmp(fz_xml_tag(node), "Path.Stroke"))
			stroke_tag = fz_xml_down(node);
		if (!strcmp(fz_xml_tag(node), "Path.Data"))
			data_tag = fz_xml_down(node);
	}

	fill_uri = base_uri;
	stroke_uri = base_uri;
	opacity_mask_uri = base_uri;

	xps_resolve_resource_reference(doc, dict, &data_att, &data_tag, NULL);
	xps_resolve_resource_reference(doc, dict, &clip_att, &clip_tag, NULL);
	xps_resolve_resource_reference(doc, dict, &transform_att, &transform_tag, NULL);
	xps_resolve_resource_reference(doc, dict, &fill_att, &fill_tag, &fill_uri);
	xps_resolve_resource_reference(doc, dict, &stroke_att, &stroke_tag, &stroke_uri);
	xps_resolve_resource_reference(doc, dict, &opacity_mask_att, &opacity_mask_tag, &opacity_mask_uri);

	/*
	 * Act on the information we have gathered:
	 */

	if (!data_att && !data_tag)
		return;

	if (fill_tag && !strcmp(fz_xml_tag(fill_tag), "SolidColorBrush"))
	{
		fill_opacity_att = fz_xml_att(fill_tag, "Opacity");
		fill_att = fz_xml_att(fill_tag, "Color");
		fill_tag = NULL;
	}

	if (stroke_tag && !strcmp(fz_xml_tag(stroke_tag), "SolidColorBrush"))
	{
		stroke_opacity_att = fz_xml_att(stroke_tag, "Opacity");
		stroke_att = fz_xml_att(stroke_tag, "Color");
		stroke_tag = NULL;
	}

	if (stroke_att || stroke_tag)
	{
		if (stroke_dash_array_att)
		{
			char *s = stroke_dash_array_att;

			while (*s)
			{
				while (*s == ' ')
					s++;
				if (*s) /* needed in case of a space before the last quote */
					dash_len++;

				while (*s && *s != ' ')
					s++;
			}
		}
		stroke = fz_new_stroke_state_with_len(doc->ctx, dash_len);
		stroke->start_cap = xps_parse_line_cap(stroke_start_line_cap_att);
		stroke->dash_cap = xps_parse_line_cap(stroke_dash_cap_att);
		stroke->end_cap = xps_parse_line_cap(stroke_end_line_cap_att);

		stroke->linejoin = FZ_LINEJOIN_MITER_XPS;
		if (stroke_line_join_att)
		{
			if (!strcmp(stroke_line_join_att, "Miter")) stroke->linejoin = FZ_LINEJOIN_MITER_XPS;
			if (!strcmp(stroke_line_join_att, "Round")) stroke->linejoin = FZ_LINEJOIN_ROUND;
			if (!strcmp(stroke_line_join_att, "Bevel")) stroke->linejoin = FZ_LINEJOIN_BEVEL;
		}

		stroke->miterlimit = 10;
		if (stroke_miter_limit_att)
			stroke->miterlimit = fz_atof(stroke_miter_limit_att);

		stroke->linewidth = 1;
		if (stroke_thickness_att)
			stroke->linewidth = fz_atof(stroke_thickness_att);

		stroke->dash_phase = 0;
		stroke->dash_len = 0;
		if (stroke_dash_array_att)
		{
			char *s = stroke_dash_array_att;

			if (stroke_dash_offset_att)
				stroke->dash_phase = fz_atof(stroke_dash_offset_att) * stroke->linewidth;

			while (*s)
			{
				while (*s == ' ')
					s++;
				if (*s) /* needed in case of a space before the last quote */
					stroke->dash_list[stroke->dash_len++] = fz_atof(s) * stroke->linewidth;
				while (*s && *s != ' ')
					s++;
			}
			/* cf. https://code.google.com/p/sumatrapdf/issues/detail?id=2339 */
			if (dash_len > 0)
			{
				float phase_len = 0.0f;
				int i;
				for (i = 0; i < dash_len; i++)
					phase_len += stroke->dash_list[i];
				if (phase_len == 0.0f)
					dash_len = 0;
			}
			stroke->dash_len = dash_len;
		}
	}

	transform = fz_identity;
	if (transform_att)
		xps_parse_render_transform(doc, transform_att, &transform);
	if (transform_tag)
		xps_parse_matrix_transform(doc, transform_tag, &transform);
	fz_concat(&local_ctm, &transform, ctm);

	if (clip_att || clip_tag)
		xps_clip(doc, &local_ctm, dict, clip_att, clip_tag);

	fill_rule = 0;
	if (data_att)
		path = xps_parse_abbreviated_geometry(doc, data_att, &fill_rule);
	else if (data_tag)
	{
		path = xps_parse_path_geometry(doc, dict, data_tag, 0, &fill_rule);
		if (stroke_att || stroke_tag)
			stroke_path = xps_parse_path_geometry(doc, dict, data_tag, 1, &fill_rule);
	}
	if (!stroke_path)
		stroke_path = path;

	if (stroke_att || stroke_tag)
	{
		fz_bound_path(doc->ctx, stroke_path, stroke, &local_ctm, &area);
		if (stroke_path != path && (fill_att || fill_tag)) {
			fz_rect bounds;
			fz_bound_path(doc->ctx, path, NULL, &local_ctm, &bounds);
			fz_union_rect(&area, &bounds);
		}
	}
	else
		fz_bound_path(doc->ctx, path, NULL, &local_ctm, &area);

	/* SumatraPDF: extended link support */
	xps_extract_anchor_info(doc, &area, navigate_uri_att, fz_xml_att(root, "Name"), 0);
	navigate_uri_att = NULL;

	if (navigate_uri_att)
		xps_add_link(doc, &area, base_uri, navigate_uri_att);

	xps_begin_opacity(doc, &local_ctm, &area, opacity_mask_uri, dict, opacity_att, opacity_mask_tag);

	if (fill_att)
	{
		xps_parse_color(doc, base_uri, fill_att, &colorspace, samples);
		if (fill_opacity_att)
			samples[0] *= fz_atof(fill_opacity_att);
		xps_set_color(doc, colorspace, samples);

		fz_fill_path(doc->dev, path, fill_rule == 0, &local_ctm,
			doc->colorspace, doc->color, doc->alpha);
	}

	if (fill_tag)
	{
		fz_clip_path(doc->dev, path, NULL, fill_rule == 0, &local_ctm);
		xps_parse_brush(doc, &local_ctm, &area, fill_uri, dict, fill_tag);
		fz_pop_clip(doc->dev);
	}

	if (stroke_att)
	{
		xps_parse_color(doc, base_uri, stroke_att, &colorspace, samples);
		if (stroke_opacity_att)
			samples[0] *= fz_atof(stroke_opacity_att);
		xps_set_color(doc, colorspace, samples);

		fz_stroke_path(doc->dev, stroke_path, stroke, &local_ctm,
			doc->colorspace, doc->color, doc->alpha);
	}

	if (stroke_tag)
	{
		fz_clip_stroke_path(doc->dev, stroke_path, NULL, stroke, &local_ctm);
		xps_parse_brush(doc, &local_ctm, &area, stroke_uri, dict, stroke_tag);
		fz_pop_clip(doc->dev);
	}

	xps_end_opacity(doc, opacity_mask_uri, dict, opacity_att, opacity_mask_tag);

	if (stroke_path != path)
		fz_free_path(doc->ctx, stroke_path);
	fz_free_path(doc->ctx, path);
	path = NULL;
	fz_drop_stroke_state(doc->ctx, stroke);

	if (clip_att || clip_tag)
		fz_pop_clip(doc->dev);
}
Exemple #6
0
void
xps_parse_path(xps_document *doc, fz_matrix ctm, char *base_uri, xps_resource *dict, xml_element *root)
{
    xml_element *node;

    char *fill_uri;
    char *stroke_uri;
    char *opacity_mask_uri;

    char *transform_att;
    char *clip_att;
    char *data_att;
    char *fill_att;
    char *stroke_att;
    char *opacity_att;
    char *opacity_mask_att;

    xml_element *transform_tag = NULL;
    xml_element *clip_tag = NULL;
    xml_element *data_tag = NULL;
    xml_element *fill_tag = NULL;
    xml_element *stroke_tag = NULL;
    xml_element *opacity_mask_tag = NULL;

    char *fill_opacity_att = NULL;
    char *stroke_opacity_att = NULL;

    char *stroke_dash_array_att;
    char *stroke_dash_cap_att;
    char *stroke_dash_offset_att;
    char *stroke_end_line_cap_att;
    char *stroke_start_line_cap_att;
    char *stroke_line_join_att;
    char *stroke_miter_limit_att;
    char *stroke_thickness_att;
    char *navigate_uri_att;

    fz_stroke_state stroke;
    fz_matrix transform;
    float samples[32];
    fz_colorspace *colorspace;
    fz_path *path;
    fz_rect area;
    int fill_rule;

    /*
     * Extract attributes and extended attributes.
     */

    transform_att = xml_att(root, "RenderTransform");
    clip_att = xml_att(root, "Clip");
    data_att = xml_att(root, "Data");
    fill_att = xml_att(root, "Fill");
    stroke_att = xml_att(root, "Stroke");
    opacity_att = xml_att(root, "Opacity");
    opacity_mask_att = xml_att(root, "OpacityMask");

    stroke_dash_array_att = xml_att(root, "StrokeDashArray");
    stroke_dash_cap_att = xml_att(root, "StrokeDashCap");
    stroke_dash_offset_att = xml_att(root, "StrokeDashOffset");
    stroke_end_line_cap_att = xml_att(root, "StrokeEndLineCap");
    stroke_start_line_cap_att = xml_att(root, "StrokeStartLineCap");
    stroke_line_join_att = xml_att(root, "StrokeLineJoin");
    stroke_miter_limit_att = xml_att(root, "StrokeMiterLimit");
    stroke_thickness_att = xml_att(root, "StrokeThickness");
    navigate_uri_att = xml_att(root, "FixedPage.NavigateUri");

    for (node = xml_down(root); node; node = xml_next(node))
    {
        if (!strcmp(xml_tag(node), "Path.RenderTransform"))
            transform_tag = xml_down(node);
        if (!strcmp(xml_tag(node), "Path.OpacityMask"))
            opacity_mask_tag = xml_down(node);
        if (!strcmp(xml_tag(node), "Path.Clip"))
            clip_tag = xml_down(node);
        if (!strcmp(xml_tag(node), "Path.Fill"))
            fill_tag = xml_down(node);
        if (!strcmp(xml_tag(node), "Path.Stroke"))
            stroke_tag = xml_down(node);
        if (!strcmp(xml_tag(node), "Path.Data"))
            data_tag = xml_down(node);
    }

    fill_uri = base_uri;
    stroke_uri = base_uri;
    opacity_mask_uri = base_uri;

    xps_resolve_resource_reference(doc, dict, &data_att, &data_tag, NULL);
    xps_resolve_resource_reference(doc, dict, &clip_att, &clip_tag, NULL);
    xps_resolve_resource_reference(doc, dict, &transform_att, &transform_tag, NULL);
    xps_resolve_resource_reference(doc, dict, &fill_att, &fill_tag, &fill_uri);
    xps_resolve_resource_reference(doc, dict, &stroke_att, &stroke_tag, &stroke_uri);
    xps_resolve_resource_reference(doc, dict, &opacity_mask_att, &opacity_mask_tag, &opacity_mask_uri);

    /*
     * Act on the information we have gathered:
     */

    if (!data_att && !data_tag)
        return;

    if (fill_tag && !strcmp(xml_tag(fill_tag), "SolidColorBrush"))
    {
        fill_opacity_att = xml_att(fill_tag, "Opacity");
        fill_att = xml_att(fill_tag, "Color");
        fill_tag = NULL;
    }

    if (stroke_tag && !strcmp(xml_tag(stroke_tag), "SolidColorBrush"))
    {
        stroke_opacity_att = xml_att(stroke_tag, "Opacity");
        stroke_att = xml_att(stroke_tag, "Color");
        stroke_tag = NULL;
    }

    stroke.start_cap = xps_parse_line_cap(stroke_start_line_cap_att);
    stroke.dash_cap = xps_parse_line_cap(stroke_dash_cap_att);
    stroke.end_cap = xps_parse_line_cap(stroke_end_line_cap_att);

    stroke.linejoin = FZ_LINEJOIN_MITER_XPS;
    if (stroke_line_join_att)
    {
        if (!strcmp(stroke_line_join_att, "Miter")) stroke.linejoin = FZ_LINEJOIN_MITER_XPS;
        if (!strcmp(stroke_line_join_att, "Round")) stroke.linejoin = FZ_LINEJOIN_ROUND;
        if (!strcmp(stroke_line_join_att, "Bevel")) stroke.linejoin = FZ_LINEJOIN_BEVEL;
    }

    stroke.miterlimit = 10;
    if (stroke_miter_limit_att)
        stroke.miterlimit = fz_atof(stroke_miter_limit_att);

    stroke.linewidth = 1;
    if (stroke_thickness_att)
        stroke.linewidth = fz_atof(stroke_thickness_att);

    stroke.dash_phase = 0;
    stroke.dash_len = 0;
    if (stroke_dash_array_att)
    {
        char *s = stroke_dash_array_att;

        if (stroke_dash_offset_att)
            stroke.dash_phase = fz_atof(stroke_dash_offset_att) * stroke.linewidth;

        while (*s && stroke.dash_len < nelem(stroke.dash_list))
        {
            while (*s == ' ')
                s++;
            if (*s) /* needed in case of a space before the last quote */
                stroke.dash_list[stroke.dash_len++] = fz_atof(s) * stroke.linewidth;
            while (*s && *s != ' ')
                s++;
        }
    }

    transform = fz_identity;
    if (transform_att)
        xps_parse_render_transform(doc, transform_att, &transform);
    if (transform_tag)
        xps_parse_matrix_transform(doc, transform_tag, &transform);
    ctm = fz_concat(transform, ctm);

    if (clip_att || clip_tag)
        xps_clip(doc, ctm, dict, clip_att, clip_tag);

    fill_rule = 0;
    if (data_att)
        path = xps_parse_abbreviated_geometry(doc, data_att, &fill_rule);
    else if (data_tag)
        path = xps_parse_path_geometry(doc, dict, data_tag, 0, &fill_rule);

    if (stroke_att || stroke_tag)
        area = fz_bound_path(doc->ctx, path, &stroke, ctm);
    else
        area = fz_bound_path(doc->ctx, path, NULL, ctm);

    if (navigate_uri_att)
        xps_add_link(doc, area, base_uri, navigate_uri_att);

    xps_begin_opacity(doc, ctm, area, opacity_mask_uri, dict, opacity_att, opacity_mask_tag);

    if (fill_att)
    {
        xps_parse_color(doc, base_uri, fill_att, &colorspace, samples);
        if (fill_opacity_att)
            samples[0] = fz_atof(fill_opacity_att);
        xps_set_color(doc, colorspace, samples);

        fz_fill_path(doc->dev, path, fill_rule == 0, ctm,
                     doc->colorspace, doc->color, doc->alpha);
    }

    if (fill_tag)
    {
        area = fz_bound_path(doc->ctx, path, NULL, ctm);

        fz_clip_path(doc->dev, path, NULL, fill_rule == 0, ctm);
        xps_parse_brush(doc, ctm, area, fill_uri, dict, fill_tag);
        fz_pop_clip(doc->dev);
    }

    if (stroke_att)
    {
        xps_parse_color(doc, base_uri, stroke_att, &colorspace, samples);
        if (stroke_opacity_att)
            samples[0] = fz_atof(stroke_opacity_att);
        xps_set_color(doc, colorspace, samples);

        fz_stroke_path(doc->dev, path, &stroke, ctm,
                       doc->colorspace, doc->color, doc->alpha);
    }

    if (stroke_tag)
    {
        fz_clip_stroke_path(doc->dev, path, NULL, &stroke, ctm);
        xps_parse_brush(doc, ctm, area, stroke_uri, dict, stroke_tag);
        fz_pop_clip(doc->dev);
    }

    xps_end_opacity(doc, opacity_mask_uri, dict, opacity_att, opacity_mask_tag);

    fz_free_path(doc->ctx, path);
    path = NULL;

    if (clip_att || clip_tag)
        fz_pop_clip(doc->dev);
}
Exemple #7
0
void
xps_parse_path(fz_context *ctx, xps_document *doc, fz_matrix ctm, char *base_uri, xps_resource *dict, fz_xml *root)
{
	fz_device *dev = doc->dev;

	fz_xml *node;

	char *fill_uri;
	char *stroke_uri;
	char *opacity_mask_uri;

	char *transform_att;
	char *clip_att;
	char *data_att;
	char *fill_att;
	char *stroke_att;
	char *opacity_att;
	char *opacity_mask_att;

	fz_xml *transform_tag = NULL;
	fz_xml *clip_tag = NULL;
	fz_xml *data_tag = NULL;
	fz_xml *fill_tag = NULL;
	fz_xml *stroke_tag = NULL;
	fz_xml *opacity_mask_tag = NULL;

	char *fill_opacity_att = NULL;
	char *stroke_opacity_att = NULL;

	char *stroke_dash_array_att;
	char *stroke_dash_cap_att;
	char *stroke_dash_offset_att;
	char *stroke_end_line_cap_att;
	char *stroke_start_line_cap_att;
	char *stroke_line_join_att;
	char *stroke_miter_limit_att;
	char *stroke_thickness_att;

	fz_stroke_state *stroke = NULL;
	float samples[FZ_MAX_COLORS];
	fz_colorspace *colorspace;
	fz_path *path = NULL;
	fz_path *stroke_path = NULL;
	fz_rect area;
	int fill_rule;
	int dash_len = 0;

	/*
	 * Extract attributes and extended attributes.
	 */

	transform_att = fz_xml_att(root, "RenderTransform");
	clip_att = fz_xml_att(root, "Clip");
	data_att = fz_xml_att(root, "Data");
	fill_att = fz_xml_att(root, "Fill");
	stroke_att = fz_xml_att(root, "Stroke");
	opacity_att = fz_xml_att(root, "Opacity");
	opacity_mask_att = fz_xml_att(root, "OpacityMask");

	stroke_dash_array_att = fz_xml_att(root, "StrokeDashArray");
	stroke_dash_cap_att = fz_xml_att(root, "StrokeDashCap");
	stroke_dash_offset_att = fz_xml_att(root, "StrokeDashOffset");
	stroke_end_line_cap_att = fz_xml_att(root, "StrokeEndLineCap");
	stroke_start_line_cap_att = fz_xml_att(root, "StrokeStartLineCap");
	stroke_line_join_att = fz_xml_att(root, "StrokeLineJoin");
	stroke_miter_limit_att = fz_xml_att(root, "StrokeMiterLimit");
	stroke_thickness_att = fz_xml_att(root, "StrokeThickness");

	for (node = fz_xml_down(root); node; node = fz_xml_next(node))
	{
		if (fz_xml_is_tag(node, "Path.RenderTransform"))
			transform_tag = fz_xml_down(node);
		if (fz_xml_is_tag(node, "Path.OpacityMask"))
			opacity_mask_tag = fz_xml_down(node);
		if (fz_xml_is_tag(node, "Path.Clip"))
			clip_tag = fz_xml_down(node);
		if (fz_xml_is_tag(node, "Path.Fill"))
			fill_tag = fz_xml_down(node);
		if (fz_xml_is_tag(node, "Path.Stroke"))
			stroke_tag = fz_xml_down(node);
		if (fz_xml_is_tag(node, "Path.Data"))
			data_tag = fz_xml_down(node);
	}

	fill_uri = base_uri;
	stroke_uri = base_uri;
	opacity_mask_uri = base_uri;

	xps_resolve_resource_reference(ctx, doc, dict, &data_att, &data_tag, NULL);
	xps_resolve_resource_reference(ctx, doc, dict, &clip_att, &clip_tag, NULL);
	xps_resolve_resource_reference(ctx, doc, dict, &transform_att, &transform_tag, NULL);
	xps_resolve_resource_reference(ctx, doc, dict, &fill_att, &fill_tag, &fill_uri);
	xps_resolve_resource_reference(ctx, doc, dict, &stroke_att, &stroke_tag, &stroke_uri);
	xps_resolve_resource_reference(ctx, doc, dict, &opacity_mask_att, &opacity_mask_tag, &opacity_mask_uri);

	/*
	 * Act on the information we have gathered:
	 */

	if (!data_att && !data_tag)
		return;

	if (fz_xml_is_tag(fill_tag, "SolidColorBrush"))
	{
		fill_opacity_att = fz_xml_att(fill_tag, "Opacity");
		fill_att = fz_xml_att(fill_tag, "Color");
		fill_tag = NULL;
	}

	if (fz_xml_is_tag(stroke_tag, "SolidColorBrush"))
	{
		stroke_opacity_att = fz_xml_att(stroke_tag, "Opacity");
		stroke_att = fz_xml_att(stroke_tag, "Color");
		stroke_tag = NULL;
	}

	if (stroke_att || stroke_tag)
	{
		if (stroke_dash_array_att)
		{
			char *s = stroke_dash_array_att;

			while (*s)
			{
				while (*s == ' ')
					s++;
				if (*s) /* needed in case of a space before the last quote */
					dash_len++;

				while (*s && *s != ' ')
					s++;
			}
		}
		stroke = fz_new_stroke_state_with_dash_len(ctx, dash_len);
		stroke->start_cap = xps_parse_line_cap(stroke_start_line_cap_att);
		stroke->dash_cap = xps_parse_line_cap(stroke_dash_cap_att);
		stroke->end_cap = xps_parse_line_cap(stroke_end_line_cap_att);

		stroke->linejoin = FZ_LINEJOIN_MITER_XPS;
		if (stroke_line_join_att)
		{
			if (!strcmp(stroke_line_join_att, "Miter")) stroke->linejoin = FZ_LINEJOIN_MITER_XPS;
			if (!strcmp(stroke_line_join_att, "Round")) stroke->linejoin = FZ_LINEJOIN_ROUND;
			if (!strcmp(stroke_line_join_att, "Bevel")) stroke->linejoin = FZ_LINEJOIN_BEVEL;
		}

		stroke->miterlimit = 10;
		if (stroke_miter_limit_att)
			stroke->miterlimit = fz_atof(stroke_miter_limit_att);

		stroke->linewidth = 1;
		if (stroke_thickness_att)
			stroke->linewidth = fz_atof(stroke_thickness_att);

		stroke->dash_phase = 0;
		stroke->dash_len = 0;
		if (stroke_dash_array_att)
		{
			char *s = stroke_dash_array_att;

			if (stroke_dash_offset_att)
				stroke->dash_phase = fz_atof(stroke_dash_offset_att) * stroke->linewidth;

			while (*s)
			{
				while (*s == ' ')
					s++;
				if (*s) /* needed in case of a space before the last quote */
					stroke->dash_list[stroke->dash_len++] = fz_atof(s) * stroke->linewidth;
				while (*s && *s != ' ')
					s++;
			}
			if (dash_len > 0)
			{
				/* fz_stroke_path doesn't draw non-empty paths with phase length zero */
				float phase_len = 0;
				int i;
				for (i = 0; i < dash_len; i++)
					phase_len += stroke->dash_list[i];
				if (phase_len == 0)
					dash_len = 0;
			}
			stroke->dash_len = dash_len;
		}
	}

	ctm = xps_parse_transform(ctx, doc, transform_att, transform_tag, ctm);

	if (clip_att || clip_tag)
		xps_clip(ctx, doc, ctm, dict, clip_att, clip_tag);

	fz_try(ctx)
	{
		fill_rule = 0;
		if (data_att)
			path = xps_parse_abbreviated_geometry(ctx, doc, data_att, &fill_rule);
		else if (data_tag)
		{
			path = xps_parse_path_geometry(ctx, doc, dict, data_tag, 0, &fill_rule);
			// /home/sebras/src/jxr/fts_06xx.xps
			if (stroke_att || stroke_tag)
				stroke_path = xps_parse_path_geometry(ctx, doc, dict, data_tag, 1, &fill_rule);
		}
		if (!stroke_path)
			stroke_path = path;

		if (stroke_att || stroke_tag)
		{
			area = fz_bound_path(ctx, stroke_path, stroke, ctm);
			if (stroke_path != path && (fill_att || fill_tag)) {
				fz_rect bounds = fz_bound_path(ctx, path, NULL, ctm);
				area = fz_union_rect(area, bounds);
			}
		}
		else
			area = fz_bound_path(ctx, path, NULL, ctm);

		xps_begin_opacity(ctx, doc, ctm, area, opacity_mask_uri, dict, opacity_att, opacity_mask_tag);

		if (fill_att)
		{
			xps_parse_color(ctx, doc, base_uri, fill_att, &colorspace, samples);
			if (fill_opacity_att)
				samples[0] *= fz_atof(fill_opacity_att);
			xps_set_color(ctx, doc, colorspace, samples);
			fz_fill_path(ctx, dev, path, fill_rule == 0, ctm,
				doc->colorspace, doc->color, doc->alpha, NULL);
		}

		if (fill_tag)
		{
			fz_clip_path(ctx, dev, path, fill_rule == 0, ctm, area);
			xps_parse_brush(ctx, doc, ctm, area, fill_uri, dict, fill_tag);
			fz_pop_clip(ctx, dev);
		}

		if (stroke_att)
		{
			xps_parse_color(ctx, doc, base_uri, stroke_att, &colorspace, samples);
			if (stroke_opacity_att)
				samples[0] *= fz_atof(stroke_opacity_att);
			xps_set_color(ctx, doc, colorspace, samples);
			fz_stroke_path(ctx, dev, stroke_path, stroke, ctm,
				doc->colorspace, doc->color, doc->alpha, NULL);
		}

		if (stroke_tag)
		{
			fz_clip_stroke_path(ctx, dev, stroke_path, stroke, ctm, area);
			xps_parse_brush(ctx, doc, ctm, area, stroke_uri, dict, stroke_tag);
			fz_pop_clip(ctx, dev);
		}

		xps_end_opacity(ctx, doc, opacity_mask_uri, dict, opacity_att, opacity_mask_tag);
	}
	fz_always(ctx)
	{
		if (stroke_path != path)
			fz_drop_path(ctx, stroke_path);
		fz_drop_path(ctx, path);
		fz_drop_stroke_state(ctx, stroke);
	}
	fz_catch(ctx)
		fz_rethrow(ctx);

	if (clip_att || clip_tag)
		fz_pop_clip(ctx, dev);
}
Exemple #8
0
int
xps_element_has_transparency(xps_context_t *ctx, char *base_uri, xps_item_t *node)
{
    char *opacity_att;
    char *stroke_att;
    char *fill_att;

    gs_color_space *colorspace;
    float samples[32];

    stroke_att = xps_att(node, "Stroke");
    if (stroke_att)
    {
        xps_parse_color(ctx, base_uri, stroke_att, &colorspace, samples);
        if (samples[0] < 1.0 && samples[0] != 0.0)
        {
            //dmprintf1(ctx->memory, "page has transparency: Stroke alpha=%g\n", samples[0]);
            return 1;
        }
    }

    fill_att = xps_att(node, "Fill");
    if (fill_att)
    {
        xps_parse_color(ctx, base_uri, fill_att, &colorspace, samples);
        if (samples[0] < 1.0 && samples[0] != 0.0)
        {
            //dmprintf1(ctx->memory, "page has transparency: Fill alpha=%g\n", samples[0]);
            return 1;
        }
    }

    opacity_att = xps_att(node, "Opacity");
    if (opacity_att)
    {
        float opacity = atof(opacity_att);
        if (opacity < 1.0 && opacity != 0.0)
        {
            //dmprintf1(ctx->memory, "page has transparency: Opacity=%g\n", atof(opacity_att));
            return 1;
        }
    }

    if (xps_att(node, "OpacityMask"))
    {
        //dmputs(ctx->memory, "page has transparency: OpacityMask\n");
        return 1;
    }

    if (!strcmp(xps_tag(node), "Path"))
        if (xps_path_has_transparency(ctx, base_uri, node))
            return 1;
    if (!strcmp(xps_tag(node), "Glyphs"))
        if (xps_glyphs_has_transparency(ctx, base_uri, node))
            return 1;
    if (!strcmp(xps_tag(node), "Canvas"))
        if (xps_canvas_has_transparency(ctx, base_uri, node))
            return 1;

    return 0;
}
Exemple #9
0
static int
xps_brush_has_transparency(xps_context_t *ctx, char *base_uri, xps_item_t *root)
{
    char *opacity_att;
    char *color_att;
    xps_item_t *node;

    gs_color_space *colorspace;
    float samples[32];

    if (!strcmp(xps_tag(root), "SolidColorBrush"))
    {
        opacity_att = xps_att(root, "Opacity");
        if (opacity_att)
        {
            float opacity = atof(opacity_att);
            if (opacity < 1.0 && opacity != 0.0)
            {
                //dmputs(ctx->memory, "page has transparency: SolidColorBrush Opacity\n");
                return 1;
            }
        }

        color_att = xps_att(root, "Color");
        if (color_att)
        {
            xps_parse_color(ctx, base_uri, color_att, &colorspace, samples);
            if (samples[0] < 1.0 && samples[0] != 0.0)
            {
                //dmputs(ctx->memory, "page has transparency: SolidColorBrush Color has alpha\n");
                return 1;
            }
        }
    }

    if (!strcmp(xps_tag(root), "VisualBrush"))
    {
        char *opacity_att = xps_att(root, "Opacity");
        if (opacity_att)
        {
            if (atof(opacity_att) < 1.0)
            {
                //dmputs(ctx->memory, "page has transparency: VisualBrush Opacity\n");
                return 1;
            }
        }

        for (node = xps_down(root); node; node = xps_next(node))
        {
            if (!strcmp(xps_tag(node), "VisualBrush.Visual"))
            {
                if (xps_element_has_transparency(ctx, base_uri, xps_down(node)))
                    return 1;
            }
        }
    }

    if (!strcmp(xps_tag(root), "ImageBrush"))
    {
        if (xps_image_brush_has_transparency(ctx, base_uri, root))
            return 1;
    }

    if (!strcmp(xps_tag(root), "LinearGradientBrush"))
    {
        if (xps_gradient_brush_has_transparency(ctx, base_uri, root))
            return 1;
    }

    if (!strcmp(xps_tag(root), "RadialGradientBrush"))
    {
        if (xps_gradient_brush_has_transparency(ctx, base_uri, root))
            return 1;
    }

    return 0;
}