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; }
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); } }
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); } }
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); }
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); }
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); }
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; }
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; }