beta-0.89.2
[luatex.git] / source / libs / cairo / cairo-src / src / cairo-xml-surface.c
blob6dbafdba2bac50d5d4c9ee705be9f4fa872b3548
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.
33 * Contributor(s):
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
40 * operations.
43 #include "cairoint.h"
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 {
60 cairo_device_t base;
62 cairo_output_stream_t *stream;
63 int indent;
64 } cairo_xml_t;
66 struct _cairo_xml_surface {
67 cairo_surface_t base;
69 double width, height;
72 slim_hidden_proto (cairo_xml_for_recording_surface);
74 static const cairo_surface_backend_t _cairo_xml_surface_backend;
76 static const char *
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));
115 return names[op];
118 static const char *
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];
131 static const char *
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];
146 static const char *
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));
154 return names[rule];
157 static const char *
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];
173 static const char *
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];
185 static const char *
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];
197 static const char *
198 _content_to_string (cairo_content_t content)
200 switch (content) {
201 case CAIRO_CONTENT_ALPHA: return "ALPHA";
202 case CAIRO_CONTENT_COLOR: return "COLOR";
203 default:
204 case CAIRO_CONTENT_COLOR_ALPHA: return "COLOR_ALPHA";
208 static const char *
209 _format_to_string (cairo_format_t format)
211 switch (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";
220 ASSERT_NOT_REACHED;
221 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);
232 return status;
235 static void
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);
243 free (xml);
246 static const cairo_device_backend_t _cairo_xml_device_backend = {
247 CAIRO_DEVICE_TYPE_XML,
249 NULL, NULL, /* lock, unlock */
251 _device_flush,
252 NULL, /* finish */
253 _device_destroy
256 static cairo_device_t *
257 _cairo_xml_create_internal (cairo_output_stream_t *stream)
259 cairo_xml_t *xml;
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);
269 xml->indent = 0;
270 xml->stream = stream;
272 return &xml->base;
275 static void
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, ...)
285 va_list ap;
286 char indent[80];
287 int len;
289 len = MIN (xml->indent, ARRAY_LENGTH (indent));
290 memset (indent, ' ', len);
291 _cairo_output_stream_write (xml->stream, indent, len);
293 va_start (ap, fmt);
294 _cairo_output_stream_vprintf (xml->stream, fmt, ap);
295 va_end (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, ...)
303 char indent[80];
304 int len;
306 len = MIN (xml->indent, ARRAY_LENGTH (indent));
307 memset (indent, ' ', len);
308 _cairo_output_stream_write (xml->stream, indent, len);
310 if (fmt != NULL) {
311 va_list ap;
313 va_start (ap, fmt);
314 _cairo_output_stream_vprintf (xml->stream, fmt, ap);
315 va_end (ap);
319 static void CAIRO_PRINTF_FORMAT (2, 3)
320 _cairo_xml_printf_continue (cairo_xml_t *xml, const char *fmt, ...)
322 va_list ap;
324 va_start (ap, fmt);
325 _cairo_output_stream_vprintf (xml->stream, fmt, ap);
326 va_end (ap);
329 static void CAIRO_PRINTF_FORMAT (2, 3)
330 _cairo_xml_printf_end (cairo_xml_t *xml, const char *fmt, ...)
332 if (fmt != NULL) {
333 va_list ap;
335 va_start (ap, fmt);
336 _cairo_output_stream_vprintf (xml->stream, fmt, ap);
337 va_end (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,
346 int width,
347 int height)
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);
358 static cairo_bool_t
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)
365 return FALSE;
367 rectangle->x = 0;
368 rectangle->y = 0;
369 rectangle->width = surface->width;
370 rectangle->height = surface->height;
372 return TRUE;
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;
422 static void
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,
430 _cairo_xml_move_to,
431 _cairo_xml_line_to,
432 _cairo_xml_curve_to,
433 _cairo_xml_close_path,
434 xml);
435 assert (status == CAIRO_STATUS_SUCCESS);
436 _cairo_xml_printf_end (xml, "</path>");
439 static void
440 _cairo_xml_emit_string (cairo_xml_t *xml,
441 const char *node,
442 const char *data)
444 _cairo_xml_printf (xml, "<%s>%s</%s>", node, data, node);
447 static void
448 _cairo_xml_emit_double (cairo_xml_t *xml,
449 const char *node,
450 double data)
452 _cairo_xml_printf (xml, "<%s>%f</%s>", node, data, node);
455 static cairo_xml_t *
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)
465 cairo_box_t *box;
466 cairo_xml_t *xml;
467 int n;
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)
525 cairo_box_t box;
526 cairo_status_t status;
527 cairo_xml_t *xml;
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))
534 return 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;
572 if (clip == NULL)
573 return CAIRO_STATUS_SUCCESS;
575 status = _cairo_xml_surface_emit_clip_boxes (surface, clip);
576 if (unlikely (status))
577 return 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>",
587 solid->color.red,
588 solid->color.green,
589 solid->color.blue,
590 solid->color.alpha);
591 return CAIRO_STATUS_SUCCESS;
594 static void
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);
606 static void
607 _cairo_xml_emit_gradient (cairo_xml_t *xml,
608 const cairo_gradient_pattern_t *gradient)
610 unsigned int i;
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))
678 return 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);
694 } else {
695 cairo_image_surface_t *image;
696 void *image_extra;
698 status = _cairo_surface_acquire_source_image (source,
699 &image, &image_extra);
700 if (unlikely (status))
701 return status;
703 status = _cairo_xml_emit_image (xml, image);
705 _cairo_surface_release_source_image (source, image, image_extra);
708 return status;
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);
724 break;
725 case CAIRO_PATTERN_TYPE_LINEAR:
726 status = _cairo_xml_emit_linear (xml, (cairo_linear_pattern_t *) pattern);
727 break;
728 case CAIRO_PATTERN_TYPE_RADIAL:
729 status = _cairo_xml_emit_radial (xml, (cairo_radial_pattern_t *) pattern);
730 break;
731 case CAIRO_PATTERN_TYPE_SURFACE:
732 status = _cairo_xml_emit_surface (xml, (cairo_surface_pattern_t *) pattern);
733 break;
734 default:
735 ASSERT_NOT_REACHED;
736 status = CAIRO_INT_STATUS_UNSUPPORTED;
737 break;
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);
753 return status;
756 static cairo_int_status_t
757 _cairo_xml_surface_paint (void *abstract_surface,
758 cairo_operator_t op,
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))
773 return status;
775 status = _cairo_xml_emit_pattern (xml, "source", source);
776 if (unlikely (status))
777 return 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,
787 cairo_operator_t op,
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))
803 return status;
805 status = _cairo_xml_emit_pattern (xml, "source", source);
806 if (unlikely (status))
807 return status;
809 status = _cairo_xml_emit_pattern (xml, "mask", mask);
810 if (unlikely (status))
811 return 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,
821 cairo_operator_t op,
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,
827 double tolerance,
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))
846 return status;
848 status = _cairo_xml_emit_pattern (xml, "source", source);
849 if (unlikely (status))
850 return status;
852 if (style->num_dashes) {
853 unsigned int i;
855 _cairo_xml_printf_start (xml, "<dash offset='%f'>",
856 style->dash_offset);
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,
877 cairo_operator_t op,
878 const cairo_pattern_t *source,
879 const cairo_path_fixed_t*path,
880 cairo_fill_rule_t fill_rule,
881 double tolerance,
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))
896 return status;
898 status = _cairo_xml_emit_pattern (xml, "source", source);
899 if (unlikely (status))
900 return 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;
923 unsigned long size;
924 uint32_t len;
925 uint8_t *buf;
927 backend = scaled_font->backend;
928 if (backend->load_truetype_table == NULL)
929 return CAIRO_INT_STATUS_UNSUPPORTED;
931 size = 0;
932 status = backend->load_truetype_table (scaled_font, 0, 0, NULL, &size);
933 if (unlikely (status))
934 return status;
936 buf = malloc (size);
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)) {
942 free (buf);
943 return 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);
951 len = size;
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);
957 free (buf);
959 status2 = _cairo_output_stream_destroy (zlib_stream);
960 if (status == CAIRO_STATUS_SUCCESS)
961 status = status2;
963 status2 = _cairo_output_stream_destroy (base64_stream);
964 if (status == CAIRO_STATUS_SUCCESS)
965 status = status2;
967 _cairo_xml_printf_end (xml, "</font>");
969 return status;
971 #else
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;
978 #endif
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,
984 int num_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,
996 int num_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>");
1012 return status;
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,
1020 int num_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;
1027 int i;
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))
1036 return status;
1038 status = _cairo_xml_emit_pattern (xml, "source", source);
1039 if (unlikely (status))
1040 return status;
1042 status = _cairo_xml_emit_scaled_font (xml, scaled_font, glyphs, num_glyphs);
1043 if (unlikely (status))
1044 return status;
1046 for (i = 0; i < num_glyphs; i++) {
1047 _cairo_xml_printf (xml, "<glyph index='%lu'>%f %f</glyph>",
1048 glyphs[i].index,
1049 glyphs[i].x,
1050 glyphs[i].y);
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,
1062 NULL,
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 */
1082 NULL, /* flush */
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,
1096 double width,
1097 double height)
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,
1107 device,
1108 content);
1110 surface->width = width;
1111 surface->height = height;
1113 return &surface->base;
1116 cairo_device_t *
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);
1129 cairo_device_t *
1130 cairo_xml_create_for_stream (cairo_write_func_t write_func,
1131 void *closure)
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);
1143 cairo_surface_t *
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);
1157 cairo_status_t
1158 cairo_xml_for_recording_surface (cairo_device_t *device,
1159 cairo_surface_t *recording_surface)
1161 cairo_box_t bbox;
1162 cairo_rectangle_int_t extents;
1163 cairo_surface_t *surface;
1164 cairo_xml_t *xml;
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,
1180 &bbox, NULL);
1181 if (unlikely (status))
1182 return status;
1184 _cairo_box_round_to_rectangle (&bbox, &extents);
1185 surface = _cairo_xml_surface_create_internal (device,
1186 recording_surface->content,
1187 extents.width,
1188 extents.height);
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>");
1207 return status;
1209 slim_hidden_def (cairo_xml_for_recording_surface);