Ejemplo n.º 1
0
static void
xps_load_links_in_fixed_page(fz_context *ctx, xps_document *doc, const fz_matrix *ctm, xps_page *page, fz_link **link)
{
	fz_xml *node, *resource_tag;
	xps_resource *dict = NULL;
	char base_uri[1024];
	char *s;

	if (!page->root)
		return;

	fz_strlcpy(base_uri, page->fix->name, sizeof base_uri);
	s = strrchr(base_uri, '/');
	if (s)
		s[1] = 0;

	resource_tag = fz_xml_down(fz_xml_find_down(page->root, "FixedPage.Resources"));
	if (resource_tag)
		dict = xps_parse_resource_dictionary(ctx, doc, base_uri, resource_tag);

	for (node = fz_xml_down(page->root); node; node = fz_xml_next(node))
		xps_load_links_in_element(ctx, doc, ctm, base_uri, dict, node, link);

	if (dict)
		xps_drop_resource_dictionary(ctx, doc, dict);
}
Ejemplo n.º 2
0
static xps_resource *
xps_parse_remote_resource_dictionary(xps_document *doc, char *base_uri, char *source_att)
{
	char part_name[1024];
	char part_uri[1024];
	xps_resource *dict;
	xps_part *part;
	xml_element *xml;
	char *s;

	/* External resource dictionaries MUST NOT reference other resource dictionaries */
	xps_resolve_url(part_name, base_uri, source_att, sizeof part_name);
	part = xps_read_part(doc, part_name);
	xml = xml_parse_document(doc->ctx, part->data, part->size);
	xps_free_part(doc, part);

	if (strcmp(xml_tag(xml), "ResourceDictionary"))
	{
		xml_free_element(doc->ctx, xml);
		fz_throw(doc->ctx, "expected ResourceDictionary element (found %s)", xml_tag(xml));
	}

	fz_strlcpy(part_uri, part_name, sizeof part_uri);
	s = strrchr(part_uri, '/');
	if (s)
		s[1] = 0;

	dict = xps_parse_resource_dictionary(doc, part_uri, xml);
	if (dict)
		dict->base_xml = xml; /* pass on ownership */

	return dict;
}
Ejemplo n.º 3
0
static int
xps_parse_remote_resource_dictionary(xps_context *ctx, xps_resource **dictp, char *base_uri, char *source_att)
{
	char part_name[1024];
	char part_uri[1024];
	xps_resource *dict;
	xps_part *part;
	xml_element *xml;
	char *s;
	int code;

	/* External resource dictionaries MUST NOT reference other resource dictionaries */
	xps_absolute_path(part_name, base_uri, source_att, sizeof part_name);
	part = xps_read_part(ctx, part_name);
	if (!part)
	{
		return fz_throw("cannot find remote resource part '%s'", part_name);
	}

	xml = xml_parse_document(part->data, part->size);
	if (!xml)
	{
		xps_free_part(ctx, part);
		return fz_rethrow(-1, "cannot parse xml");
	}

	if (strcmp(xml_tag(xml), "ResourceDictionary"))
	{
		xml_free_element(xml);
		xps_free_part(ctx, part);
		return fz_throw("expected ResourceDictionary element (found %s)", xml_tag(xml));
	}

	fz_strlcpy(part_uri, part_name, sizeof part_uri);
	s = strrchr(part_uri, '/');
	if (s)
		s[1] = 0;

	code = xps_parse_resource_dictionary(ctx, &dict, part_uri, xml);
	if (code)
	{
		xml_free_element(xml);
		xps_free_part(ctx, part);
		return fz_rethrow(code, "cannot parse remote resource dictionary: %s", part_uri);
	}

	dict->base_xml = xml; /* pass on ownership */

	xps_free_part(ctx, part);

	*dictp = dict;
	return fz_okay;
}
Ejemplo n.º 4
0
void
xps_parse_fixed_page(fz_context *ctx, xps_document *doc, const fz_matrix *ctm, xps_page *page)
{
	fz_xml *root, *node;
	xps_resource *dict;
	char base_uri[1024];
	fz_rect area;
	char *s;
	fz_matrix scm;

	fz_strlcpy(base_uri, page->fix->name, sizeof base_uri);
	s = strrchr(base_uri, '/');
	if (s)
		s[1] = 0;

	dict = NULL;

	doc->opacity_top = 0;
	doc->opacity[0] = 1;

	root = fz_xml_root(page->xml);
	if (!root)
		return;

	area = fz_unit_rect;
	fz_transform_rect(&area, fz_scale(&scm, page->fix->width, page->fix->height));

	fz_try(ctx)
	{
		for (node = fz_xml_down(root); node; node = fz_xml_next(node))
		{
			if (fz_xml_is_tag(node, "FixedPage.Resources") && fz_xml_down(node))
			{
				if (dict)
					fz_warn(ctx, "ignoring follow-up resource dictionaries");
				else
					dict = xps_parse_resource_dictionary(ctx, doc, base_uri, fz_xml_down(node));
			}
			xps_parse_element(ctx, doc, ctm, &area, base_uri, dict, node);
		}
	}
	fz_always(ctx)
		xps_drop_resource_dictionary(ctx, doc, dict);
	fz_catch(ctx)
		fz_rethrow(ctx);
}
Ejemplo n.º 5
0
static xps_resource *
xps_parse_remote_resource_dictionary(fz_context *ctx, xps_document *doc, char *base_uri, char *source_att)
{
	char part_name[1024];
	char part_uri[1024];
	xps_part *part;
	xps_resource *dict = NULL;
	fz_xml_doc *xml = NULL;
	char *s;

	fz_var(xml);

	/* External resource dictionaries MUST NOT reference other resource dictionaries */
	xps_resolve_url(ctx, doc, part_name, base_uri, source_att, sizeof part_name);

	part = xps_read_part(ctx, doc, part_name);
	fz_try(ctx)
	{
		xml = fz_parse_xml(ctx, part->data, 0);
		if (!fz_xml_is_tag(fz_xml_root(xml), "ResourceDictionary"))
			fz_throw(ctx, FZ_ERROR_GENERIC, "expected ResourceDictionary element");

		fz_strlcpy(part_uri, part_name, sizeof part_uri);
		s = strrchr(part_uri, '/');
		if (s)
			s[1] = 0;

		dict = xps_parse_resource_dictionary(ctx, doc, part_uri, fz_xml_root(xml));
		if (dict)
		{
			dict->base_xml = xml; /* pass on ownership */
			xml = NULL;
		}
	}
	fz_always(ctx)
	{
		xps_drop_part(ctx, doc, part);
		fz_drop_xml(ctx, xml);
	}
	fz_catch(ctx)
	{
		fz_rethrow(ctx);
	}

	return dict;
}
Ejemplo n.º 6
0
void
xps_parse_fixed_page(xps_document *doc, const fz_matrix *ctm, xps_page *page)
{
	fz_xml *node;
	xps_resource *dict;
	char base_uri[1024];
	fz_rect area;
	char *s;
	fz_matrix scm;

	fz_strlcpy(base_uri, page->name, sizeof base_uri);
	s = strrchr(base_uri, '/');
	if (s)
		s[1] = 0;

	dict = NULL;

	doc->opacity_top = 0;
	doc->opacity[0] = 1;

	if (!page->root)
		return;

	area = fz_unit_rect;
	fz_transform_rect(&area, fz_scale(&scm, page->width, page->height));

	for (node = fz_xml_down(page->root); node; node = fz_xml_next(node))
	{
		if (!strcmp(fz_xml_tag(node), "FixedPage.Resources") && fz_xml_down(node))
		{
			if (dict)
				fz_warn(doc->ctx, "ignoring follow-up resource dictionaries");
			else
				dict = xps_parse_resource_dictionary(doc, base_uri, fz_xml_down(node));
		}
		xps_parse_element(doc, ctm, &area, base_uri, dict, node);
	}

	if (dict)
		xps_free_resource_dictionary(doc, dict);
}
Ejemplo n.º 7
0
void
xps_parse_fixed_page(xps_context *ctx, fz_matrix ctm, xps_page *page)
{
	xml_element *node;
	xps_resource *dict;
	char base_uri[1024];
	fz_rect area;
	char *s;
	int code;

	fz_strlcpy(base_uri, page->name, sizeof base_uri);
	s = strrchr(base_uri, '/');
	if (s)
		s[1] = 0;

	dict = NULL;

	ctx->opacity_top = 0;
	ctx->opacity[0] = 1;

	if (!page->root)
		return;

	area = fz_transform_rect(fz_scale(page->width, page->height), fz_unit_rect);

	for (node = xml_down(page->root); node; node = xml_next(node))
	{
		if (!strcmp(xml_tag(node), "FixedPage.Resources") && xml_down(node))
		{
			code = xps_parse_resource_dictionary(ctx, &dict, base_uri, xml_down(node));
			if (code)
				fz_catch(code, "cannot load FixedPage.Resources");
		}
		xps_parse_element(ctx, ctm, area, base_uri, dict, node);
	}

	if (dict)
	{
		xps_free_resource_dictionary(ctx, dict);
	}
}
Ejemplo n.º 8
0
static void
xps_load_links_in_canvas(fz_context *ctx, xps_document *doc, const fz_matrix *ctm,
		char *base_uri, xps_resource *dict, fz_xml *root, fz_link **link)
{
	xps_resource *new_dict = NULL;
	fz_matrix local_ctm;
	fz_xml *node;

	char *navigate_uri_att = fz_xml_att(root, "FixedPage.NavigateUri");
	char *transform_att = fz_xml_att(root, "RenderTransform");
	fz_xml *transform_tag = fz_xml_down(fz_xml_find_down(root, "Canvas.RenderTransform"));
	fz_xml *resource_tag = fz_xml_down(fz_xml_find_down(root, "Canvas.Resources"));

	if (resource_tag)
	{
		new_dict = xps_parse_resource_dictionary(ctx, doc, base_uri, resource_tag);
		if (new_dict)
		{
			new_dict->parent = dict;
			dict = new_dict;
		}
	}

	xps_resolve_resource_reference(ctx, doc, dict, &transform_att, &transform_tag, NULL);

	xps_parse_transform(ctx, doc, transform_att, transform_tag, &local_ctm, ctm);

	if (navigate_uri_att)
		fz_warn(ctx, "FixedPage.NavigateUri attribute on Canvas element");

	for (node = fz_xml_down(root); node; node = fz_xml_next(node))
		xps_load_links_in_element(ctx, doc, &local_ctm, base_uri, dict, node, link);

	if (new_dict)
		xps_drop_resource_dictionary(ctx, doc, new_dict);
}
Ejemplo n.º 9
0
void
xps_parse_canvas(fz_context *ctx, xps_document *doc, const fz_matrix *ctm, const fz_rect *area, char *base_uri, xps_resource *dict, fz_xml *root)
{
	fz_device *dev = doc->dev;
	xps_resource *new_dict = NULL;
	fz_xml *node;
	char *opacity_mask_uri;

	char *transform_att;
	char *clip_att;
	char *opacity_att;
	char *opacity_mask_att;
	char *navigate_uri_att;

	fz_xml *transform_tag = NULL;
	fz_xml *clip_tag = NULL;
	fz_xml *opacity_mask_tag = NULL;

	fz_matrix transform;

	transform_att = fz_xml_att(root, "RenderTransform");
	clip_att = fz_xml_att(root, "Clip");
	opacity_att = fz_xml_att(root, "Opacity");
	opacity_mask_att = fz_xml_att(root, "OpacityMask");
	navigate_uri_att = fz_xml_att(root, "FixedPage.NavigateUri");

	for (node = fz_xml_down(root); node; node = fz_xml_next(node))
	{
		if (fz_xml_is_tag(node, "Canvas.Resources") && fz_xml_down(node))
		{
			if (new_dict)
			{
				fz_warn(ctx, "ignoring follow-up resource dictionaries");
			}
			else
			{
				new_dict = xps_parse_resource_dictionary(ctx, doc, base_uri, fz_xml_down(node));
				if (new_dict)
				{
					new_dict->parent = dict;
					dict = new_dict;
				}
			}
		}

		if (fz_xml_is_tag(node, "Canvas.RenderTransform"))
			transform_tag = fz_xml_down(node);
		if (fz_xml_is_tag(node, "Canvas.Clip"))
			clip_tag = fz_xml_down(node);
		if (fz_xml_is_tag(node, "Canvas.OpacityMask"))
			opacity_mask_tag = fz_xml_down(node);
	}

	opacity_mask_uri = base_uri;
	xps_resolve_resource_reference(ctx, doc, dict, &transform_att, &transform_tag, NULL);
	xps_resolve_resource_reference(ctx, doc, dict, &clip_att, &clip_tag, NULL);
	xps_resolve_resource_reference(ctx, doc, dict, &opacity_mask_att, &opacity_mask_tag, &opacity_mask_uri);

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

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

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

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

	for (node = fz_xml_down(root); node; node = fz_xml_next(node))
	{
		xps_parse_element(ctx, doc, &transform, area, base_uri, dict, node);
	}

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

	if (clip_att || clip_tag)
		fz_pop_clip(ctx, dev);

	if (new_dict)
		xps_drop_resource_dictionary(ctx, doc, new_dict);
}
Ejemplo n.º 10
0
void
xps_parse_canvas(xps_document *doc, const fz_matrix *ctm, const fz_rect *area, char *base_uri, xps_resource *dict, fz_xml *root)
{
	xps_resource *new_dict = NULL;
	fz_xml *node;
	char *opacity_mask_uri;

	char *transform_att;
	char *clip_att;
	char *opacity_att;
	char *opacity_mask_att;
	char *navigate_uri_att;

	fz_xml *transform_tag = NULL;
	fz_xml *clip_tag = NULL;
	fz_xml *opacity_mask_tag = NULL;

	fz_matrix transform;

	transform_att = fz_xml_att(root, "RenderTransform");
	clip_att = fz_xml_att(root, "Clip");
	opacity_att = fz_xml_att(root, "Opacity");
	opacity_mask_att = fz_xml_att(root, "OpacityMask");
	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), "Canvas.Resources") && fz_xml_down(node))
		{
			if (new_dict)
			{
				fz_warn(doc->ctx, "ignoring follow-up resource dictionaries");
			}
			else
			{
				new_dict = xps_parse_resource_dictionary(doc, base_uri, fz_xml_down(node));
				if (new_dict)
				{
					new_dict->parent = dict;
					dict = new_dict;
				}
			}
		}

		if (!strcmp(fz_xml_tag(node), "Canvas.RenderTransform"))
			transform_tag = fz_xml_down(node);
		if (!strcmp(fz_xml_tag(node), "Canvas.Clip"))
			clip_tag = fz_xml_down(node);
		if (!strcmp(fz_xml_tag(node), "Canvas.OpacityMask"))
			opacity_mask_tag = fz_xml_down(node);
	}

	opacity_mask_uri = base_uri;
	xps_resolve_resource_reference(doc, dict, &transform_att, &transform_tag, NULL);
	xps_resolve_resource_reference(doc, dict, &clip_att, &clip_tag, NULL);
	xps_resolve_resource_reference(doc, dict, &opacity_mask_att, &opacity_mask_tag, &opacity_mask_uri);

	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(&transform, &transform, ctm);

	/* SumatraPDF: extended link support */
	xps_extract_anchor_info(doc, &fz_empty_rect, navigate_uri_att, NULL, 1);
	navigate_uri_att = NULL;

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

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

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

	for (node = fz_xml_down(root); node; node = fz_xml_next(node))
	{
		xps_parse_element(doc, &transform, area, base_uri, dict, node);
	}

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

	/* SumatraPDF: extended link support */
	xps_extract_anchor_info(doc, area, NULL, fz_xml_att(root, "Name"), 2);

	if (clip_att || clip_tag)
		fz_pop_clip(doc->dev);

	if (new_dict)
		xps_free_resource_dictionary(doc, new_dict);
}
Ejemplo n.º 11
0
void
xps_parse_canvas(xps_context *ctx, fz_matrix ctm, fz_rect area, char *base_uri, xps_resource *dict, xml_element *root)
{
	xps_resource *new_dict = NULL;
	xml_element *node;
	char *opacity_mask_uri;
	int code;

	char *transform_att;
	char *clip_att;
	char *opacity_att;
	char *opacity_mask_att;

	xml_element *transform_tag = NULL;
	xml_element *clip_tag = NULL;
	xml_element *opacity_mask_tag = NULL;

	fz_matrix transform;

	transform_att = xml_att(root, "RenderTransform");
	clip_att = xml_att(root, "Clip");
	opacity_att = xml_att(root, "Opacity");
	opacity_mask_att = xml_att(root, "OpacityMask");

	for (node = xml_down(root); node; node = xml_next(node))
	{
		if (!strcmp(xml_tag(node), "Canvas.Resources") && xml_down(node))
		{
			code = xps_parse_resource_dictionary(ctx, &new_dict, base_uri, xml_down(node));
			if (code)
				fz_catch(code, "cannot load Canvas.Resources");
			else
			{
				new_dict->parent = dict;
				dict = new_dict;
			}
		}

		if (!strcmp(xml_tag(node), "Canvas.RenderTransform"))
			transform_tag = xml_down(node);
		if (!strcmp(xml_tag(node), "Canvas.Clip"))
			clip_tag = xml_down(node);
		if (!strcmp(xml_tag(node), "Canvas.OpacityMask"))
			opacity_mask_tag = xml_down(node);
	}

	opacity_mask_uri = base_uri;
	xps_resolve_resource_reference(ctx, dict, &transform_att, &transform_tag, NULL);
	xps_resolve_resource_reference(ctx, dict, &clip_att, &clip_tag, NULL);
	xps_resolve_resource_reference(ctx, dict, &opacity_mask_att, &opacity_mask_tag, &opacity_mask_uri);

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

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

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

	for (node = xml_down(root); node; node = xml_next(node))
	{
		xps_parse_element(ctx, ctm, area, base_uri, dict, node);
	}

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

	if (clip_att || clip_tag)
		fz_pop_clip(ctx->dev);

	if (new_dict)
		xps_free_resource_dictionary(ctx, new_dict);
}
Ejemplo n.º 12
0
int
xps_parse_canvas(xps_context_t *ctx, char *base_uri, xps_resource_t *dict, xps_item_t *root)
{
    xps_resource_t *new_dict = NULL;
    xps_item_t *node;
    char *opacity_mask_uri;
    int code;

    char *transform_att;
    char *clip_att;
    char *opacity_att;
    char *opacity_mask_att;

    xps_item_t *transform_tag = NULL;
    xps_item_t *clip_tag = NULL;
    xps_item_t *opacity_mask_tag = NULL;

    gs_matrix transform;

    transform_att = xps_att(root, "RenderTransform");
    clip_att = xps_att(root, "Clip");
    opacity_att = xps_att(root, "Opacity");
    opacity_mask_att = xps_att(root, "OpacityMask");

    for (node = xps_down(root); node; node = xps_next(node))
    {
        if (!strcmp(xps_tag(node), "Canvas.Resources") && xps_down(node))
        {
            code = xps_parse_resource_dictionary(ctx, &new_dict, base_uri, xps_down(node));
            if (code)
                return gs_rethrow(code, "cannot load Canvas.Resources");
            if (new_dict && new_dict != dict)
            {
                new_dict->parent = dict;
                dict = new_dict;
            }
        }

        if (!strcmp(xps_tag(node), "Canvas.RenderTransform"))
            transform_tag = xps_down(node);
        if (!strcmp(xps_tag(node), "Canvas.Clip"))
            clip_tag = xps_down(node);
        if (!strcmp(xps_tag(node), "Canvas.OpacityMask"))
            opacity_mask_tag = xps_down(node);
    }

    opacity_mask_uri = base_uri;
    xps_resolve_resource_reference(ctx, dict, &transform_att, &transform_tag, NULL);
    xps_resolve_resource_reference(ctx, dict, &clip_att, &clip_tag, NULL);
    xps_resolve_resource_reference(ctx, dict, &opacity_mask_att, &opacity_mask_tag, &opacity_mask_uri);

    gs_gsave(ctx->pgs);

    gs_make_identity(&transform);
    if (transform_att)
        xps_parse_render_transform(ctx, transform_att, &transform);
    if (transform_tag)
        xps_parse_matrix_transform(ctx, transform_tag, &transform);
    gs_concat(ctx->pgs, &transform);

    if (clip_att || clip_tag)
    {
        if (clip_att)
            xps_parse_abbreviated_geometry(ctx, clip_att);
        if (clip_tag)
            xps_parse_path_geometry(ctx, dict, clip_tag, 0);
        xps_clip(ctx);
    }

    code = xps_begin_opacity(ctx, opacity_mask_uri, dict, opacity_att, opacity_mask_tag, false, false);
    if (code)
    {
        gs_grestore(ctx->pgs);
        return gs_rethrow(code, "cannot create transparency group");
    }

    for (node = xps_down(root); node; node = xps_next(node))
    {
        code = xps_parse_element(ctx, base_uri, dict, node);
        if (code)
        {
            xps_end_opacity(ctx, opacity_mask_uri, dict, opacity_att, opacity_mask_tag);
            gs_grestore(ctx->pgs);
            return gs_rethrow(code, "cannot parse child of Canvas");
        }
    }

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

    gs_grestore(ctx->pgs);

    if (new_dict)
        xps_free_resource_dictionary(ctx, new_dict);

    return 0;
}
Ejemplo n.º 13
0
int
xps_parse_fixed_page(xps_context_t *ctx, xps_part_t *part)
{
    xps_item_t *root, *node;
    xps_resource_t *dict;
    char *width_att;
    char *height_att;
    char base_uri[1024];
    char *s;
    int code;

    if_debug1m('|', ctx->memory, "doc: parsing page %s\n", part->name);

    xps_strlcpy(base_uri, part->name, sizeof base_uri);
    s = strrchr(base_uri, '/');
    if (s)
        s[1] = 0;

    root = xps_parse_xml(ctx, part->data, part->size);
    if (!root)
        return gs_rethrow(-1, "cannot parse xml");

    if (strcmp(xps_tag(root), "FixedPage"))
        return gs_throw1(-1, "expected FixedPage element (found %s)", xps_tag(root));

    width_att = xps_att(root, "Width");
    height_att = xps_att(root, "Height");

    if (!width_att)
        return gs_throw(-1, "FixedPage missing required attribute: Width");
    if (!height_att)
        return gs_throw(-1, "FixedPage missing required attribute: Height");

    dict = NULL;

    /* Setup new page */
    {
        gs_memory_t *mem = ctx->memory;
        gs_state *pgs = ctx->pgs;
        gx_device *dev = gs_currentdevice(pgs);
        gs_param_float_array fa;
        float fv[2];
        gs_c_param_list list;

        gs_c_param_list_write(&list, mem);

        fv[0] = atoi(width_att) / 96.0 * 72.0;
        fv[1] = atoi(height_att) / 96.0 * 72.0;
        fa.persistent = false;
        fa.data = fv;
        fa.size = 2;

        code = param_write_float_array((gs_param_list *)&list, ".MediaSize", &fa);
        if ( code >= 0 )
        {
            gs_c_param_list_read(&list);
            code = gs_putdeviceparams(dev, (gs_param_list *)&list);
        }
        gs_c_param_list_release(&list);

        /* nb this is for the demo it is wrong and should be removed */
        gs_initgraphics(pgs);

        /* 96 dpi default - and put the origin at the top of the page */

        gs_initmatrix(pgs);

        code = gs_scale(pgs, 72.0/96.0, -72.0/96.0);
        if (code < 0)
            return gs_rethrow(code, "cannot set page transform");

        code = gs_translate(pgs, 0.0, -atoi(height_att));
        if (code < 0)
            return gs_rethrow(code, "cannot set page transform");

        code = gs_erasepage(pgs);
        if (code < 0)
            return gs_rethrow(code, "cannot clear page");
    }

    /* Pre-parse looking for transparency */

    ctx->has_transparency = 0;

    for (node = xps_down(root); node; node = xps_next(node))
    {
        if (!strcmp(xps_tag(node), "FixedPage.Resources") && xps_down(node))
            if (xps_resource_dictionary_has_transparency(ctx, base_uri, xps_down(node)))
                ctx->has_transparency = 1;
        if (xps_element_has_transparency(ctx, base_uri, node))
            ctx->has_transparency = 1;
    }

    /* save the state with the original device before we push */
    gs_gsave(ctx->pgs);

    if (ctx->use_transparency && ctx->has_transparency)
    {
        code = gs_push_pdf14trans_device(ctx->pgs, false);
        if (code < 0)
        {
            gs_grestore(ctx->pgs);
            return gs_rethrow(code, "cannot install transparency device");
        }
    }

    /* Draw contents */

    for (node = xps_down(root); node; node = xps_next(node))
    {
        if (!strcmp(xps_tag(node), "FixedPage.Resources") && xps_down(node))
        {
            code = xps_parse_resource_dictionary(ctx, &dict, base_uri, xps_down(node));
            if (code)
            {
                gs_pop_pdf14trans_device(ctx->pgs, false);
                gs_grestore(ctx->pgs);
                return gs_rethrow(code, "cannot load FixedPage.Resources");
            }
        }
        code = xps_parse_element(ctx, base_uri, dict, node);
        if (code)
        {
            gs_pop_pdf14trans_device(ctx->pgs, false);
            gs_grestore(ctx->pgs);
            return gs_rethrow(code, "cannot parse child of FixedPage");
        }
    }

    if (ctx->use_transparency && ctx->has_transparency)
    {
        code = gs_pop_pdf14trans_device(ctx->pgs, false);
        if (code < 0)
        {
            gs_grestore(ctx->pgs);
            return gs_rethrow(code, "cannot uninstall transparency device");
        }
    }

    /* Flush page */
    {
        code = xps_show_page(ctx, 1, true); /* copies, flush */
        if (code < 0)
        {
            gs_grestore(ctx->pgs);
            return gs_rethrow(code, "cannot flush page");
        }
    }

    /* restore the original device, discarding the pdf14 compositor */
    gs_grestore(ctx->pgs);

    if (dict)
    {
        xps_free_resource_dictionary(ctx, dict);
    }

    xps_free_item(ctx, root);

    return 0;
}