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_boxes (cairo_xml_surface_t
*surface
,
463 const cairo_clip_t
*clip
)
469 if (clip
->num_boxes
== 0)
470 return CAIRO_STATUS_SUCCESS
;
472 /* skip the trivial clip covering the surface extents */
473 if (surface
->width
>= 0 && surface
->height
>= 0 && clip
->num_boxes
== 1) {
474 box
= &clip
->boxes
[0];
475 if (box
->p1
.x
<= 0 && box
->p1
.y
<= 0 &&
476 box
->p2
.x
- box
->p1
.x
>= _cairo_fixed_from_double (surface
->width
) &&
477 box
->p2
.y
- box
->p1
.y
>= _cairo_fixed_from_double (surface
->height
))
479 return CAIRO_STATUS_SUCCESS
;
483 xml
= to_xml (surface
);
485 _cairo_xml_printf (xml
, "<clip>");
486 _cairo_xml_indent (xml
, 2);
488 _cairo_xml_printf (xml
, "<path>");
489 _cairo_xml_indent (xml
, 2);
490 for (n
= 0; n
< clip
->num_boxes
; n
++) {
491 box
= &clip
->boxes
[n
];
493 _cairo_xml_printf_start (xml
, "%f %f m",
494 _cairo_fixed_to_double (box
->p1
.x
),
495 _cairo_fixed_to_double (box
->p1
.y
));
496 _cairo_xml_printf_continue (xml
, " %f %f l",
497 _cairo_fixed_to_double (box
->p2
.x
),
498 _cairo_fixed_to_double (box
->p1
.y
));
499 _cairo_xml_printf_continue (xml
, " %f %f l",
500 _cairo_fixed_to_double (box
->p2
.x
),
501 _cairo_fixed_to_double (box
->p2
.y
));
502 _cairo_xml_printf_continue (xml
, " %f %f l",
503 _cairo_fixed_to_double (box
->p1
.x
),
504 _cairo_fixed_to_double (box
->p2
.y
));
505 _cairo_xml_printf_end (xml
, " h");
507 _cairo_xml_indent (xml
, -2);
508 _cairo_xml_printf (xml
, "</path>");
509 _cairo_xml_emit_double (xml
, "tolerance", 1.0);
510 _cairo_xml_emit_string (xml
, "antialias",
511 _antialias_to_string (CAIRO_ANTIALIAS_NONE
));
512 _cairo_xml_emit_string (xml
, "fill-rule",
513 _fill_rule_to_string (CAIRO_FILL_RULE_WINDING
));
515 _cairo_xml_indent (xml
, -2);
516 _cairo_xml_printf (xml
, "</clip>");
518 return CAIRO_STATUS_SUCCESS
;
521 static cairo_status_t
522 _cairo_xml_surface_emit_clip_path (cairo_xml_surface_t
*surface
,
523 const cairo_clip_path_t
*clip_path
)
526 cairo_status_t status
;
529 if (clip_path
== NULL
)
530 return CAIRO_STATUS_SUCCESS
;
532 status
= _cairo_xml_surface_emit_clip_path (surface
, clip_path
->prev
);
533 if (unlikely (status
))
536 /* skip the trivial clip covering the surface extents */
537 if (surface
->width
>= 0 && surface
->height
>= 0 &&
538 _cairo_path_fixed_is_box (&clip_path
->path
, &box
))
540 if (box
.p1
.x
<= 0 && box
.p1
.y
<= 0 &&
541 box
.p2
.x
- box
.p1
.x
>= _cairo_fixed_from_double (surface
->width
) &&
542 box
.p2
.y
- box
.p1
.y
>= _cairo_fixed_from_double (surface
->height
))
544 return CAIRO_STATUS_SUCCESS
;
548 xml
= to_xml (surface
);
550 _cairo_xml_printf_start (xml
, "<clip>");
551 _cairo_xml_indent (xml
, 2);
553 _cairo_xml_emit_path (xml
, &clip_path
->path
);
554 _cairo_xml_emit_double (xml
, "tolerance", clip_path
->tolerance
);
555 _cairo_xml_emit_string (xml
, "antialias",
556 _antialias_to_string (clip_path
->antialias
));
557 _cairo_xml_emit_string (xml
, "fill-rule",
558 _fill_rule_to_string (clip_path
->fill_rule
));
560 _cairo_xml_indent (xml
, -2);
561 _cairo_xml_printf_end (xml
, "</clip>");
563 return CAIRO_STATUS_SUCCESS
;
566 static cairo_status_t
567 _cairo_xml_surface_emit_clip (cairo_xml_surface_t
*surface
,
568 const cairo_clip_t
*clip
)
570 cairo_status_t status
;
573 return CAIRO_STATUS_SUCCESS
;
575 status
= _cairo_xml_surface_emit_clip_boxes (surface
, clip
);
576 if (unlikely (status
))
579 return _cairo_xml_surface_emit_clip_path (surface
, clip
->path
);
582 static cairo_status_t
583 _cairo_xml_emit_solid (cairo_xml_t
*xml
,
584 const cairo_solid_pattern_t
*solid
)
586 _cairo_xml_printf (xml
, "<solid>%f %f %f %f</solid>",
591 return CAIRO_STATUS_SUCCESS
;
595 _cairo_xml_emit_matrix (cairo_xml_t
*xml
,
596 const cairo_matrix_t
*matrix
)
598 if (! _cairo_matrix_is_identity (matrix
)) {
599 _cairo_xml_printf (xml
, "<matrix>%f %f %f %f %f %f</matrix>",
600 matrix
->xx
, matrix
->yx
,
601 matrix
->xy
, matrix
->yy
,
602 matrix
->x0
, matrix
->y0
);
607 _cairo_xml_emit_gradient (cairo_xml_t
*xml
,
608 const cairo_gradient_pattern_t
*gradient
)
612 for (i
= 0; i
< gradient
->n_stops
; i
++) {
613 _cairo_xml_printf (xml
,
614 "<color-stop>%f %f %f %f %f</color-stop>",
615 gradient
->stops
[i
].offset
,
616 gradient
->stops
[i
].color
.red
,
617 gradient
->stops
[i
].color
.green
,
618 gradient
->stops
[i
].color
.blue
,
619 gradient
->stops
[i
].color
.alpha
);
623 static cairo_status_t
624 _cairo_xml_emit_linear (cairo_xml_t
*xml
,
625 const cairo_linear_pattern_t
*linear
)
627 _cairo_xml_printf (xml
,
628 "<linear x1='%f' y1='%f' x2='%f' y2='%f'>",
629 linear
->pd1
.x
, linear
->pd1
.y
,
630 linear
->pd2
.x
, linear
->pd2
.y
);
631 _cairo_xml_indent (xml
, 2);
632 _cairo_xml_emit_gradient (xml
, &linear
->base
);
633 _cairo_xml_indent (xml
, -2);
634 _cairo_xml_printf (xml
, "</linear>");
635 return CAIRO_STATUS_SUCCESS
;
638 static cairo_status_t
639 _cairo_xml_emit_radial (cairo_xml_t
*xml
,
640 const cairo_radial_pattern_t
*radial
)
642 _cairo_xml_printf (xml
,
643 "<radial x1='%f' y1='%f' r1='%f' x2='%f' y2='%f' r2='%f'>",
644 radial
->cd1
.center
.x
, radial
->cd1
.center
.y
, radial
->cd1
.radius
,
645 radial
->cd2
.center
.x
, radial
->cd2
.center
.y
, radial
->cd2
.radius
);
646 _cairo_xml_indent (xml
, 2);
647 _cairo_xml_emit_gradient (xml
, &radial
->base
);
648 _cairo_xml_indent (xml
, -2);
649 _cairo_xml_printf (xml
, "</radial>");
650 return CAIRO_STATUS_SUCCESS
;
653 static cairo_status_t
654 _write_func (void *closure
, const unsigned char *data
, unsigned len
)
656 _cairo_output_stream_write (closure
, data
, len
);
657 return CAIRO_STATUS_SUCCESS
;
660 static cairo_status_t
661 _cairo_xml_emit_image (cairo_xml_t
*xml
,
662 cairo_image_surface_t
*image
)
664 cairo_output_stream_t
*stream
;
665 cairo_status_t status
;
667 _cairo_xml_printf_start (xml
,
668 "<image width='%d' height='%d' format='%s'>",
669 image
->width
, image
->height
,
670 _format_to_string (image
->format
));
672 stream
= _cairo_base64_stream_create (xml
->stream
);
673 status
= cairo_surface_write_to_png_stream (&image
->base
,
674 _write_func
, stream
);
675 assert (status
== CAIRO_STATUS_SUCCESS
);
676 status
= _cairo_output_stream_destroy (stream
);
677 if (unlikely (status
))
680 _cairo_xml_printf_end (xml
, "</image>");
682 return CAIRO_STATUS_SUCCESS
;
685 static cairo_status_t
686 _cairo_xml_emit_surface (cairo_xml_t
*xml
,
687 const cairo_surface_pattern_t
*pattern
)
689 cairo_surface_t
*source
= pattern
->surface
;
690 cairo_status_t status
;
692 if (_cairo_surface_is_recording (source
)) {
693 status
= cairo_xml_for_recording_surface (&xml
->base
, source
);
695 cairo_image_surface_t
*image
;
698 status
= _cairo_surface_acquire_source_image (source
,
699 &image
, &image_extra
);
700 if (unlikely (status
))
703 status
= _cairo_xml_emit_image (xml
, image
);
705 _cairo_surface_release_source_image (source
, image
, image_extra
);
711 static cairo_status_t
712 _cairo_xml_emit_pattern (cairo_xml_t
*xml
,
713 const char *source_or_mask
,
714 const cairo_pattern_t
*pattern
)
716 cairo_status_t status
;
718 _cairo_xml_printf (xml
, "<%s-pattern>", source_or_mask
);
719 _cairo_xml_indent (xml
, 2);
721 switch (pattern
->type
) {
722 case CAIRO_PATTERN_TYPE_SOLID
:
723 status
= _cairo_xml_emit_solid (xml
, (cairo_solid_pattern_t
*) pattern
);
725 case CAIRO_PATTERN_TYPE_LINEAR
:
726 status
= _cairo_xml_emit_linear (xml
, (cairo_linear_pattern_t
*) pattern
);
728 case CAIRO_PATTERN_TYPE_RADIAL
:
729 status
= _cairo_xml_emit_radial (xml
, (cairo_radial_pattern_t
*) pattern
);
731 case CAIRO_PATTERN_TYPE_SURFACE
:
732 status
= _cairo_xml_emit_surface (xml
, (cairo_surface_pattern_t
*) pattern
);
736 status
= CAIRO_INT_STATUS_UNSUPPORTED
;
740 if (pattern
->type
!= CAIRO_PATTERN_TYPE_SOLID
) {
741 _cairo_xml_emit_matrix (xml
, &pattern
->matrix
);
742 _cairo_xml_printf (xml
,
743 "<extend>%s</extend>",
744 _extend_to_string (pattern
->extend
));
745 _cairo_xml_printf (xml
,
746 "<filter>%s</filter>",
747 _filter_to_string (pattern
->filter
));
750 _cairo_xml_indent (xml
, -2);
751 _cairo_xml_printf (xml
, "</%s-pattern>", source_or_mask
);
756 static cairo_int_status_t
757 _cairo_xml_surface_paint (void *abstract_surface
,
759 const cairo_pattern_t
*source
,
760 const cairo_clip_t
*clip
)
762 cairo_xml_surface_t
*surface
= abstract_surface
;
763 cairo_xml_t
*xml
= to_xml (surface
);
764 cairo_status_t status
;
766 _cairo_xml_printf (xml
, "<paint>");
767 _cairo_xml_indent (xml
, 2);
769 _cairo_xml_emit_string (xml
, "operator", _operator_to_string (op
));
771 status
= _cairo_xml_surface_emit_clip (surface
, clip
);
772 if (unlikely (status
))
775 status
= _cairo_xml_emit_pattern (xml
, "source", source
);
776 if (unlikely (status
))
779 _cairo_xml_indent (xml
, -2);
780 _cairo_xml_printf (xml
, "</paint>");
782 return CAIRO_STATUS_SUCCESS
;
785 static cairo_int_status_t
786 _cairo_xml_surface_mask (void *abstract_surface
,
788 const cairo_pattern_t
*source
,
789 const cairo_pattern_t
*mask
,
790 const cairo_clip_t
*clip
)
792 cairo_xml_surface_t
*surface
= abstract_surface
;
793 cairo_xml_t
*xml
= to_xml (surface
);
794 cairo_status_t status
;
796 _cairo_xml_printf (xml
, "<mask>");
797 _cairo_xml_indent (xml
, 2);
799 _cairo_xml_emit_string (xml
, "operator", _operator_to_string (op
));
801 status
= _cairo_xml_surface_emit_clip (surface
, clip
);
802 if (unlikely (status
))
805 status
= _cairo_xml_emit_pattern (xml
, "source", source
);
806 if (unlikely (status
))
809 status
= _cairo_xml_emit_pattern (xml
, "mask", mask
);
810 if (unlikely (status
))
813 _cairo_xml_indent (xml
, -2);
814 _cairo_xml_printf (xml
, "</mask>");
816 return CAIRO_STATUS_SUCCESS
;
819 static cairo_int_status_t
820 _cairo_xml_surface_stroke (void *abstract_surface
,
822 const cairo_pattern_t
*source
,
823 const cairo_path_fixed_t
*path
,
824 const cairo_stroke_style_t
*style
,
825 const cairo_matrix_t
*ctm
,
826 const cairo_matrix_t
*ctm_inverse
,
828 cairo_antialias_t antialias
,
829 const cairo_clip_t
*clip
)
831 cairo_xml_surface_t
*surface
= abstract_surface
;
832 cairo_xml_t
*xml
= to_xml (surface
);
833 cairo_status_t status
;
835 _cairo_xml_printf (xml
, "<stroke>");
836 _cairo_xml_indent (xml
, 2);
838 _cairo_xml_emit_string (xml
, "operator", _operator_to_string (op
));
839 _cairo_xml_emit_double (xml
, "line-width", style
->line_width
);
840 _cairo_xml_emit_double (xml
, "miter-limit", style
->miter_limit
);
841 _cairo_xml_emit_string (xml
, "line-cap", _line_cap_to_string (style
->line_cap
));
842 _cairo_xml_emit_string (xml
, "line-join", _line_join_to_string (style
->line_join
));
844 status
= _cairo_xml_surface_emit_clip (surface
, clip
);
845 if (unlikely (status
))
848 status
= _cairo_xml_emit_pattern (xml
, "source", source
);
849 if (unlikely (status
))
852 if (style
->num_dashes
) {
855 _cairo_xml_printf_start (xml
, "<dash offset='%f'>",
857 for (i
= 0; i
< style
->num_dashes
; i
++)
858 _cairo_xml_printf_continue (xml
, "%f ", style
->dash
[i
]);
860 _cairo_xml_printf_end (xml
, "</dash>");
863 _cairo_xml_emit_path (xml
, path
);
864 _cairo_xml_emit_double (xml
, "tolerance", tolerance
);
865 _cairo_xml_emit_string (xml
, "antialias", _antialias_to_string (antialias
));
867 _cairo_xml_emit_matrix (xml
, ctm
);
869 _cairo_xml_indent (xml
, -2);
870 _cairo_xml_printf (xml
, "</stroke>");
872 return CAIRO_STATUS_SUCCESS
;
875 static cairo_int_status_t
876 _cairo_xml_surface_fill (void *abstract_surface
,
878 const cairo_pattern_t
*source
,
879 const cairo_path_fixed_t
*path
,
880 cairo_fill_rule_t fill_rule
,
882 cairo_antialias_t antialias
,
883 const cairo_clip_t
*clip
)
885 cairo_xml_surface_t
*surface
= abstract_surface
;
886 cairo_xml_t
*xml
= to_xml (surface
);
887 cairo_status_t status
;
889 _cairo_xml_printf (xml
, "<fill>");
890 _cairo_xml_indent (xml
, 2);
892 _cairo_xml_emit_string (xml
, "operator", _operator_to_string (op
));
894 status
= _cairo_xml_surface_emit_clip (surface
, clip
);
895 if (unlikely (status
))
898 status
= _cairo_xml_emit_pattern (xml
, "source", source
);
899 if (unlikely (status
))
902 _cairo_xml_emit_path (xml
, path
);
903 _cairo_xml_emit_double (xml
, "tolerance", tolerance
);
904 _cairo_xml_emit_string (xml
, "antialias", _antialias_to_string (antialias
));
905 _cairo_xml_emit_string (xml
, "fill-rule", _fill_rule_to_string (fill_rule
));
907 _cairo_xml_indent (xml
, -2);
908 _cairo_xml_printf (xml
, "</fill>");
910 return CAIRO_STATUS_SUCCESS
;
913 #if CAIRO_HAS_FT_FONT
914 #include "cairo-ft-private.h"
915 static cairo_status_t
916 _cairo_xml_emit_type42_font (cairo_xml_t
*xml
,
917 cairo_scaled_font_t
*scaled_font
)
919 const cairo_scaled_font_backend_t
*backend
;
920 cairo_output_stream_t
*base64_stream
;
921 cairo_output_stream_t
*zlib_stream
;
922 cairo_status_t status
, status2
;
927 backend
= scaled_font
->backend
;
928 if (backend
->load_truetype_table
== NULL
)
929 return CAIRO_INT_STATUS_UNSUPPORTED
;
932 status
= backend
->load_truetype_table (scaled_font
, 0, 0, NULL
, &size
);
933 if (unlikely (status
))
937 if (unlikely (buf
== NULL
))
938 return _cairo_error (CAIRO_STATUS_NO_MEMORY
);
940 status
= backend
->load_truetype_table (scaled_font
, 0, 0, buf
, &size
);
941 if (unlikely (status
)) {
946 _cairo_xml_printf_start (xml
, "<font type='42' flags='%d' index='0'>",
947 _cairo_ft_scaled_font_get_load_flags (scaled_font
));
950 base64_stream
= _cairo_base64_stream_create (xml
->stream
);
952 _cairo_output_stream_write (base64_stream
, &len
, sizeof (len
));
954 zlib_stream
= _cairo_deflate_stream_create (base64_stream
);
956 _cairo_output_stream_write (zlib_stream
, buf
, size
);
959 status2
= _cairo_output_stream_destroy (zlib_stream
);
960 if (status
== CAIRO_STATUS_SUCCESS
)
963 status2
= _cairo_output_stream_destroy (base64_stream
);
964 if (status
== CAIRO_STATUS_SUCCESS
)
967 _cairo_xml_printf_end (xml
, "</font>");
972 static cairo_status_t
973 _cairo_xml_emit_type42_font (cairo_xml_t
*xml
,
974 cairo_scaled_font_t
*scaled_font
)
976 return CAIRO_INT_STATUS_UNSUPPORTED
;
980 static cairo_status_t
981 _cairo_xml_emit_type3_font (cairo_xml_t
*xml
,
982 cairo_scaled_font_t
*scaled_font
,
983 cairo_glyph_t
*glyphs
,
986 _cairo_xml_printf_start (xml
, "<font type='3'>");
987 _cairo_xml_printf_end (xml
, "</font>");
989 return CAIRO_STATUS_SUCCESS
;
992 static cairo_status_t
993 _cairo_xml_emit_scaled_font (cairo_xml_t
*xml
,
994 cairo_scaled_font_t
*scaled_font
,
995 cairo_glyph_t
*glyphs
,
998 cairo_int_status_t status
;
1000 _cairo_xml_printf (xml
, "<scaled-font>");
1001 _cairo_xml_indent (xml
, 2);
1003 status
= _cairo_xml_emit_type42_font (xml
, scaled_font
);
1004 if (status
== CAIRO_INT_STATUS_UNSUPPORTED
) {
1005 status
= _cairo_xml_emit_type3_font (xml
, scaled_font
,
1006 glyphs
, num_glyphs
);
1009 _cairo_xml_indent (xml
, -2);
1010 _cairo_xml_printf (xml
, "<scaled-font>");
1015 static cairo_int_status_t
1016 _cairo_xml_surface_glyphs (void *abstract_surface
,
1017 cairo_operator_t op
,
1018 const cairo_pattern_t
*source
,
1019 cairo_glyph_t
*glyphs
,
1021 cairo_scaled_font_t
*scaled_font
,
1022 const cairo_clip_t
*clip
)
1024 cairo_xml_surface_t
*surface
= abstract_surface
;
1025 cairo_xml_t
*xml
= to_xml (surface
);
1026 cairo_status_t status
;
1029 _cairo_xml_printf (xml
, "<glyphs>");
1030 _cairo_xml_indent (xml
, 2);
1032 _cairo_xml_emit_string (xml
, "operator", _operator_to_string (op
));
1034 status
= _cairo_xml_surface_emit_clip (surface
, clip
);
1035 if (unlikely (status
))
1038 status
= _cairo_xml_emit_pattern (xml
, "source", source
);
1039 if (unlikely (status
))
1042 status
= _cairo_xml_emit_scaled_font (xml
, scaled_font
, glyphs
, num_glyphs
);
1043 if (unlikely (status
))
1046 for (i
= 0; i
< num_glyphs
; i
++) {
1047 _cairo_xml_printf (xml
, "<glyph index='%lu'>%f %f</glyph>",
1053 _cairo_xml_indent (xml
, -2);
1054 _cairo_xml_printf (xml
, "</glyphs>");
1056 return CAIRO_STATUS_SUCCESS
;
1059 static const cairo_surface_backend_t
1060 _cairo_xml_surface_backend
= {
1061 CAIRO_SURFACE_TYPE_XML
,
1064 _cairo_default_context_create
,
1066 _cairo_xml_surface_create_similar
,
1067 NULL
, /* create_similar_image */
1068 NULL
, /* map_to_image */
1069 NULL
, /* unmap_image */
1071 _cairo_surface_default_source
,
1072 NULL
, /* acquire source image */
1073 NULL
, /* release source image */
1074 NULL
, /* snapshot */
1076 NULL
, /* copy page */
1077 NULL
, /* show page */
1079 _cairo_xml_surface_get_extents
,
1080 NULL
, /* get_font_options */
1083 NULL
, /* mark_dirty_rectangle */
1085 _cairo_xml_surface_paint
,
1086 _cairo_xml_surface_mask
,
1087 _cairo_xml_surface_stroke
,
1088 _cairo_xml_surface_fill
,
1089 NULL
, /* fill_stroke */
1090 _cairo_xml_surface_glyphs
,
1093 static cairo_surface_t
*
1094 _cairo_xml_surface_create_internal (cairo_device_t
*device
,
1095 cairo_content_t content
,
1099 cairo_xml_surface_t
*surface
;
1101 surface
= malloc (sizeof (cairo_xml_surface_t
));
1102 if (unlikely (surface
== NULL
))
1103 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY
));
1105 _cairo_surface_init (&surface
->base
,
1106 &_cairo_xml_surface_backend
,
1110 surface
->width
= width
;
1111 surface
->height
= height
;
1113 return &surface
->base
;
1117 cairo_xml_create (const char *filename
)
1119 cairo_output_stream_t
*stream
;
1120 cairo_status_t status
;
1122 stream
= _cairo_output_stream_create_for_filename (filename
);
1123 if ((status
= _cairo_output_stream_get_status (stream
)))
1124 return _cairo_device_create_in_error (status
);
1126 return _cairo_xml_create_internal (stream
);
1130 cairo_xml_create_for_stream (cairo_write_func_t write_func
,
1133 cairo_output_stream_t
*stream
;
1134 cairo_status_t status
;
1136 stream
= _cairo_output_stream_create (write_func
, NULL
, closure
);
1137 if ((status
= _cairo_output_stream_get_status (stream
)))
1138 return _cairo_device_create_in_error (status
);
1140 return _cairo_xml_create_internal (stream
);
1144 cairo_xml_surface_create (cairo_device_t
*device
,
1145 cairo_content_t content
,
1146 double width
, double height
)
1148 if (unlikely (device
->backend
->type
!= CAIRO_DEVICE_TYPE_XML
))
1149 return _cairo_surface_create_in_error (CAIRO_STATUS_DEVICE_TYPE_MISMATCH
);
1151 if (unlikely (device
->status
))
1152 return _cairo_surface_create_in_error (device
->status
);
1154 return _cairo_xml_surface_create_internal (device
, content
, width
, height
);
1158 cairo_xml_for_recording_surface (cairo_device_t
*device
,
1159 cairo_surface_t
*recording_surface
)
1162 cairo_rectangle_int_t extents
;
1163 cairo_surface_t
*surface
;
1165 cairo_status_t status
;
1167 if (unlikely (device
->status
))
1168 return device
->status
;
1170 if (unlikely (recording_surface
->status
))
1171 return recording_surface
->status
;
1173 if (unlikely (device
->backend
->type
!= CAIRO_DEVICE_TYPE_XML
))
1174 return _cairo_error (CAIRO_STATUS_DEVICE_TYPE_MISMATCH
);
1176 if (unlikely (! _cairo_surface_is_recording (recording_surface
)))
1177 return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH
);
1179 status
= _cairo_recording_surface_get_bbox ((cairo_recording_surface_t
*) recording_surface
,
1181 if (unlikely (status
))
1184 _cairo_box_round_to_rectangle (&bbox
, &extents
);
1185 surface
= _cairo_xml_surface_create_internal (device
,
1186 recording_surface
->content
,
1189 if (unlikely (surface
->status
))
1190 return surface
->status
;
1192 xml
= (cairo_xml_t
*) device
;
1194 _cairo_xml_printf (xml
,
1195 "<surface content='%s' width='%d' height='%d'>",
1196 _content_to_string (recording_surface
->content
),
1197 extents
.width
, extents
.height
);
1198 _cairo_xml_indent (xml
, 2);
1200 cairo_surface_set_device_offset (surface
, -extents
.x
, -extents
.y
);
1201 status
= _cairo_recording_surface_replay (recording_surface
, surface
);
1202 cairo_surface_destroy (surface
);
1204 _cairo_xml_indent (xml
, -2);
1205 _cairo_xml_printf (xml
, "</surface>");
1209 slim_hidden_def (cairo_xml_for_recording_surface
);