1 /* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
2 /* cairo - a vector graphics library with display and print output
4 * Copyright © 2009 Chris Wilson
6 * This library is free software; you can redistribute it and/or
7 * modify it either under the terms of the GNU Lesser General Public
8 * License version 2.1 as published by the Free Software Foundation
9 * (the "LGPL") or, at your option, under the terms of the Mozilla
10 * Public License Version 1.1 (the "MPL"). If you do not alter this
11 * notice, a recipient may use your version of this file under either
12 * the MPL or the LGPL.
14 * You should have received a copy of the LGPL along with this library
15 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
17 * You should have received a copy of the MPL along with this library
18 * in the file COPYING-MPL-1.1
20 * The contents of this file are subject to the Mozilla Public License
21 * Version 1.1 (the "License"); you may not use this file except in
22 * compliance with the License. You may obtain a copy of the License at
23 * http://www.mozilla.org/MPL/
25 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
26 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
27 * the specific language governing rights and limitations.
29 * The Original Code is the cairo graphics library.
31 * The Initial Developer of the Original Code is Chris Wilson.
34 * Chris Wilson <chris@chris-wilson.co.uk>
37 /* This surface is intended to produce a verbose, hierarchical, DAG XML file
38 * representing a single surface. It is intended to be used by debuggers,
39 * such as cairo-sphinx, or by application test-suites that what a log of
45 #include "cairo-xml.h"
47 #include "cairo-clip-private.h"
48 #include "cairo-device-private.h"
49 #include "cairo-default-context-private.h"
50 #include "cairo-image-surface-private.h"
51 #include "cairo-error-private.h"
52 #include "cairo-output-stream-private.h"
53 #include "cairo-recording-surface-inline.h"
55 #define static cairo_warn static
57 typedef struct _cairo_xml_surface cairo_xml_surface_t;
59 typedef struct _cairo_xml {
62 cairo_output_stream_t *stream;
66 struct _cairo_xml_surface {
72 slim_hidden_proto (cairo_xml_for_recording_surface);
74 static const cairo_surface_backend_t _cairo_xml_surface_backend;
77 _operator_to_string (cairo_operator_t op)
79 static const char *names[] = {
80 "CLEAR", /* CAIRO_OPERATOR_CLEAR */
82 "SOURCE", /* CAIRO_OPERATOR_SOURCE */
83 "OVER", /* CAIRO_OPERATOR_OVER */
84 "IN", /* CAIRO_OPERATOR_IN */
85 "OUT", /* CAIRO_OPERATOR_OUT */
86 "ATOP", /* CAIRO_OPERATOR_ATOP */
88 "DEST", /* CAIRO_OPERATOR_DEST */
89 "DEST_OVER", /* CAIRO_OPERATOR_DEST_OVER */
90 "DEST_IN", /* CAIRO_OPERATOR_DEST_IN */
91 "DEST_OUT", /* CAIRO_OPERATOR_DEST_OUT */
92 "DEST_ATOP", /* CAIRO_OPERATOR_DEST_ATOP */
94 "XOR", /* CAIRO_OPERATOR_XOR */
95 "ADD", /* CAIRO_OPERATOR_ADD */
96 "SATURATE", /* CAIRO_OPERATOR_SATURATE */
98 "MULTIPLY", /* CAIRO_OPERATOR_MULTIPLY */
99 "SCREEN", /* CAIRO_OPERATOR_SCREEN */
100 "OVERLAY", /* CAIRO_OPERATOR_OVERLAY */
101 "DARKEN", /* CAIRO_OPERATOR_DARKEN */
102 "LIGHTEN", /* CAIRO_OPERATOR_LIGHTEN */
103 "DODGE", /* CAIRO_OPERATOR_COLOR_DODGE */
104 "BURN", /* CAIRO_OPERATOR_COLOR_BURN */
105 "HARD_LIGHT", /* CAIRO_OPERATOR_HARD_LIGHT */
106 "SOFT_LIGHT", /* CAIRO_OPERATOR_SOFT_LIGHT */
107 "DIFFERENCE", /* CAIRO_OPERATOR_DIFFERENCE */
108 "EXCLUSION", /* CAIRO_OPERATOR_EXCLUSION */
109 "HSL_HUE", /* CAIRO_OPERATOR_HSL_HUE */
110 "HSL_SATURATION", /* CAIRO_OPERATOR_HSL_SATURATION */
111 "HSL_COLOR", /* CAIRO_OPERATOR_HSL_COLOR */
112 "HSL_LUMINOSITY" /* CAIRO_OPERATOR_HSL_LUMINOSITY */
114 assert (op < ARRAY_LENGTH (names));
119 _extend_to_string (cairo_extend_t extend)
121 static const char *names[] = {
122 "EXTEND_NONE", /* CAIRO_EXTEND_NONE */
123 "EXTEND_REPEAT", /* CAIRO_EXTEND_REPEAT */
124 "EXTEND_REFLECT", /* CAIRO_EXTEND_REFLECT */
125 "EXTEND_PAD" /* CAIRO_EXTEND_PAD */
127 assert (extend < ARRAY_LENGTH (names));
128 return names[extend];
132 _filter_to_string (cairo_filter_t filter)
134 static const char *names[] = {
135 "FILTER_FAST", /* CAIRO_FILTER_FAST */
136 "FILTER_GOOD", /* CAIRO_FILTER_GOOD */
137 "FILTER_BEST", /* CAIRO_FILTER_BEST */
138 "FILTER_NEAREST", /* CAIRO_FILTER_NEAREST */
139 "FILTER_BILINEAR", /* CAIRO_FILTER_BILINEAR */
140 "FILTER_GAUSSIAN", /* CAIRO_FILTER_GAUSSIAN */
142 assert (filter < ARRAY_LENGTH (names));
143 return names[filter];
147 _fill_rule_to_string (cairo_fill_rule_t rule)
149 static const char *names[] = {
150 "WINDING", /* CAIRO_FILL_RULE_WINDING */
151 "EVEN_ODD" /* CAIRO_FILL_RILE_EVEN_ODD */
153 assert (rule < ARRAY_LENGTH (names));
158 _antialias_to_string (cairo_antialias_t antialias)
160 static const char *names[] = {
161 "DEFAULT", /* CAIRO_ANTIALIAS_DEFAULT */
162 "NONE", /* CAIRO_ANTIALIAS_NONE */
163 "GRAY", /* CAIRO_ANTIALIAS_GRAY */
164 "SUBPIXEL", /* CAIRO_ANTIALIAS_SUBPIXEL */
165 "FAST", /* CAIRO_ANTIALIAS_FAST */
166 "GOOD", /* CAIRO_ANTIALIAS_GOOD */
167 "BEST", /* CAIRO_ANTIALIAS_BEST */
169 assert (antialias < ARRAY_LENGTH (names));
170 return names[antialias];
174 _line_cap_to_string (cairo_line_cap_t line_cap)
176 static const char *names[] = {
177 "LINE_CAP_BUTT", /* CAIRO_LINE_CAP_BUTT */
178 "LINE_CAP_ROUND", /* CAIRO_LINE_CAP_ROUND */
179 "LINE_CAP_SQUARE" /* CAIRO_LINE_CAP_SQUARE */
181 assert (line_cap < ARRAY_LENGTH (names));
182 return names[line_cap];
186 _line_join_to_string (cairo_line_join_t line_join)
188 static const char *names[] = {
189 "LINE_JOIN_MITER", /* CAIRO_LINE_JOIN_MITER */
190 "LINE_JOIN_ROUND", /* CAIRO_LINE_JOIN_ROUND */
191 "LINE_JOIN_BEVEL", /* CAIRO_LINE_JOIN_BEVEL */
193 assert (line_join < ARRAY_LENGTH (names));
194 return names[line_join];
198 _content_to_string (cairo_content_t content)
201 case CAIRO_CONTENT_ALPHA: return "ALPHA";
202 case CAIRO_CONTENT_COLOR: return "COLOR";
204 case CAIRO_CONTENT_COLOR_ALPHA: return "COLOR_ALPHA";
209 _format_to_string (cairo_format_t format)
212 case CAIRO_FORMAT_ARGB32: return "ARGB32";
213 case CAIRO_FORMAT_RGB30: return "RGB30";
214 case CAIRO_FORMAT_RGB24: return "RGB24";
215 case CAIRO_FORMAT_RGB16_565: return "RGB16_565";
216 case CAIRO_FORMAT_A8: return "A8";
217 case CAIRO_FORMAT_A1: return "A1";
218 case CAIRO_FORMAT_INVALID: return "INVALID";
224 static cairo_status_t
225 _device_flush (void *abstract_device)
227 cairo_xml_t *xml = abstract_device;
228 cairo_status_t status;
230 status = _cairo_output_stream_flush (xml->stream);
236 _device_destroy (void *abstract_device)
238 cairo_xml_t *xml = abstract_device;
239 cairo_status_t status;
241 status = _cairo_output_stream_destroy (xml->stream);
246 static const cairo_device_backend_t _cairo_xml_device_backend = {
247 CAIRO_DEVICE_TYPE_XML,
249 NULL, NULL, /* lock, unlock */
256 static cairo_device_t *
257 _cairo_xml_create_internal (cairo_output_stream_t *stream)
261 xml = malloc (sizeof (cairo_xml_t));
262 if (unlikely (xml == NULL))
263 return _cairo_device_create_in_error (CAIRO_STATUS_NO_MEMORY);
265 memset (xml, 0, sizeof (cairo_xml_t));
267 _cairo_device_init (&xml->base, &_cairo_xml_device_backend);
270 xml->stream = stream;
276 _cairo_xml_indent (cairo_xml_t *xml, int indent)
278 xml->indent += indent;
279 assert (xml->indent >= 0);
282 static void CAIRO_PRINTF_FORMAT (2, 3)
283 _cairo_xml_printf (cairo_xml_t *xml, const char *fmt, ...)
289 len = MIN (xml->indent, ARRAY_LENGTH (indent));
290 memset (indent, ' ', len);
291 _cairo_output_stream_write (xml->stream, indent, len);
294 _cairo_output_stream_vprintf (xml->stream, fmt, ap);
297 _cairo_output_stream_write (xml->stream, "\n", 1);
300 static void CAIRO_PRINTF_FORMAT (2, 3)
301 _cairo_xml_printf_start (cairo_xml_t *xml, const char *fmt, ...)
306 len = MIN (xml->indent, ARRAY_LENGTH (indent));
307 memset (indent, ' ', len);
308 _cairo_output_stream_write (xml->stream, indent, len);
314 _cairo_output_stream_vprintf (xml->stream, fmt, ap);
319 static void CAIRO_PRINTF_FORMAT (2, 3)
320 _cairo_xml_printf_continue (cairo_xml_t *xml, const char *fmt, ...)
325 _cairo_output_stream_vprintf (xml->stream, fmt, ap);
329 static void CAIRO_PRINTF_FORMAT (2, 3)
330 _cairo_xml_printf_end (cairo_xml_t *xml, const char *fmt, ...)
336 _cairo_output_stream_vprintf (xml->stream, fmt, ap);
340 _cairo_output_stream_write (xml->stream, "\n", 1);
343 static cairo_surface_t *
344 _cairo_xml_surface_create_similar (void *abstract_surface,
345 cairo_content_t content,
349 cairo_rectangle_t extents;
351 extents.x = extents.y = 0;
352 extents.width = width;
353 extents.height = height;
355 return cairo_recording_surface_create (content, &extents);
359 _cairo_xml_surface_get_extents (void *abstract_surface,
360 cairo_rectangle_int_t *rectangle)
362 cairo_xml_surface_t *surface = abstract_surface;
364 if (surface->width < 0 || surface->height < 0)
369 rectangle->width = surface->width;
370 rectangle->height = surface->height;
375 static cairo_status_t
376 _cairo_xml_move_to (void *closure,
377 const cairo_point_t *p1)
379 _cairo_xml_printf_continue (closure, " %f %f m",
380 _cairo_fixed_to_double (p1->x),
381 _cairo_fixed_to_double (p1->y));
383 return CAIRO_STATUS_SUCCESS;
386 static cairo_status_t
387 _cairo_xml_line_to (void *closure,
388 const cairo_point_t *p1)
390 _cairo_xml_printf_continue (closure, " %f %f l",
391 _cairo_fixed_to_double (p1->x),
392 _cairo_fixed_to_double (p1->y));
394 return CAIRO_STATUS_SUCCESS;
397 static cairo_status_t
398 _cairo_xml_curve_to (void *closure,
399 const cairo_point_t *p1,
400 const cairo_point_t *p2,
401 const cairo_point_t *p3)
403 _cairo_xml_printf_continue (closure, " %f %f %f %f %f %f c",
404 _cairo_fixed_to_double (p1->x),
405 _cairo_fixed_to_double (p1->y),
406 _cairo_fixed_to_double (p2->x),
407 _cairo_fixed_to_double (p2->y),
408 _cairo_fixed_to_double (p3->x),
409 _cairo_fixed_to_double (p3->y));
411 return CAIRO_STATUS_SUCCESS;
414 static cairo_status_t
415 _cairo_xml_close_path (void *closure)
417 _cairo_xml_printf_continue (closure, " h");
419 return CAIRO_STATUS_SUCCESS;
423 _cairo_xml_emit_path (cairo_xml_t *xml,
424 const cairo_path_fixed_t *path)
426 cairo_status_t status;
428 _cairo_xml_printf_start (xml, "<path>");
429 status = _cairo_path_fixed_interpret (path,
433 _cairo_xml_close_path,
435 assert (status == CAIRO_STATUS_SUCCESS);
436 _cairo_xml_printf_end (xml, "</path>");
440 _cairo_xml_emit_string (cairo_xml_t *xml,
444 _cairo_xml_printf (xml, "<%s>%s</%s>", node, data, node);
448 _cairo_xml_emit_double (cairo_xml_t *xml,
452 _cairo_xml_printf (xml, "<%s>%f</%s>", node, data, node);
456 to_xml (cairo_xml_surface_t *surface)
458 return (cairo_xml_t *) surface->base.device;
461 static cairo_status_t
462 _cairo_xml_surface_emit_clip_path (cairo_xml_surface_t *surface,
463 cairo_clip_path_t *clip_path)
466 cairo_status_t status;
469 if (clip_path->prev != NULL) {
470 status = _cairo_xml_surface_emit_clip_path (surface, clip_path->prev);
471 if (unlikely (status))
476 /* skip the trivial clip covering the surface extents */
477 if (surface->width >= 0 && surface->height >= 0 &&
478 _cairo_path_fixed_is_box (&clip_path->path, &box))
480 if (box.p1.x <= 0 && box.p1.y <= 0 &&
481 box.p2.x - box.p1.x >= _cairo_fixed_from_double (surface->width) &&
482 box.p2.y - box.p1.y >= _cairo_fixed_from_double (surface->height))
484 return CAIRO_STATUS_SUCCESS;
488 xml = to_xml (surface);
490 _cairo_xml_printf_start (xml, "<clip>");
491 _cairo_xml_indent (xml, 2);
493 _cairo_xml_emit_path (xml, &clip_path->path);
494 _cairo_xml_emit_double (xml, "tolerance", clip_path->tolerance);
495 _cairo_xml_emit_string (xml, "antialias",
496 _antialias_to_string (clip_path->antialias));
497 _cairo_xml_emit_string (xml, "fill-rule",
498 _fill_rule_to_string (clip_path->fill_rule));
500 _cairo_xml_indent (xml, -2);
501 _cairo_xml_printf_end (xml, "</clip>");
503 return CAIRO_STATUS_SUCCESS;
506 static cairo_status_t
507 _cairo_xml_surface_emit_clip (cairo_xml_surface_t *surface,
508 const cairo_clip_t *clip)
511 return CAIRO_STATUS_SUCCESS;
513 return _cairo_xml_surface_emit_clip_path (surface, clip->path);
516 static cairo_status_t
517 _cairo_xml_emit_solid (cairo_xml_t *xml,
518 const cairo_solid_pattern_t *solid)
520 _cairo_xml_printf (xml, "<solid>%f %f %f %f</solid>",
525 return CAIRO_STATUS_SUCCESS;
529 _cairo_xml_emit_matrix (cairo_xml_t *xml,
530 const cairo_matrix_t *matrix)
532 if (! _cairo_matrix_is_identity (matrix)) {
533 _cairo_xml_printf (xml, "<matrix>%f %f %f %f %f %f</matrix>",
534 matrix->xx, matrix->yx,
535 matrix->xy, matrix->yy,
536 matrix->x0, matrix->y0);
541 _cairo_xml_emit_gradient (cairo_xml_t *xml,
542 const cairo_gradient_pattern_t *gradient)
546 for (i = 0; i < gradient->n_stops; i++) {
547 _cairo_xml_printf (xml,
548 "<color-stop>%f %f %f %f %f</color-stop>",
549 gradient->stops[i].offset,
550 gradient->stops[i].color.red,
551 gradient->stops[i].color.green,
552 gradient->stops[i].color.blue,
553 gradient->stops[i].color.alpha);
557 static cairo_status_t
558 _cairo_xml_emit_linear (cairo_xml_t *xml,
559 const cairo_linear_pattern_t *linear)
561 _cairo_xml_printf (xml,
562 "<linear x1='%f' y1='%f' x2='%f' y2='%f'>",
563 linear->pd1.x, linear->pd1.y,
564 linear->pd2.x, linear->pd2.y);
565 _cairo_xml_indent (xml, 2);
566 _cairo_xml_emit_gradient (xml, &linear->base);
567 _cairo_xml_indent (xml, -2);
568 _cairo_xml_printf (xml, "</linear>");
569 return CAIRO_STATUS_SUCCESS;
572 static cairo_status_t
573 _cairo_xml_emit_radial (cairo_xml_t *xml,
574 const cairo_radial_pattern_t *radial)
576 _cairo_xml_printf (xml,
577 "<radial x1='%f' y1='%f' r1='%f' x2='%f' y2='%f' r2='%f'>",
578 radial->cd1.center.x, radial->cd1.center.y, radial->cd1.radius,
579 radial->cd2.center.x, radial->cd2.center.y, radial->cd2.radius);
580 _cairo_xml_indent (xml, 2);
581 _cairo_xml_emit_gradient (xml, &radial->base);
582 _cairo_xml_indent (xml, -2);
583 _cairo_xml_printf (xml, "</radial>");
584 return CAIRO_STATUS_SUCCESS;
587 static cairo_status_t
588 _write_func (void *closure, const unsigned char *data, unsigned len)
590 _cairo_output_stream_write (closure, data, len);
591 return CAIRO_STATUS_SUCCESS;
594 static cairo_status_t
595 _cairo_xml_emit_image (cairo_xml_t *xml,
596 cairo_image_surface_t *image)
598 cairo_output_stream_t *stream;
599 cairo_status_t status;
601 _cairo_xml_printf_start (xml,
602 "<image width='%d' height='%d' format='%s'>",
603 image->width, image->height,
604 _format_to_string (image->format));
606 stream = _cairo_base64_stream_create (xml->stream);
607 status = cairo_surface_write_to_png_stream (&image->base,
608 _write_func, stream);
609 assert (status == CAIRO_STATUS_SUCCESS);
610 status = _cairo_output_stream_destroy (stream);
611 if (unlikely (status))
614 _cairo_xml_printf_end (xml, "</image>");
616 return CAIRO_STATUS_SUCCESS;
619 static cairo_status_t
620 _cairo_xml_emit_surface (cairo_xml_t *xml,
621 const cairo_surface_pattern_t *pattern)
623 cairo_surface_t *source = pattern->surface;
624 cairo_status_t status;
626 if (_cairo_surface_is_recording (source)) {
627 status = cairo_xml_for_recording_surface (&xml->base, source);
629 cairo_image_surface_t *image;
632 status = _cairo_surface_acquire_source_image (source,
633 &image, &image_extra);
634 if (unlikely (status))
637 status = _cairo_xml_emit_image (xml, image);
639 _cairo_surface_release_source_image (source, image, image_extra);
645 static cairo_status_t
646 _cairo_xml_emit_pattern (cairo_xml_t *xml,
647 const char *source_or_mask,
648 const cairo_pattern_t *pattern)
650 cairo_status_t status;
652 _cairo_xml_printf (xml, "<%s-pattern>", source_or_mask);
653 _cairo_xml_indent (xml, 2);
655 switch (pattern->type) {
656 case CAIRO_PATTERN_TYPE_SOLID:
657 status = _cairo_xml_emit_solid (xml, (cairo_solid_pattern_t *) pattern);
659 case CAIRO_PATTERN_TYPE_LINEAR:
660 status = _cairo_xml_emit_linear (xml, (cairo_linear_pattern_t *) pattern);
662 case CAIRO_PATTERN_TYPE_RADIAL:
663 status = _cairo_xml_emit_radial (xml, (cairo_radial_pattern_t *) pattern);
665 case CAIRO_PATTERN_TYPE_SURFACE:
666 status = _cairo_xml_emit_surface (xml, (cairo_surface_pattern_t *) pattern);
670 status = CAIRO_INT_STATUS_UNSUPPORTED;
674 if (pattern->type != CAIRO_PATTERN_TYPE_SOLID) {
675 _cairo_xml_emit_matrix (xml, &pattern->matrix);
676 _cairo_xml_printf (xml,
677 "<extend>%s</extend>",
678 _extend_to_string (pattern->extend));
679 _cairo_xml_printf (xml,
680 "<filter>%s</filter>",
681 _filter_to_string (pattern->filter));
684 _cairo_xml_indent (xml, -2);
685 _cairo_xml_printf (xml, "</%s-pattern>", source_or_mask);
690 static cairo_int_status_t
691 _cairo_xml_surface_paint (void *abstract_surface,
693 const cairo_pattern_t *source,
694 const cairo_clip_t *clip)
696 cairo_xml_surface_t *surface = abstract_surface;
697 cairo_xml_t *xml = to_xml (surface);
698 cairo_status_t status;
700 _cairo_xml_printf (xml, "<paint>");
701 _cairo_xml_indent (xml, 2);
703 _cairo_xml_emit_string (xml, "operator", _operator_to_string (op));
705 status = _cairo_xml_surface_emit_clip (surface, clip);
706 if (unlikely (status))
709 status = _cairo_xml_emit_pattern (xml, "source", source);
710 if (unlikely (status))
713 _cairo_xml_indent (xml, -2);
714 _cairo_xml_printf (xml, "</paint>");
716 return CAIRO_STATUS_SUCCESS;
719 static cairo_int_status_t
720 _cairo_xml_surface_mask (void *abstract_surface,
722 const cairo_pattern_t *source,
723 const cairo_pattern_t *mask,
724 const cairo_clip_t *clip)
726 cairo_xml_surface_t *surface = abstract_surface;
727 cairo_xml_t *xml = to_xml (surface);
728 cairo_status_t status;
730 _cairo_xml_printf (xml, "<mask>");
731 _cairo_xml_indent (xml, 2);
733 _cairo_xml_emit_string (xml, "operator", _operator_to_string (op));
735 status = _cairo_xml_surface_emit_clip (surface, clip);
736 if (unlikely (status))
739 status = _cairo_xml_emit_pattern (xml, "source", source);
740 if (unlikely (status))
743 status = _cairo_xml_emit_pattern (xml, "mask", mask);
744 if (unlikely (status))
747 _cairo_xml_indent (xml, -2);
748 _cairo_xml_printf (xml, "</mask>");
750 return CAIRO_STATUS_SUCCESS;
753 static cairo_int_status_t
754 _cairo_xml_surface_stroke (void *abstract_surface,
756 const cairo_pattern_t *source,
757 const cairo_path_fixed_t *path,
758 const cairo_stroke_style_t *style,
759 const cairo_matrix_t *ctm,
760 const cairo_matrix_t *ctm_inverse,
762 cairo_antialias_t antialias,
763 const cairo_clip_t *clip)
765 cairo_xml_surface_t *surface = abstract_surface;
766 cairo_xml_t *xml = to_xml (surface);
767 cairo_status_t status;
769 _cairo_xml_printf (xml, "<stroke>");
770 _cairo_xml_indent (xml, 2);
772 _cairo_xml_emit_string (xml, "operator", _operator_to_string (op));
773 _cairo_xml_emit_double (xml, "line-width", style->line_width);
774 _cairo_xml_emit_double (xml, "miter-limit", style->miter_limit);
775 _cairo_xml_emit_string (xml, "line-cap", _line_cap_to_string (style->line_cap));
776 _cairo_xml_emit_string (xml, "line-join", _line_join_to_string (style->line_join));
778 status = _cairo_xml_surface_emit_clip (surface, clip);
779 if (unlikely (status))
782 status = _cairo_xml_emit_pattern (xml, "source", source);
783 if (unlikely (status))
786 if (style->num_dashes) {
789 _cairo_xml_printf_start (xml, "<dash offset='%f'>",
791 for (i = 0; i < style->num_dashes; i++)
792 _cairo_xml_printf_continue (xml, "%f ", style->dash[i]);
794 _cairo_xml_printf_end (xml, "</dash>");
797 _cairo_xml_emit_path (xml, path);
798 _cairo_xml_emit_double (xml, "tolerance", tolerance);
799 _cairo_xml_emit_string (xml, "antialias", _antialias_to_string (antialias));
801 _cairo_xml_emit_matrix (xml, ctm);
803 _cairo_xml_indent (xml, -2);
804 _cairo_xml_printf (xml, "</stroke>");
806 return CAIRO_STATUS_SUCCESS;
809 static cairo_int_status_t
810 _cairo_xml_surface_fill (void *abstract_surface,
812 const cairo_pattern_t *source,
813 const cairo_path_fixed_t*path,
814 cairo_fill_rule_t fill_rule,
816 cairo_antialias_t antialias,
817 const cairo_clip_t *clip)
819 cairo_xml_surface_t *surface = abstract_surface;
820 cairo_xml_t *xml = to_xml (surface);
821 cairo_status_t status;
823 _cairo_xml_printf (xml, "<fill>");
824 _cairo_xml_indent (xml, 2);
826 _cairo_xml_emit_string (xml, "operator", _operator_to_string (op));
828 status = _cairo_xml_surface_emit_clip (surface, clip);
829 if (unlikely (status))
832 status = _cairo_xml_emit_pattern (xml, "source", source);
833 if (unlikely (status))
836 _cairo_xml_emit_path (xml, path);
837 _cairo_xml_emit_double (xml, "tolerance", tolerance);
838 _cairo_xml_emit_string (xml, "antialias", _antialias_to_string (antialias));
839 _cairo_xml_emit_string (xml, "fill-rule", _fill_rule_to_string (fill_rule));
841 _cairo_xml_indent (xml, -2);
842 _cairo_xml_printf (xml, "</fill>");
844 return CAIRO_STATUS_SUCCESS;
847 #if CAIRO_HAS_FT_FONT
848 #include "cairo-ft-private.h"
849 static cairo_status_t
850 _cairo_xml_emit_type42_font (cairo_xml_t *xml,
851 cairo_scaled_font_t *scaled_font)
853 const cairo_scaled_font_backend_t *backend;
854 cairo_output_stream_t *base64_stream;
855 cairo_output_stream_t *zlib_stream;
856 cairo_status_t status, status2;
861 backend = scaled_font->backend;
862 if (backend->load_truetype_table == NULL)
863 return CAIRO_INT_STATUS_UNSUPPORTED;
866 status = backend->load_truetype_table (scaled_font, 0, 0, NULL, &size);
867 if (unlikely (status))
871 if (unlikely (buf == NULL))
872 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
874 status = backend->load_truetype_table (scaled_font, 0, 0, buf, &size);
875 if (unlikely (status)) {
880 _cairo_xml_printf_start (xml, "<font type='42' flags='%d' index='0'>",
881 _cairo_ft_scaled_font_get_load_flags (scaled_font));
884 base64_stream = _cairo_base64_stream_create (xml->stream);
886 _cairo_output_stream_write (base64_stream, &len, sizeof (len));
888 zlib_stream = _cairo_deflate_stream_create (base64_stream);
890 _cairo_output_stream_write (zlib_stream, buf, size);
893 status2 = _cairo_output_stream_destroy (zlib_stream);
894 if (status == CAIRO_STATUS_SUCCESS)
897 status2 = _cairo_output_stream_destroy (base64_stream);
898 if (status == CAIRO_STATUS_SUCCESS)
901 _cairo_xml_printf_end (xml, "</font>");
906 static cairo_status_t
907 _cairo_xml_emit_type42_font (cairo_xml_t *xml,
908 cairo_scaled_font_t *scaled_font)
910 return CAIRO_INT_STATUS_UNSUPPORTED;
914 static cairo_status_t
915 _cairo_xml_emit_type3_font (cairo_xml_t *xml,
916 cairo_scaled_font_t *scaled_font,
917 cairo_glyph_t *glyphs,
920 _cairo_xml_printf_start (xml, "<font type='3'>");
921 _cairo_xml_printf_end (xml, "</font>");
923 return CAIRO_STATUS_SUCCESS;
926 static cairo_status_t
927 _cairo_xml_emit_scaled_font (cairo_xml_t *xml,
928 cairo_scaled_font_t *scaled_font,
929 cairo_glyph_t *glyphs,
932 cairo_int_status_t status;
934 _cairo_xml_printf (xml, "<scaled-font>");
935 _cairo_xml_indent (xml, 2);
937 status = _cairo_xml_emit_type42_font (xml, scaled_font);
938 if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
939 status = _cairo_xml_emit_type3_font (xml, scaled_font,
943 _cairo_xml_indent (xml, -2);
944 _cairo_xml_printf (xml, "<scaled-font>");
949 static cairo_int_status_t
950 _cairo_xml_surface_glyphs (void *abstract_surface,
952 const cairo_pattern_t *source,
953 cairo_glyph_t *glyphs,
955 cairo_scaled_font_t *scaled_font,
956 const cairo_clip_t *clip)
958 cairo_xml_surface_t *surface = abstract_surface;
959 cairo_xml_t *xml = to_xml (surface);
960 cairo_status_t status;
963 _cairo_xml_printf (xml, "<glyphs>");
964 _cairo_xml_indent (xml, 2);
966 _cairo_xml_emit_string (xml, "operator", _operator_to_string (op));
968 status = _cairo_xml_surface_emit_clip (surface, clip);
969 if (unlikely (status))
972 status = _cairo_xml_emit_pattern (xml, "source", source);
973 if (unlikely (status))
976 status = _cairo_xml_emit_scaled_font (xml, scaled_font, glyphs, num_glyphs);
977 if (unlikely (status))
980 for (i = 0; i < num_glyphs; i++) {
981 _cairo_xml_printf (xml, "<glyph index='%lu'>%f %f</glyph>",
987 _cairo_xml_indent (xml, -2);
988 _cairo_xml_printf (xml, "</glyphs>");
990 return CAIRO_STATUS_SUCCESS;
993 static const cairo_surface_backend_t
994 _cairo_xml_surface_backend = {
995 CAIRO_SURFACE_TYPE_XML,
998 _cairo_default_context_create,
1000 _cairo_xml_surface_create_similar,
1001 NULL, /* create_similar_image */
1002 NULL, /* map_to_image */
1003 NULL, /* unmap_image */
1005 _cairo_surface_default_source,
1006 NULL, /* acquire source image */
1007 NULL, /* release source image */
1008 NULL, /* snapshot */
1010 NULL, /* copy page */
1011 NULL, /* show page */
1013 _cairo_xml_surface_get_extents,
1014 NULL, /* get_font_options */
1017 NULL, /* mark_dirty_rectangle */
1019 _cairo_xml_surface_paint,
1020 _cairo_xml_surface_mask,
1021 _cairo_xml_surface_stroke,
1022 _cairo_xml_surface_fill,
1023 NULL, /* fill_stroke */
1024 _cairo_xml_surface_glyphs,
1027 static cairo_surface_t *
1028 _cairo_xml_surface_create_internal (cairo_device_t *device,
1029 cairo_content_t content,
1033 cairo_xml_surface_t *surface;
1035 surface = malloc (sizeof (cairo_xml_surface_t));
1036 if (unlikely (surface == NULL))
1037 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
1039 _cairo_surface_init (&surface->base,
1040 &_cairo_xml_surface_backend,
1044 surface->width = width;
1045 surface->height = height;
1047 return &surface->base;
1051 cairo_xml_create (const char *filename)
1053 cairo_output_stream_t *stream;
1054 cairo_status_t status;
1056 stream = _cairo_output_stream_create_for_filename (filename);
1057 if ((status = _cairo_output_stream_get_status (stream)))
1058 return _cairo_device_create_in_error (status);
1060 return _cairo_xml_create_internal (stream);
1064 cairo_xml_create_for_stream (cairo_write_func_t write_func,
1067 cairo_output_stream_t *stream;
1068 cairo_status_t status;
1070 stream = _cairo_output_stream_create (write_func, NULL, closure);
1071 if ((status = _cairo_output_stream_get_status (stream)))
1072 return _cairo_device_create_in_error (status);
1074 return _cairo_xml_create_internal (stream);
1078 cairo_xml_surface_create (cairo_device_t *device,
1079 cairo_content_t content,
1080 double width, double height)
1082 if (unlikely (device->backend->type != CAIRO_DEVICE_TYPE_XML))
1083 return _cairo_surface_create_in_error (CAIRO_STATUS_DEVICE_TYPE_MISMATCH);
1085 if (unlikely (device->status))
1086 return _cairo_surface_create_in_error (device->status);
1088 return _cairo_xml_surface_create_internal (device, content, width, height);
1092 cairo_xml_for_recording_surface (cairo_device_t *device,
1093 cairo_surface_t *recording_surface)
1096 cairo_rectangle_int_t extents;
1097 cairo_surface_t *surface;
1099 cairo_status_t status;
1101 if (unlikely (device->status))
1102 return device->status;
1104 if (unlikely (recording_surface->status))
1105 return recording_surface->status;
1107 if (unlikely (device->backend->type != CAIRO_DEVICE_TYPE_XML))
1108 return _cairo_error (CAIRO_STATUS_DEVICE_TYPE_MISMATCH);
1110 if (unlikely (! _cairo_surface_is_recording (recording_surface)))
1111 return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
1113 status = _cairo_recording_surface_get_bbox ((cairo_recording_surface_t *) recording_surface,
1115 if (unlikely (status))
1118 _cairo_box_round_to_rectangle (&bbox, &extents);
1119 surface = _cairo_xml_surface_create_internal (device,
1120 recording_surface->content,
1123 if (unlikely (surface->status))
1124 return surface->status;
1126 xml = (cairo_xml_t *) device;
1128 _cairo_xml_printf (xml,
1129 "<surface content='%s' width='%d' height='%d'>",
1130 _content_to_string (recording_surface->content),
1131 extents.width, extents.height);
1132 _cairo_xml_indent (xml, 2);
1134 cairo_surface_set_device_offset (surface, -extents.x, -extents.y);
1135 status = _cairo_recording_surface_replay (recording_surface, surface);
1136 cairo_surface_destroy (surface);
1138 _cairo_xml_indent (xml, -2);
1139 _cairo_xml_printf (xml, "</surface>");
1143 slim_hidden_def (cairo_xml_for_recording_surface);