📄 cairo-svg-surface.c
字号:
if (i >= num_elements) { cairo_surface_t *paginated_surface; cairo_surface_t *svg_surface; cairo_meta_snapshot_t new_snapshot; meta = (cairo_meta_surface_t *) _cairo_surface_snapshot ((cairo_surface_t *)surface); paginated_surface = _cairo_svg_surface_create_for_document (document, meta->content, meta->width_pixels, meta->height_pixels); svg_surface = _cairo_paginated_surface_get_target (paginated_surface); cairo_surface_set_fallback_resolution (paginated_surface, document->owner->x_fallback_resolution, document->owner->y_fallback_resolution); _cairo_meta_surface_replay ((cairo_surface_t *)meta, paginated_surface); _cairo_surface_show_page (paginated_surface); new_snapshot.meta = meta; new_snapshot.id = ((cairo_svg_surface_t *) svg_surface)->id; _cairo_array_append (&document->meta_snapshots, &new_snapshot); if (meta->content == CAIRO_CONTENT_ALPHA) { emit_alpha_filter (document); _cairo_output_stream_printf (document->xml_node_defs, "<g id=\"surface%d\" " "clip-path=\"url(#clip%d)\" " "filter=\"url(#alpha)\">\n", ((cairo_svg_surface_t *) svg_surface)->id, ((cairo_svg_surface_t *) svg_surface)->base_clip); } else { _cairo_output_stream_printf (document->xml_node_defs, "<g id=\"surface%d\" " "clip-path=\"url(#clip%d)\">\n", ((cairo_svg_surface_t *) svg_surface)->id, ((cairo_svg_surface_t *) svg_surface)->base_clip); } contents = ((cairo_svg_surface_t *) svg_surface)->xml_node; _cairo_memory_stream_copy (contents, document->xml_node_defs); for (i = 0; i < ((cairo_svg_surface_t *) svg_surface)->clip_level; i++) _cairo_output_stream_printf (document->xml_node_defs, "</g>\n"); _cairo_output_stream_printf (document->xml_node_defs, "</g>\n"); id = new_snapshot.id; cairo_surface_destroy (paginated_surface); /* FIXME: cairo_paginated_surface doesn't take a ref to the * passed in target surface so we can't call destroy here. * cairo_paginated_surface should be fixed, but for now just * work around it. */ /* cairo_surface_destroy (svg_surface); */ } return id;}static cairo_status_temit_composite_meta_pattern (cairo_output_stream_t *output, cairo_svg_surface_t *surface, cairo_surface_pattern_t *pattern, int pattern_id, const char *extra_attributes){ cairo_svg_document_t *document = surface->document; cairo_meta_surface_t *meta_surface; cairo_matrix_t p2u; int id; meta_surface = (cairo_meta_surface_t *) pattern->surface; id = emit_meta_surface (document, meta_surface); p2u = pattern->base.matrix; cairo_matrix_invert (&p2u); if (pattern_id != invalid_pattern_id) { _cairo_output_stream_printf (output, "<pattern id=\"pattern%d\" " "patternUnits=\"userSpaceOnUse\" " "width=\"%d\" height=\"%d\"", pattern_id, meta_surface->width_pixels, meta_surface->height_pixels); emit_transform (output, " patternTransform", ">\n", &p2u); } _cairo_output_stream_printf (output, "<use xlink:href=\"#surface%d\"", id); if (pattern_id == invalid_pattern_id) emit_transform (output, " transform", "", &p2u); if (extra_attributes) _cairo_output_stream_printf (output, " %s", extra_attributes); _cairo_output_stream_printf (output, "/>\n"); if (pattern_id != invalid_pattern_id) _cairo_output_stream_printf (output, "</pattern>\n"); return CAIRO_STATUS_SUCCESS;}static cairo_status_temit_composite_pattern (cairo_output_stream_t *output, cairo_svg_surface_t *surface, cairo_surface_pattern_t *pattern, int pattern_id, const char *extra_attributes){ if (_cairo_surface_is_meta (pattern->surface)) { return emit_composite_meta_pattern (output, surface, pattern, pattern_id, extra_attributes); } return emit_composite_image_pattern (output, surface, pattern, pattern_id, extra_attributes);}static voidemit_operator (cairo_output_stream_t *output, cairo_svg_surface_t *surface, cairo_operator_t op){ char const *op_str[] = { "clear", "src", "src-over", "src-in", "src-out", "src-atop", "dst", "dst-over", "dst-in", "dst-out", "dst-atop", "xor", "plus", "color-dodge" /* FIXME: saturate ? */ }; if (surface->document->svg_version >= CAIRO_SVG_VERSION_1_2) _cairo_output_stream_printf (output, "comp-op: %s; ", op_str[op]);}static voidemit_solid_pattern (cairo_svg_surface_t *surface, cairo_solid_pattern_t *pattern, cairo_output_stream_t *style, cairo_bool_t is_stroke){ _cairo_output_stream_printf (style, "%s: rgb(%f%%,%f%%,%f%%); " "opacity: %f;", is_stroke ? "stroke" : "fill", pattern->color.red * 100.0, pattern->color.green * 100.0, pattern->color.blue * 100.0, pattern->color.alpha);}static voidemit_surface_pattern (cairo_svg_surface_t *surface, cairo_surface_pattern_t *pattern, cairo_output_stream_t *style, cairo_bool_t is_stroke){ cairo_svg_document_t *document = surface->document; int pattern_id; pattern_id = document->pattern_id++; emit_composite_pattern (document->xml_node_defs, surface, pattern, pattern_id, NULL); _cairo_output_stream_printf (style, "%s: url(#pattern%d);", is_stroke ? "color" : "fill", pattern_id);}static voidemit_pattern_stops (cairo_output_stream_t *output, cairo_gradient_pattern_t const *pattern, double start_offset){ double offset; int i; for (i = 0; i < pattern->n_stops; i++) { offset = start_offset + (1 - start_offset ) * _cairo_fixed_to_double (pattern->stops[i].x); _cairo_output_stream_printf (output, "<stop offset=\"%f\" style=\"" "stop-color: rgb(%f%%,%f%%,%f%%); " "stop-opacity: %f;\"/>\n", offset, pattern->stops[i].color.red / 655.35, pattern->stops[i].color.green / 655.35, pattern->stops[i].color.blue / 655.35, pattern->stops[i].color.alpha / 65535.0); }}static voidemit_pattern_extend (cairo_output_stream_t *output, cairo_pattern_t *pattern){ switch (pattern->extend) { case CAIRO_EXTEND_REPEAT: _cairo_output_stream_printf (output, "spreadMethod=\"repeat\" "); break; case CAIRO_EXTEND_REFLECT: _cairo_output_stream_printf (output, "spreadMethod=\"reflect\" "); break; case CAIRO_EXTEND_NONE: break; case CAIRO_EXTEND_PAD: /* FIXME not implemented */ break; }}static voidemit_linear_pattern (cairo_svg_surface_t *surface, cairo_linear_pattern_t *pattern, cairo_output_stream_t *style, cairo_bool_t is_stroke){ cairo_svg_document_t *document = surface->document; double x0, y0, x1, y1; cairo_matrix_t p2u; x0 = _cairo_fixed_to_double (pattern->gradient.p1.x); y0 = _cairo_fixed_to_double (pattern->gradient.p1.y); x1 = _cairo_fixed_to_double (pattern->gradient.p2.x); y1 = _cairo_fixed_to_double (pattern->gradient.p2.y); _cairo_output_stream_printf (document->xml_node_defs, "<linearGradient id=\"linear%d\" " "gradientUnits=\"userSpaceOnUse\" " "x1=\"%f\" y1=\"%f\" x2=\"%f\" y2=\"%f\" ", document->linear_pattern_id, x0, y0, x1, y1); emit_pattern_extend (document->xml_node_defs, &pattern->base.base), p2u = pattern->base.base.matrix; cairo_matrix_invert (&p2u); emit_transform (document->xml_node_defs, "gradientTransform", ">\n", &p2u); emit_pattern_stops (document->xml_node_defs ,&pattern->base, 0.0); _cairo_output_stream_printf (document->xml_node_defs, "</linearGradient>\n"); _cairo_output_stream_printf (style, "%s: url(#linear%d);", is_stroke ? "color" : "fill", document->linear_pattern_id); document->linear_pattern_id++;}static voidemit_radial_pattern (cairo_svg_surface_t *surface, cairo_radial_pattern_t *pattern, cairo_output_stream_t *style, cairo_bool_t is_stroke){ cairo_svg_document_t *document = surface->document; cairo_matrix_t p2u; double x0, y0, x1, y1, r0, r1; double fx, fy; x0 = _cairo_fixed_to_double (pattern->gradient.inner.x); y0 = _cairo_fixed_to_double (pattern->gradient.inner.y); r0 = _cairo_fixed_to_double (pattern->gradient.inner.radius); x1 = _cairo_fixed_to_double (pattern->gradient.outer.x); y1 = _cairo_fixed_to_double (pattern->gradient.outer.y); r1 = _cairo_fixed_to_double (pattern->gradient.outer.radius); /* SVG doesn't have a start radius, so computing now SVG focal coordinates * and emulating start radius by translating color stops. * FIXME: We also need to emulate cairo behaviour inside start circle when * extend != CAIRO_EXTEND_NONE. * FIXME: Handle radius1 <= radius0 */ fx = (r1 * x0 - r0 * x1) / (r1 - r0); fy = (r1 * y0 - r0 * y1) / (r1 - r0); _cairo_output_stream_printf (document->xml_node_defs, "<radialGradient id=\"radial%d\" " "gradientUnits=\"userSpaceOnUse\" " "cx=\"%f\" cy=\"%f\" " "fx=\"%f\" fy=\"%f\" r=\"%f\" ", document->radial_pattern_id, x1, y1, fx, fy, r1); emit_pattern_extend (document->xml_node_defs, &pattern->base.base), p2u = pattern->base.base.matrix; cairo_matrix_invert (&p2u); emit_transform (document->xml_node_defs, "gradientTransform", ">\n", &p2u); emit_pattern_stops (document->xml_node_defs, &pattern->base, r0 / r1); _cairo_output_stream_printf (document->xml_node_defs, "</radialGradient>\n"); _cairo_output_stream_printf (style, "%s: url(#radial%d);", is_stroke ? "color" : "fill", document->radial_pattern_id); document->radial_pattern_id++;}static voidemit_pattern (cairo_svg_surface_t *surface, cairo_pattern_t *pattern, cairo_output_stream_t *output, cairo_bool_t is_stroke){ switch (pattern->type) { case CAIRO_PATTERN_TYPE_SOLID: emit_solid_pattern (surface, (cairo_solid_pattern_t *) pattern, output, is_stroke); break; case CAIRO_PATTERN_TYPE_SURFACE: emit_surface_pattern (surface, (cairo_surface_pattern_t *) pattern, output, is_stroke); break; case CAIRO_PATTERN_TYPE_LINEAR: emit_linear_pattern (surface, (cairo_linear_pattern_t *) pattern, output, is_stroke); break; case CAIRO_PATTERN_TYPE_RADIAL: emit_radial_pattern (surface, (cairo_radial_pattern_t *) pattern, output, is_stroke); break; }}static cairo_int_status_t_cairo_svg_surface_fill (void *abstract_surface, cairo_operator_t op, cairo_pattern_t *source, cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, double tolerance, cairo_antialias_t antialias){ cairo_svg_surface_t *surface = abstract_surface; cairo_status_t status; if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) return _analyze_operation (surface, op, source); assert (_operation_supported (surface, op, source)); _cairo_output_stream_printf (surface->xml_node, "<path style=\"stroke: none; " "fill-rule: %s; ", fill_rule == CAIRO_FILL_RULE_EVEN_ODD ? "evenodd" : "nonzero"); emit_operator (surface->xml_node, surface, op); emit_pattern (surface, source, surface->xml_node, FALSE); _cairo_output_stream_printf (surface->xml_node, "\" "); status = emit_path (surface->xml_node, path, NULL); _cairo_output_stream_printf (surface->xml_node, "/>\n"); return status;}static cairo_int_status_t_cairo_svg_surface_get_extents (void *abstract_surface, cairo_rectangle_int16_t *rectangle){ cairo_svg_surface_t *surface = abstract_surface; rectangle->x = 0; rectangle->y = 0; /* XXX: The conversion to integers here is pretty bogus, (not to * mention the aribitray limitation of width to a short(!). We * may need to come up with a better interface for get_size. */ rectangle->width = (int) ceil (surface->width); rectangle->height = (int) ceil (surface->height); return CAIRO_STATUS_SUCCESS;}static cairo_status_temit_paint (cairo_output_stream_t *output, cairo_svg_surface_t *surface, cairo_operator_t op, cairo_pattern_t *source, const char *extra_attributes){ if (source->type == CAIRO_PATTERN_TYPE_SURFACE && source->extend == CAIRO_EXTEND_NONE) return emit_composite_pattern (output, surface, (cairo_surface_pattern_t *) source, invalid_pattern_id, extra_attributes); _cairo_output_stream_printf (output, "<rect x=\"0\" y=\"0\" " "width=\"%f\" height=\"%f\" " "style=\"", surface->width, surface->height); emit_operator (output, surface, op); emit_pattern (surface, source, output, FALSE); _cairo_output_stream_printf (output, " stroke: none;\""); if (extra_attributes) _cairo_output_stream_printf (output, " %s", extra_attributes); _cairo_output_stream_printf (output, "/>\n"); return CAIRO_STATUS_SUCCESS;}static cairo_int_status_t_cairo_svg_surface_paint (void *abstract_surface, cairo_operator_t op, cairo_pattern_t *source){ cairo_svg_surface_t *surface = abstract_surface; if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) return _analyze_operation (surface, op, source); /* XXX: It would be nice to be able to assert this condition * here. But, we actually allow one 'cheat' that is used when * painting the final image-based fallbacks. The final fallbacks * do have alpha which we support by blending with white. This is * possible only because there is nothing between the fallback * images and the paper, nor is anything painted above. */ /* assert (_operation_supported (surface, op, source)); */ /* Emulation of clear and source operators, when no clipping region * is defined. We just delete existing content of surface root node, * and exit early if operator is clear. * XXX: optimization of SOURCE operator doesn't work, since analyze * above always return FALSE. In order to make it work, we need a way * to know if there's an active clipping path. * Optimization of CLEAR works because of a test in paginated surface, * and an optimiszation in meta surface. */ if (surface->clip_level == 0 && (op == CAIRO_OPERATOR_CLEAR || op == CAIRO_OPERATOR_SOURCE)) { _cairo_output_stream_destroy (surface->xml_node);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -