Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
4349 Serge 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
3
 *
4
 * Copyright © 2009 Chris Wilson
5
 *
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.
13
 *
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
19
 *
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/
24
 *
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.
28
 *
29
 * The Original Code is the cairo graphics library.
30
 *
31
 * The Initial Developer of the Original Code is Chris Wilson.
32
 *
33
 * Contributor(s):
34
 *      Chris Wilson 
35
 */
36
 
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.
41
 */
42
 
43
#include "cairoint.h"
44
 
45
#include "cairo-xml.h"
46
 
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"
54
 
55
#define static cairo_warn static
56
 
57
typedef struct _cairo_xml_surface cairo_xml_surface_t;
58
 
59
typedef struct _cairo_xml {
60
    cairo_device_t base;
61
 
62
    cairo_output_stream_t *stream;
63
    int indent;
64
} cairo_xml_t;
65
 
66
struct _cairo_xml_surface {
67
    cairo_surface_t base;
68
 
69
    double width, height;
70
};
71
 
72
slim_hidden_proto (cairo_xml_for_recording_surface);
73
 
74
static const cairo_surface_backend_t _cairo_xml_surface_backend;
75
 
76
static const char *
77
_operator_to_string (cairo_operator_t op)
78
{
79
    static const char *names[] = {
80
	"CLEAR",	/* CAIRO_OPERATOR_CLEAR */
81
 
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 */
87
 
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 */
93
 
94
	"XOR",		/* CAIRO_OPERATOR_XOR */
95
	"ADD",		/* CAIRO_OPERATOR_ADD */
96
	"SATURATE",	/* CAIRO_OPERATOR_SATURATE */
97
 
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 */
113
    };
114
    assert (op < ARRAY_LENGTH (names));
115
    return names[op];
116
}
117
 
118
static const char *
119
_extend_to_string (cairo_extend_t extend)
120
{
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 */
126
    };
127
    assert (extend < ARRAY_LENGTH (names));
128
    return names[extend];
129
}
130
 
131
static const char *
132
_filter_to_string (cairo_filter_t filter)
133
{
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 */
141
    };
142
    assert (filter < ARRAY_LENGTH (names));
143
    return names[filter];
144
}
145
 
146
static const char *
147
_fill_rule_to_string (cairo_fill_rule_t rule)
148
{
149
    static const char *names[] = {
150
	"WINDING",	/* CAIRO_FILL_RULE_WINDING */
151
	"EVEN_ODD"	/* CAIRO_FILL_RILE_EVEN_ODD */
152
    };
153
    assert (rule < ARRAY_LENGTH (names));
154
    return names[rule];
155
}
156
 
157
static const char *
158
_antialias_to_string (cairo_antialias_t antialias)
159
{
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 */
168
    };
169
    assert (antialias < ARRAY_LENGTH (names));
170
    return names[antialias];
171
}
172
 
173
static const char *
174
_line_cap_to_string (cairo_line_cap_t line_cap)
175
{
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 */
180
    };
181
    assert (line_cap < ARRAY_LENGTH (names));
182
    return names[line_cap];
183
}
184
 
185
static const char *
186
_line_join_to_string (cairo_line_join_t line_join)
187
{
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 */
192
    };
193
    assert (line_join < ARRAY_LENGTH (names));
194
    return names[line_join];
195
}
196
 
197
static const char *
198
_content_to_string (cairo_content_t content)
199
{
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";
205
    }
206
}
207
 
208
static const char *
209
_format_to_string (cairo_format_t format)
210
{
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";
219
    }
220
    ASSERT_NOT_REACHED;
221
    return "INVALID";
222
}
223
 
224
static cairo_status_t
225
_device_flush (void *abstract_device)
226
{
227
    cairo_xml_t *xml = abstract_device;
228
    cairo_status_t status;
229
 
230
    status = _cairo_output_stream_flush (xml->stream);
231
 
232
    return status;
233
}
234
 
235
static void
236
_device_destroy (void *abstract_device)
237
{
238
    cairo_xml_t *xml = abstract_device;
239
    cairo_status_t status;
240
 
241
    status = _cairo_output_stream_destroy (xml->stream);
242
 
243
    free (xml);
244
}
245
 
246
static const cairo_device_backend_t _cairo_xml_device_backend = {
247
    CAIRO_DEVICE_TYPE_XML,
248
 
249
    NULL, NULL, /* lock, unlock */
250
 
251
    _device_flush,
252
    NULL,  /* finish */
253
    _device_destroy
254
};
255
 
256
static cairo_device_t *
257
_cairo_xml_create_internal (cairo_output_stream_t *stream)
258
{
259
    cairo_xml_t *xml;
260
 
261
    xml = malloc (sizeof (cairo_xml_t));
262
    if (unlikely (xml == NULL))
263
	return _cairo_device_create_in_error (CAIRO_STATUS_NO_MEMORY);
264
 
265
    memset (xml, 0, sizeof (cairo_xml_t));
266
 
267
    _cairo_device_init (&xml->base, &_cairo_xml_device_backend);
268
 
269
    xml->indent = 0;
270
    xml->stream = stream;
271
 
272
    return &xml->base;
273
}
274
 
275
static void
276
_cairo_xml_indent (cairo_xml_t *xml, int indent)
277
{
278
    xml->indent += indent;
279
    assert (xml->indent >= 0);
280
}
281
 
282
static void CAIRO_PRINTF_FORMAT (2, 3)
283
_cairo_xml_printf (cairo_xml_t *xml, const char *fmt, ...)
284
{
285
    va_list ap;
286
    char indent[80];
287
    int len;
288
 
289
    len = MIN (xml->indent, ARRAY_LENGTH (indent));
290
    memset (indent, ' ', len);
291
    _cairo_output_stream_write (xml->stream, indent, len);
292
 
293
    va_start (ap, fmt);
294
    _cairo_output_stream_vprintf (xml->stream, fmt, ap);
295
    va_end (ap);
296
 
297
    _cairo_output_stream_write (xml->stream, "\n", 1);
298
}
299
 
300
static void CAIRO_PRINTF_FORMAT (2, 3)
301
_cairo_xml_printf_start (cairo_xml_t *xml, const char *fmt, ...)
302
{
303
    char indent[80];
304
    int len;
305
 
306
    len = MIN (xml->indent, ARRAY_LENGTH (indent));
307
    memset (indent, ' ', len);
308
    _cairo_output_stream_write (xml->stream, indent, len);
309
 
310
    if (fmt != NULL) {
311
	va_list ap;
312
 
313
	va_start (ap, fmt);
314
	_cairo_output_stream_vprintf (xml->stream, fmt, ap);
315
	va_end (ap);
316
    }
317
}
318
 
319
static void CAIRO_PRINTF_FORMAT (2, 3)
320
_cairo_xml_printf_continue (cairo_xml_t *xml, const char *fmt, ...)
321
{
322
    va_list ap;
323
 
324
    va_start (ap, fmt);
325
    _cairo_output_stream_vprintf (xml->stream, fmt, ap);
326
    va_end (ap);
327
}
328
 
329
static void CAIRO_PRINTF_FORMAT (2, 3)
330
_cairo_xml_printf_end (cairo_xml_t *xml, const char *fmt, ...)
331
{
332
    if (fmt != NULL) {
333
	va_list ap;
334
 
335
	va_start (ap, fmt);
336
	_cairo_output_stream_vprintf (xml->stream, fmt, ap);
337
	va_end (ap);
338
    }
339
 
340
    _cairo_output_stream_write (xml->stream, "\n", 1);
341
}
342
 
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)
348
{
349
    cairo_rectangle_t extents;
350
 
351
    extents.x = extents.y = 0;
352
    extents.width  = width;
353
    extents.height = height;
354
 
355
    return cairo_recording_surface_create (content, &extents);
356
}
357
 
358
static cairo_bool_t
359
_cairo_xml_surface_get_extents (void *abstract_surface,
360
				cairo_rectangle_int_t *rectangle)
361
{
362
    cairo_xml_surface_t *surface = abstract_surface;
363
 
364
    if (surface->width < 0 || surface->height < 0)
365
	return FALSE;
366
 
367
    rectangle->x = 0;
368
    rectangle->y = 0;
369
    rectangle->width  = surface->width;
370
    rectangle->height = surface->height;
371
 
372
    return TRUE;
373
}
374
 
375
static cairo_status_t
376
_cairo_xml_move_to (void *closure,
377
		    const cairo_point_t *p1)
378
{
379
    _cairo_xml_printf_continue (closure, " %f %f m",
380
				_cairo_fixed_to_double (p1->x),
381
				_cairo_fixed_to_double (p1->y));
382
 
383
    return CAIRO_STATUS_SUCCESS;
384
}
385
 
386
static cairo_status_t
387
_cairo_xml_line_to (void *closure,
388
		    const cairo_point_t *p1)
389
{
390
    _cairo_xml_printf_continue (closure, " %f %f l",
391
				_cairo_fixed_to_double (p1->x),
392
				_cairo_fixed_to_double (p1->y));
393
 
394
    return CAIRO_STATUS_SUCCESS;
395
}
396
 
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)
402
{
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));
410
 
411
    return CAIRO_STATUS_SUCCESS;
412
}
413
 
414
static cairo_status_t
415
_cairo_xml_close_path (void *closure)
416
{
417
    _cairo_xml_printf_continue (closure, " h");
418
 
419
    return CAIRO_STATUS_SUCCESS;
420
}
421
 
422
static void
423
_cairo_xml_emit_path (cairo_xml_t *xml,
424
		      const cairo_path_fixed_t *path)
425
{
426
    cairo_status_t status;
427
 
428
    _cairo_xml_printf_start (xml, "");
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, "");
437
}
438
 
439
static void
440
_cairo_xml_emit_string (cairo_xml_t *xml,
441
			const char *node,
442
			const char *data)
443
{
444
    _cairo_xml_printf (xml, "<%s>%s", node, data, node);
445
}
446
 
447
static void
448
_cairo_xml_emit_double (cairo_xml_t *xml,
449
			const char *node,
450
			double data)
451
{
452
    _cairo_xml_printf (xml, "<%s>%f", node, data, node);
453
}
454
 
455
static cairo_xml_t *
456
to_xml (cairo_xml_surface_t *surface)
457
{
458
    return (cairo_xml_t *) surface->base.device;
459
}
460
 
461
static cairo_status_t
462
_cairo_xml_surface_emit_clip_boxes (cairo_xml_surface_t *surface,
463
				    cairo_clip_t *clip)
464
{
465
    cairo_box_t *box;
466
    cairo_status_t status;
467
    cairo_xml_t *xml;
468
    int n;
469
 
470
    if (clip->num_boxes == 0)
471
	return CAIRO_STATUS_SUCCESS;
472
 
473
    /* skip the trivial clip covering the surface extents */
474
    if (surface->width >= 0 && surface->height >= 0 && clip->num_boxes == 1) {
475
	box = &clip->boxes[0];
476
	if (box->p1.x <= 0 && box->p1.y <= 0 &&
477
	    box->p2.x - box->p1.x >= _cairo_fixed_from_double (surface->width) &&
478
	    box->p2.y - box->p1.y >= _cairo_fixed_from_double (surface->height))
479
	{
480
	    return CAIRO_STATUS_SUCCESS;
481
	}
482
    }
483
 
484
    xml = to_xml (surface);
485
 
486
    _cairo_xml_printf (xml, "");
487
    _cairo_xml_indent (xml, 2);
488
 
489
    _cairo_xml_printf (xml, "");
490
    _cairo_xml_indent (xml, 2);
491
    for (n = 0; n < clip->num_boxes; n++) {
492
	box = &clip->boxes[n];
493
 
494
	_cairo_xml_printf_start (xml, "%f %f m",
495
				 _cairo_fixed_to_double (box->p1.x),
496
				 _cairo_fixed_to_double (box->p1.y));
497
	_cairo_xml_printf_continue (xml, " %f %f l",
498
				    _cairo_fixed_to_double (box->p2.x),
499
				    _cairo_fixed_to_double (box->p1.y));
500
	_cairo_xml_printf_continue (xml, " %f %f l",
501
				    _cairo_fixed_to_double (box->p2.x),
502
				    _cairo_fixed_to_double (box->p2.y));
503
	_cairo_xml_printf_continue (xml, " %f %f l",
504
				    _cairo_fixed_to_double (box->p1.x),
505
				    _cairo_fixed_to_double (box->p2.y));
506
	_cairo_xml_printf_end (xml, " h");
507
    }
508
    _cairo_xml_indent (xml, -2);
509
    _cairo_xml_printf (xml, "");
510
    _cairo_xml_emit_double (xml, "tolerance", 1.0);
511
    _cairo_xml_emit_string (xml, "antialias",
512
			    _antialias_to_string (CAIRO_ANTIALIAS_NONE));
513
    _cairo_xml_emit_string (xml, "fill-rule",
514
			    _fill_rule_to_string (CAIRO_FILL_RULE_WINDING));
515
 
516
    _cairo_xml_indent (xml, -2);
517
    _cairo_xml_printf (xml, "");
518
 
519
    return CAIRO_STATUS_SUCCESS;
520
}
521
 
522
static cairo_status_t
523
_cairo_xml_surface_emit_clip_path (cairo_xml_surface_t *surface,
524
				   cairo_clip_path_t *clip_path)
525
{
526
    cairo_box_t box;
527
    cairo_status_t status;
528
    cairo_xml_t *xml;
529
 
530
    if (clip_path == NULL)
531
	return CAIRO_STATUS_SUCCESS;
532
 
533
    status = _cairo_xml_surface_emit_clip_path (surface, clip_path->prev);
534
    if (unlikely (status))
535
	return status;
536
 
537
    /* skip the trivial clip covering the surface extents */
538
    if (surface->width >= 0 && surface->height >= 0 &&
539
	_cairo_path_fixed_is_box (&clip_path->path, &box))
540
    {
541
	if (box.p1.x <= 0 && box.p1.y <= 0 &&
542
	    box.p2.x - box.p1.x >= _cairo_fixed_from_double (surface->width) &&
543
	    box.p2.y - box.p1.y >= _cairo_fixed_from_double (surface->height))
544
	{
545
	    return CAIRO_STATUS_SUCCESS;
546
	}
547
    }
548
 
549
    xml = to_xml (surface);
550
 
551
    _cairo_xml_printf_start (xml, "");
552
    _cairo_xml_indent (xml, 2);
553
 
554
    _cairo_xml_emit_path (xml, &clip_path->path);
555
    _cairo_xml_emit_double (xml, "tolerance", clip_path->tolerance);
556
    _cairo_xml_emit_string (xml, "antialias",
557
			    _antialias_to_string (clip_path->antialias));
558
    _cairo_xml_emit_string (xml, "fill-rule",
559
			    _fill_rule_to_string (clip_path->fill_rule));
560
 
561
    _cairo_xml_indent (xml, -2);
562
    _cairo_xml_printf_end (xml, "");
563
 
564
    return CAIRO_STATUS_SUCCESS;
565
}
566
 
567
static cairo_status_t
568
_cairo_xml_surface_emit_clip (cairo_xml_surface_t *surface,
569
			      const cairo_clip_t *clip)
570
{
571
    cairo_status_t status;
572
 
573
    if (clip == NULL)
574
	return CAIRO_STATUS_SUCCESS;
575
 
576
    status = _cairo_xml_surface_emit_clip_boxes (surface, clip);
577
    if (unlikely (status))
578
	return status;
579
 
580
    return _cairo_xml_surface_emit_clip_path (surface, clip->path);
581
}
582
 
583
static cairo_status_t
584
_cairo_xml_emit_solid (cairo_xml_t *xml,
585
		       const cairo_solid_pattern_t *solid)
586
{
587
    _cairo_xml_printf (xml, "%f %f %f %f",
588
		       solid->color.red,
589
		       solid->color.green,
590
		       solid->color.blue,
591
		       solid->color.alpha);
592
    return CAIRO_STATUS_SUCCESS;
593
}
594
 
595
static void
596
_cairo_xml_emit_matrix (cairo_xml_t *xml,
597
			const cairo_matrix_t *matrix)
598
{
599
    if (! _cairo_matrix_is_identity (matrix)) {
600
	_cairo_xml_printf (xml, "%f %f %f %f %f %f",
601
			   matrix->xx, matrix->yx,
602
			   matrix->xy, matrix->yy,
603
			   matrix->x0, matrix->y0);
604
    }
605
}
606
 
607
static void
608
_cairo_xml_emit_gradient (cairo_xml_t *xml,
609
			  const cairo_gradient_pattern_t *gradient)
610
{
611
    unsigned int i;
612
 
613
    for (i = 0; i < gradient->n_stops; i++) {
614
	_cairo_xml_printf (xml,
615
			   "%f %f %f %f %f",
616
			   gradient->stops[i].offset,
617
			   gradient->stops[i].color.red,
618
			   gradient->stops[i].color.green,
619
			   gradient->stops[i].color.blue,
620
			   gradient->stops[i].color.alpha);
621
    }
622
}
623
 
624
static cairo_status_t
625
_cairo_xml_emit_linear (cairo_xml_t *xml,
626
			const cairo_linear_pattern_t *linear)
627
{
628
    _cairo_xml_printf (xml,
629
		       "",
630
		       linear->pd1.x, linear->pd1.y,
631
		       linear->pd2.x, linear->pd2.y);
632
    _cairo_xml_indent (xml, 2);
633
    _cairo_xml_emit_gradient (xml, &linear->base);
634
    _cairo_xml_indent (xml, -2);
635
    _cairo_xml_printf (xml, "");
636
    return CAIRO_STATUS_SUCCESS;
637
}
638
 
639
static cairo_status_t
640
_cairo_xml_emit_radial (cairo_xml_t *xml,
641
			const cairo_radial_pattern_t *radial)
642
{
643
    _cairo_xml_printf (xml,
644
		       "",
645
		       radial->cd1.center.x, radial->cd1.center.y, radial->cd1.radius,
646
		       radial->cd2.center.x, radial->cd2.center.y, radial->cd2.radius);
647
    _cairo_xml_indent (xml, 2);
648
    _cairo_xml_emit_gradient (xml, &radial->base);
649
    _cairo_xml_indent (xml, -2);
650
    _cairo_xml_printf (xml, "");
651
    return CAIRO_STATUS_SUCCESS;
652
}
653
 
654
static cairo_status_t
655
_write_func (void *closure, const unsigned char *data, unsigned len)
656
{
657
    _cairo_output_stream_write (closure, data, len);
658
    return CAIRO_STATUS_SUCCESS;
659
}
660
 
661
static cairo_status_t
662
_cairo_xml_emit_image (cairo_xml_t *xml,
663
		       cairo_image_surface_t *image)
664
{
665
    cairo_output_stream_t *stream;
666
    cairo_status_t status;
667
 
668
    _cairo_xml_printf_start (xml,
669
			     "",
670
			     image->width, image->height,
671
			     _format_to_string (image->format));
672
 
673
    stream = _cairo_base64_stream_create (xml->stream);
674
    status = cairo_surface_write_to_png_stream (&image->base,
675
						_write_func, stream);
676
    assert (status == CAIRO_STATUS_SUCCESS);
677
    status = _cairo_output_stream_destroy (stream);
678
    if (unlikely (status))
679
	return status;
680
 
681
    _cairo_xml_printf_end (xml, "");
682
 
683
    return CAIRO_STATUS_SUCCESS;
684
}
685
 
686
static cairo_status_t
687
_cairo_xml_emit_surface (cairo_xml_t *xml,
688
			 const cairo_surface_pattern_t *pattern)
689
{
690
    cairo_surface_t *source = pattern->surface;
691
    cairo_status_t status;
692
 
693
    if (_cairo_surface_is_recording (source)) {
694
	status = cairo_xml_for_recording_surface (&xml->base, source);
695
    } else {
696
	cairo_image_surface_t *image;
697
	void *image_extra;
698
 
699
	status = _cairo_surface_acquire_source_image (source,
700
						      &image, &image_extra);
701
	if (unlikely (status))
702
	    return status;
703
 
704
	status = _cairo_xml_emit_image (xml, image);
705
 
706
	_cairo_surface_release_source_image (source, image, image_extra);
707
    }
708
 
709
    return status;
710
}
711
 
712
static cairo_status_t
713
_cairo_xml_emit_pattern (cairo_xml_t *xml,
714
			 const char *source_or_mask,
715
			 const cairo_pattern_t *pattern)
716
{
717
    cairo_status_t status;
718
 
719
    _cairo_xml_printf (xml, "<%s-pattern>", source_or_mask);
720
    _cairo_xml_indent (xml, 2);
721
 
722
    switch (pattern->type) {
723
    case CAIRO_PATTERN_TYPE_SOLID:
724
	status = _cairo_xml_emit_solid (xml, (cairo_solid_pattern_t *) pattern);
725
	break;
726
    case CAIRO_PATTERN_TYPE_LINEAR:
727
	status = _cairo_xml_emit_linear (xml, (cairo_linear_pattern_t *) pattern);
728
	break;
729
    case CAIRO_PATTERN_TYPE_RADIAL:
730
	status = _cairo_xml_emit_radial (xml, (cairo_radial_pattern_t *) pattern);
731
	break;
732
    case CAIRO_PATTERN_TYPE_SURFACE:
733
	status = _cairo_xml_emit_surface (xml, (cairo_surface_pattern_t *) pattern);
734
	break;
735
    default:
736
	ASSERT_NOT_REACHED;
737
	status = CAIRO_INT_STATUS_UNSUPPORTED;
738
	break;
739
    }
740
 
741
    if (pattern->type != CAIRO_PATTERN_TYPE_SOLID) {
742
	_cairo_xml_emit_matrix (xml, &pattern->matrix);
743
	_cairo_xml_printf (xml,
744
			   "%s",
745
			   _extend_to_string (pattern->extend));
746
	_cairo_xml_printf (xml,
747
			   "%s",
748
			   _filter_to_string (pattern->filter));
749
    }
750
 
751
    _cairo_xml_indent (xml, -2);
752
    _cairo_xml_printf (xml, "", source_or_mask);
753
 
754
    return status;
755
}
756
 
757
static cairo_int_status_t
758
_cairo_xml_surface_paint (void			*abstract_surface,
759
			  cairo_operator_t	 op,
760
			  const cairo_pattern_t	*source,
761
			  const cairo_clip_t	*clip)
762
{
763
    cairo_xml_surface_t *surface = abstract_surface;
764
    cairo_xml_t *xml = to_xml (surface);
765
    cairo_status_t status;
766
 
767
    _cairo_xml_printf (xml, "");
768
    _cairo_xml_indent (xml, 2);
769
 
770
    _cairo_xml_emit_string (xml, "operator", _operator_to_string (op));
771
 
772
    status = _cairo_xml_surface_emit_clip (surface, clip);
773
    if (unlikely (status))
774
	return status;
775
 
776
    status = _cairo_xml_emit_pattern (xml, "source", source);
777
    if (unlikely (status))
778
	return status;
779
 
780
    _cairo_xml_indent (xml, -2);
781
    _cairo_xml_printf (xml, "");
782
 
783
    return CAIRO_STATUS_SUCCESS;
784
}
785
 
786
static cairo_int_status_t
787
_cairo_xml_surface_mask (void			*abstract_surface,
788
			 cairo_operator_t	 op,
789
			 const cairo_pattern_t	*source,
790
			 const cairo_pattern_t	*mask,
791
			 const cairo_clip_t	*clip)
792
{
793
    cairo_xml_surface_t *surface = abstract_surface;
794
    cairo_xml_t *xml = to_xml (surface);
795
    cairo_status_t status;
796
 
797
    _cairo_xml_printf (xml, "");
798
    _cairo_xml_indent (xml, 2);
799
 
800
    _cairo_xml_emit_string (xml, "operator", _operator_to_string (op));
801
 
802
    status = _cairo_xml_surface_emit_clip (surface, clip);
803
    if (unlikely (status))
804
	return status;
805
 
806
    status = _cairo_xml_emit_pattern (xml, "source", source);
807
    if (unlikely (status))
808
	return status;
809
 
810
    status = _cairo_xml_emit_pattern (xml, "mask", mask);
811
    if (unlikely (status))
812
	return status;
813
 
814
    _cairo_xml_indent (xml, -2);
815
    _cairo_xml_printf (xml, "");
816
 
817
    return CAIRO_STATUS_SUCCESS;
818
}
819
 
820
static cairo_int_status_t
821
_cairo_xml_surface_stroke (void				*abstract_surface,
822
			   cairo_operator_t		 op,
823
			   const cairo_pattern_t	*source,
824
			   const cairo_path_fixed_t		*path,
825
			   const cairo_stroke_style_t		*style,
826
			   const cairo_matrix_t		*ctm,
827
			   const cairo_matrix_t		*ctm_inverse,
828
			   double			 tolerance,
829
			   cairo_antialias_t		 antialias,
830
			   const cairo_clip_t		*clip)
831
{
832
    cairo_xml_surface_t *surface = abstract_surface;
833
    cairo_xml_t *xml = to_xml (surface);
834
    cairo_status_t status;
835
 
836
    _cairo_xml_printf (xml, "");
837
    _cairo_xml_indent (xml, 2);
838
 
839
    _cairo_xml_emit_string (xml, "operator", _operator_to_string (op));
840
    _cairo_xml_emit_double (xml, "line-width", style->line_width);
841
    _cairo_xml_emit_double (xml, "miter-limit", style->miter_limit);
842
    _cairo_xml_emit_string (xml, "line-cap", _line_cap_to_string (style->line_cap));
843
    _cairo_xml_emit_string (xml, "line-join", _line_join_to_string (style->line_join));
844
 
845
    status = _cairo_xml_surface_emit_clip (surface, clip);
846
    if (unlikely (status))
847
	return status;
848
 
849
    status = _cairo_xml_emit_pattern (xml, "source", source);
850
    if (unlikely (status))
851
	return status;
852
 
853
    if (style->num_dashes) {
854
	unsigned int i;
855
 
856
	_cairo_xml_printf_start (xml, "",
857
				 style->dash_offset);
858
	for (i = 0; i < style->num_dashes; i++)
859
	    _cairo_xml_printf_continue (xml, "%f ", style->dash[i]);
860
 
861
	_cairo_xml_printf_end (xml, "");
862
    }
863
 
864
    _cairo_xml_emit_path (xml, path);
865
    _cairo_xml_emit_double (xml, "tolerance", tolerance);
866
    _cairo_xml_emit_string (xml, "antialias", _antialias_to_string (antialias));
867
 
868
    _cairo_xml_emit_matrix (xml, ctm);
869
 
870
    _cairo_xml_indent (xml, -2);
871
    _cairo_xml_printf (xml, "");
872
 
873
    return CAIRO_STATUS_SUCCESS;
874
}
875
 
876
static cairo_int_status_t
877
_cairo_xml_surface_fill (void			*abstract_surface,
878
			 cairo_operator_t	 op,
879
			 const cairo_pattern_t	*source,
880
			 const cairo_path_fixed_t*path,
881
			 cairo_fill_rule_t	 fill_rule,
882
			 double			 tolerance,
883
			 cairo_antialias_t	 antialias,
884
			 const cairo_clip_t	*clip)
885
{
886
    cairo_xml_surface_t *surface = abstract_surface;
887
    cairo_xml_t *xml = to_xml (surface);
888
    cairo_status_t status;
889
 
890
    _cairo_xml_printf (xml, "");
891
    _cairo_xml_indent (xml, 2);
892
 
893
    _cairo_xml_emit_string (xml, "operator", _operator_to_string (op));
894
 
895
    status = _cairo_xml_surface_emit_clip (surface, clip);
896
    if (unlikely (status))
897
	return status;
898
 
899
    status = _cairo_xml_emit_pattern (xml, "source", source);
900
    if (unlikely (status))
901
	return status;
902
 
903
    _cairo_xml_emit_path (xml, path);
904
    _cairo_xml_emit_double (xml, "tolerance", tolerance);
905
    _cairo_xml_emit_string (xml, "antialias", _antialias_to_string (antialias));
906
    _cairo_xml_emit_string (xml, "fill-rule", _fill_rule_to_string (fill_rule));
907
 
908
    _cairo_xml_indent (xml, -2);
909
    _cairo_xml_printf (xml, "");
910
 
911
    return CAIRO_STATUS_SUCCESS;
912
}
913
 
914
#if CAIRO_HAS_FT_FONT
915
#include "cairo-ft-private.h"
916
static cairo_status_t
917
_cairo_xml_emit_type42_font (cairo_xml_t *xml,
918
			     cairo_scaled_font_t *scaled_font)
919
{
920
    const cairo_scaled_font_backend_t *backend;
921
    cairo_output_stream_t *base64_stream;
922
    cairo_output_stream_t *zlib_stream;
923
    cairo_status_t status, status2;
924
    unsigned long size;
925
    uint32_t len;
926
    uint8_t *buf;
927
 
928
    backend = scaled_font->backend;
929
    if (backend->load_truetype_table == NULL)
930
	return CAIRO_INT_STATUS_UNSUPPORTED;
931
 
932
    size = 0;
933
    status = backend->load_truetype_table (scaled_font, 0, 0, NULL, &size);
934
    if (unlikely (status))
935
	return status;
936
 
937
    buf = malloc (size);
938
    if (unlikely (buf == NULL))
939
	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
940
 
941
    status = backend->load_truetype_table (scaled_font, 0, 0, buf, &size);
942
    if (unlikely (status)) {
943
	free (buf);
944
	return status;
945
    }
946
 
947
    _cairo_xml_printf_start (xml, "",
948
		       _cairo_ft_scaled_font_get_load_flags (scaled_font));
949
 
950
 
951
    base64_stream = _cairo_base64_stream_create (xml->stream);
952
    len = size;
953
    _cairo_output_stream_write (base64_stream, &len, sizeof (len));
954
 
955
    zlib_stream = _cairo_deflate_stream_create (base64_stream);
956
 
957
    _cairo_output_stream_write (zlib_stream, buf, size);
958
    free (buf);
959
 
960
    status2 = _cairo_output_stream_destroy (zlib_stream);
961
    if (status == CAIRO_STATUS_SUCCESS)
962
	status = status2;
963
 
964
    status2 = _cairo_output_stream_destroy (base64_stream);
965
    if (status == CAIRO_STATUS_SUCCESS)
966
	status = status2;
967
 
968
    _cairo_xml_printf_end (xml, "");
969
 
970
    return status;
971
}
972
#else
973
static cairo_status_t
974
_cairo_xml_emit_type42_font (cairo_xml_t *xml,
975
			     cairo_scaled_font_t *scaled_font)
976
{
977
    return CAIRO_INT_STATUS_UNSUPPORTED;
978
}
979
#endif
980
 
981
static cairo_status_t
982
_cairo_xml_emit_type3_font (cairo_xml_t *xml,
983
			    cairo_scaled_font_t *scaled_font,
984
			    cairo_glyph_t *glyphs,
985
			    int num_glyphs)
986
{
987
    _cairo_xml_printf_start (xml, "");
988
    _cairo_xml_printf_end (xml, "");
989
 
990
    return CAIRO_STATUS_SUCCESS;
991
}
992
 
993
static cairo_status_t
994
_cairo_xml_emit_scaled_font (cairo_xml_t *xml,
995
			     cairo_scaled_font_t *scaled_font,
996
			     cairo_glyph_t *glyphs,
997
			     int num_glyphs)
998
{
999
    cairo_int_status_t status;
1000
 
1001
    _cairo_xml_printf (xml, "");
1002
    _cairo_xml_indent (xml, 2);
1003
 
1004
    status = _cairo_xml_emit_type42_font (xml, scaled_font);
1005
    if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
1006
	status = _cairo_xml_emit_type3_font (xml, scaled_font,
1007
					     glyphs, num_glyphs);
1008
    }
1009
 
1010
    _cairo_xml_indent (xml, -2);
1011
    _cairo_xml_printf (xml, "");
1012
 
1013
    return status;
1014
}
1015
 
1016
static cairo_int_status_t
1017
_cairo_xml_surface_glyphs (void			    *abstract_surface,
1018
			   cairo_operator_t	     op,
1019
			   const cairo_pattern_t    *source,
1020
			   cairo_glyph_t	    *glyphs,
1021
			   int			     num_glyphs,
1022
			   cairo_scaled_font_t	    *scaled_font,
1023
			   const cairo_clip_t       *clip)
1024
{
1025
    cairo_xml_surface_t *surface = abstract_surface;
1026
    cairo_xml_t *xml = to_xml (surface);
1027
    cairo_status_t status;
1028
    int i;
1029
 
1030
    _cairo_xml_printf (xml, "");
1031
    _cairo_xml_indent (xml, 2);
1032
 
1033
    _cairo_xml_emit_string (xml, "operator", _operator_to_string (op));
1034
 
1035
    status = _cairo_xml_surface_emit_clip (surface, clip);
1036
    if (unlikely (status))
1037
	return status;
1038
 
1039
    status = _cairo_xml_emit_pattern (xml, "source", source);
1040
    if (unlikely (status))
1041
	return status;
1042
 
1043
    status = _cairo_xml_emit_scaled_font (xml, scaled_font, glyphs, num_glyphs);
1044
    if (unlikely (status))
1045
	return status;
1046
 
1047
    for (i = 0; i < num_glyphs; i++) {
1048
	_cairo_xml_printf (xml, "%f %f",
1049
			   glyphs[i].index,
1050
			   glyphs[i].x,
1051
			   glyphs[i].y);
1052
    }
1053
 
1054
    _cairo_xml_indent (xml, -2);
1055
    _cairo_xml_printf (xml, "");
1056
 
1057
    return CAIRO_STATUS_SUCCESS;
1058
}
1059
 
1060
static const cairo_surface_backend_t
1061
_cairo_xml_surface_backend = {
1062
    CAIRO_SURFACE_TYPE_XML,
1063
    NULL,
1064
 
1065
    _cairo_default_context_create,
1066
 
1067
    _cairo_xml_surface_create_similar,
1068
    NULL, /* create_similar_image */
1069
    NULL, /* map_to_image */
1070
    NULL, /* unmap_image */
1071
 
1072
    _cairo_surface_default_source,
1073
    NULL, /* acquire source image */
1074
    NULL, /* release source image */
1075
    NULL, /* snapshot */
1076
 
1077
    NULL, /* copy page */
1078
    NULL, /* show page */
1079
 
1080
    _cairo_xml_surface_get_extents,
1081
    NULL, /* get_font_options */
1082
 
1083
    NULL, /* flush */
1084
    NULL, /* mark_dirty_rectangle */
1085
 
1086
    _cairo_xml_surface_paint,
1087
    _cairo_xml_surface_mask,
1088
    _cairo_xml_surface_stroke,
1089
    _cairo_xml_surface_fill,
1090
    NULL, /* fill_stroke */
1091
    _cairo_xml_surface_glyphs,
1092
};
1093
 
1094
static cairo_surface_t *
1095
_cairo_xml_surface_create_internal (cairo_device_t *device,
1096
				    cairo_content_t content,
1097
				    double width,
1098
				    double height)
1099
{
1100
    cairo_xml_surface_t *surface;
1101
 
1102
    surface = malloc (sizeof (cairo_xml_surface_t));
1103
    if (unlikely (surface == NULL))
1104
	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
1105
 
1106
    _cairo_surface_init (&surface->base,
1107
			 &_cairo_xml_surface_backend,
1108
			 device,
1109
			 content);
1110
 
1111
    surface->width = width;
1112
    surface->height = height;
1113
 
1114
    return &surface->base;
1115
}
1116
 
1117
cairo_device_t *
1118
cairo_xml_create (const char *filename)
1119
{
1120
    cairo_output_stream_t *stream;
1121
    cairo_status_t status;
1122
 
1123
    stream = _cairo_output_stream_create_for_filename (filename);
1124
    if ((status = _cairo_output_stream_get_status (stream)))
1125
	return _cairo_device_create_in_error (status);
1126
 
1127
    return _cairo_xml_create_internal (stream);
1128
}
1129
 
1130
cairo_device_t *
1131
cairo_xml_create_for_stream (cairo_write_func_t	 write_func,
1132
			     void		*closure)
1133
{
1134
    cairo_output_stream_t *stream;
1135
    cairo_status_t status;
1136
 
1137
    stream = _cairo_output_stream_create (write_func, NULL, closure);
1138
    if ((status = _cairo_output_stream_get_status (stream)))
1139
	return _cairo_device_create_in_error (status);
1140
 
1141
    return _cairo_xml_create_internal (stream);
1142
}
1143
 
1144
cairo_surface_t *
1145
cairo_xml_surface_create (cairo_device_t *device,
1146
			  cairo_content_t content,
1147
			  double width, double height)
1148
{
1149
    if (unlikely (device->backend->type != CAIRO_DEVICE_TYPE_XML))
1150
	return _cairo_surface_create_in_error (CAIRO_STATUS_DEVICE_TYPE_MISMATCH);
1151
 
1152
    if (unlikely (device->status))
1153
	return _cairo_surface_create_in_error (device->status);
1154
 
1155
    return _cairo_xml_surface_create_internal (device, content, width, height);
1156
}
1157
 
1158
cairo_status_t
1159
cairo_xml_for_recording_surface (cairo_device_t	 *device,
1160
				 cairo_surface_t *recording_surface)
1161
{
1162
    cairo_box_t bbox;
1163
    cairo_rectangle_int_t extents;
1164
    cairo_surface_t *surface;
1165
    cairo_xml_t *xml;
1166
    cairo_status_t status;
1167
 
1168
    if (unlikely (device->status))
1169
	return device->status;
1170
 
1171
    if (unlikely (recording_surface->status))
1172
	return recording_surface->status;
1173
 
1174
    if (unlikely (device->backend->type != CAIRO_DEVICE_TYPE_XML))
1175
	return _cairo_error (CAIRO_STATUS_DEVICE_TYPE_MISMATCH);
1176
 
1177
    if (unlikely (! _cairo_surface_is_recording (recording_surface)))
1178
	return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
1179
 
1180
    status = _cairo_recording_surface_get_bbox ((cairo_recording_surface_t *) recording_surface,
1181
						&bbox, NULL);
1182
    if (unlikely (status))
1183
	return status;
1184
 
1185
    _cairo_box_round_to_rectangle (&bbox, &extents);
1186
    surface = _cairo_xml_surface_create_internal (device,
1187
						  recording_surface->content,
1188
						  extents.width,
1189
						  extents.height);
1190
    if (unlikely (surface->status))
1191
	return surface->status;
1192
 
1193
    xml = (cairo_xml_t *) device;
1194
 
1195
    _cairo_xml_printf (xml,
1196
		       "",
1197
		       _content_to_string (recording_surface->content),
1198
		       extents.width, extents.height);
1199
    _cairo_xml_indent (xml, 2);
1200
 
1201
    cairo_surface_set_device_offset (surface, -extents.x, -extents.y);
1202
    status = _cairo_recording_surface_replay (recording_surface, surface);
1203
    cairo_surface_destroy (surface);
1204
 
1205
    _cairo_xml_indent (xml, -2);
1206
    _cairo_xml_printf (xml, "");
1207
 
1208
    return status;
1209
}
1210
slim_hidden_def (cairo_xml_for_recording_surface);