Subversion Repositories Kolibri OS

Rev

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 © 2008 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
/* The script surface is one that records all operations performed on
38
 * it in the form of a procedural script, similar in fashion to
39
 * PostScript but using Cairo's imaging model. In essence, this is
40
 * equivalent to the recording-surface, but as there is no impedance mismatch
41
 * between Cairo and CairoScript, we can generate output immediately
42
 * without having to copy and hold the data in memory.
43
 */
44
 
45
/**
46
 * SECTION:cairo-script
47
 * @Title: Script Surfaces
48
 * @Short_Description: Rendering to replayable scripts
49
 * @See_Also: #cairo_surface_t
50
 *
51
 * The script surface provides the ability to render to a native
52
 * script that matches the cairo drawing model. The scripts can
53
 * be replayed using tools under the util/cairo-script directoriy,
54
 * or with cairo-perf-trace.
55
 **/
56
 
57
/**
58
 * CAIRO_HAS_SCRIPT_SURFACE:
59
 *
60
 * Defined if the script surface backend is available.
61
 * The script surface backend is always built in since 1.12.
62
 *
63
 * Since: 1.12
64
 **/
65
 
66
 
67
#include "cairoint.h"
68
 
69
#include "cairo-script.h"
70
#include "cairo-script-private.h"
71
 
72
#include "cairo-analysis-surface-private.h"
73
#include "cairo-default-context-private.h"
74
#include "cairo-device-private.h"
75
#include "cairo-error-private.h"
76
#include "cairo-list-inline.h"
77
#include "cairo-image-surface-private.h"
78
#include "cairo-output-stream-private.h"
79
#include "cairo-pattern-private.h"
80
#include "cairo-recording-surface-inline.h"
81
#include "cairo-scaled-font-private.h"
82
#include "cairo-surface-clipper-private.h"
83
#include "cairo-surface-snapshot-inline.h"
84
#include "cairo-surface-subsurface-private.h"
85
#include "cairo-surface-wrapper-private.h"
86
 
87
#if CAIRO_HAS_FT_FONT
88
#include "cairo-ft-private.h"
89
#endif
90
 
91
#include 
92
 
93
#ifdef WORDS_BIGENDIAN
94
#define to_be32(x) x
95
#else
96
#define to_be32(x) bswap_32(x)
97
#endif
98
 
99
#define _cairo_output_stream_puts(S, STR) \
100
    _cairo_output_stream_write ((S), (STR), strlen (STR))
101
 
102
#define static cairo_warn static
103
 
104
typedef struct _cairo_script_context cairo_script_context_t;
105
typedef struct _cairo_script_surface cairo_script_surface_t;
106
typedef struct _cairo_script_implicit_context cairo_script_implicit_context_t;
107
typedef struct _cairo_script_font cairo_script_font_t;
108
 
109
typedef struct _operand {
110
    enum {
111
	SURFACE,
112
	DEFERRED,
113
    } type;
114
    cairo_list_t link;
115
} operand_t;
116
 
117
 
118
struct deferred_finish {
119
    cairo_list_t link;
120
    operand_t operand;
121
};
122
 
123
struct _cairo_script_context {
124
    cairo_device_t base;
125
 
126
    int active;
127
    int attach_snapshots;
128
 
129
    cairo_bool_t owns_stream;
130
    cairo_output_stream_t *stream;
131
    cairo_script_mode_t mode;
132
 
133
    struct _bitmap {
134
	unsigned long min;
135
	unsigned long count;
136
	unsigned int map[64];
137
	struct _bitmap *next;
138
    } surface_id, font_id;
139
 
140
    cairo_list_t operands;
141
    cairo_list_t deferred;
142
 
143
    cairo_list_t fonts;
144
    cairo_list_t defines;
145
};
146
 
147
struct _cairo_script_font {
148
    cairo_scaled_font_private_t base;
149
 
150
    cairo_bool_t has_sfnt;
151
    unsigned long id;
152
    unsigned long subset_glyph_index;
153
    cairo_list_t link;
154
    cairo_scaled_font_t *parent;
155
};
156
 
157
struct _cairo_script_implicit_context {
158
    cairo_operator_t current_operator;
159
    cairo_fill_rule_t current_fill_rule;
160
    double current_tolerance;
161
    cairo_antialias_t current_antialias;
162
    cairo_stroke_style_t current_style;
163
    cairo_pattern_union_t current_source;
164
    cairo_matrix_t current_ctm;
165
    cairo_matrix_t current_stroke_matrix;
166
    cairo_matrix_t current_font_matrix;
167
    cairo_font_options_t current_font_options;
168
    cairo_scaled_font_t *current_scaled_font;
169
    cairo_path_fixed_t current_path;
170
    cairo_bool_t has_clip;
171
};
172
 
173
struct _cairo_script_surface {
174
    cairo_surface_t base;
175
 
176
    cairo_surface_wrapper_t wrapper;
177
 
178
    cairo_surface_clipper_t clipper;
179
 
180
    operand_t operand;
181
    cairo_bool_t emitted;
182
    cairo_bool_t defined;
183
    cairo_bool_t active;
184
 
185
    double width, height;
186
 
187
    /* implicit flattened context */
188
    cairo_script_implicit_context_t cr;
189
};
190
 
191
static const cairo_surface_backend_t _cairo_script_surface_backend;
192
 
193
static cairo_script_surface_t *
194
_cairo_script_surface_create_internal (cairo_script_context_t *ctx,
195
				       cairo_content_t content,
196
				       cairo_rectangle_t *extents,
197
				       cairo_surface_t *passthrough);
198
 
199
static void
200
_cairo_script_scaled_font_fini (cairo_scaled_font_private_t *abstract_private,
201
				cairo_scaled_font_t *scaled_font);
202
 
203
static void
204
_cairo_script_implicit_context_init (cairo_script_implicit_context_t *cr);
205
 
206
static void
207
_cairo_script_implicit_context_reset (cairo_script_implicit_context_t *cr);
208
 
209
static void
210
_bitmap_release_id (struct _bitmap *b, unsigned long token)
211
{
212
    struct _bitmap **prev = NULL;
213
 
214
    do {
215
	if (token < b->min + sizeof (b->map) * CHAR_BIT) {
216
	    unsigned int bit, elem;
217
 
218
	    token -= b->min;
219
	    elem = token / (sizeof (b->map[0]) * CHAR_BIT);
220
	    bit  = token % (sizeof (b->map[0]) * CHAR_BIT);
221
	    b->map[elem] &= ~(1 << bit);
222
	    if (! --b->count && prev) {
223
		*prev = b->next;
224
		free (b);
225
	    }
226
	    return;
227
	}
228
	prev = &b->next;
229
	b = b->next;
230
    } while (b != NULL);
231
}
232
 
233
static cairo_status_t
234
_bitmap_next_id (struct _bitmap *b,
235
		 unsigned long *id)
236
{
237
    struct _bitmap *bb, **prev = NULL;
238
    unsigned long min = 0;
239
 
240
    do {
241
	if (b->min != min)
242
	    break;
243
 
244
	if (b->count < sizeof (b->map) * CHAR_BIT) {
245
	    unsigned int n, m, bit;
246
	    for (n = 0; n < ARRAY_LENGTH (b->map); n++) {
247
		if (b->map[n] == (unsigned int) -1)
248
		    continue;
249
 
250
		for (m=0, bit=1; mmap[0])*CHAR_BIT; m++, bit<<=1) {
251
		    if ((b->map[n] & bit) == 0) {
252
			b->map[n] |= bit;
253
			b->count++;
254
			*id = n * sizeof (b->map[0])*CHAR_BIT + m + b->min;
255
			return CAIRO_STATUS_SUCCESS;
256
		    }
257
		}
258
	    }
259
	}
260
	min += sizeof (b->map) * CHAR_BIT;
261
 
262
	prev = &b->next;
263
	b = b->next;
264
    } while (b != NULL);
265
 
266
    bb = malloc (sizeof (struct _bitmap));
267
    if (unlikely (bb == NULL))
268
	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
269
 
270
    *prev = bb;
271
    bb->next = b;
272
    bb->min = min;
273
    bb->count = 1;
274
    bb->map[0] = 0x1;
275
    memset (bb->map + 1, 0, sizeof (bb->map) - sizeof (bb->map[0]));
276
    *id = min;
277
 
278
    return CAIRO_STATUS_SUCCESS;
279
}
280
 
281
static void
282
_bitmap_fini (struct _bitmap *b)
283
{
284
    while (b != NULL) {
285
	struct _bitmap *next = b->next;
286
	free (b);
287
	b = next;
288
    }
289
}
290
 
291
static const char *
292
_direction_to_string (cairo_bool_t backward)
293
{
294
    static const char *names[] = {
295
	"FORWARD",
296
	"BACKWARD"
297
    };
298
    assert (backward < ARRAY_LENGTH (names));
299
    return names[backward];
300
}
301
 
302
static const char *
303
_operator_to_string (cairo_operator_t op)
304
{
305
    static const char *names[] = {
306
	"CLEAR",	/* CAIRO_OPERATOR_CLEAR */
307
 
308
	"SOURCE",	/* CAIRO_OPERATOR_SOURCE */
309
	"OVER",		/* CAIRO_OPERATOR_OVER */
310
	"IN",		/* CAIRO_OPERATOR_IN */
311
	"OUT",		/* CAIRO_OPERATOR_OUT */
312
	"ATOP",		/* CAIRO_OPERATOR_ATOP */
313
 
314
	"DEST",		/* CAIRO_OPERATOR_DEST */
315
	"DEST_OVER",	/* CAIRO_OPERATOR_DEST_OVER */
316
	"DEST_IN",	/* CAIRO_OPERATOR_DEST_IN */
317
	"DEST_OUT",	/* CAIRO_OPERATOR_DEST_OUT */
318
	"DEST_ATOP",	/* CAIRO_OPERATOR_DEST_ATOP */
319
 
320
	"XOR",		/* CAIRO_OPERATOR_XOR */
321
	"ADD",		/* CAIRO_OPERATOR_ADD */
322
	"SATURATE",	/* CAIRO_OPERATOR_SATURATE */
323
 
324
	"MULTIPLY",	/* CAIRO_OPERATOR_MULTIPLY */
325
	"SCREEN",	/* CAIRO_OPERATOR_SCREEN */
326
	"OVERLAY",	/* CAIRO_OPERATOR_OVERLAY */
327
	"DARKEN",	/* CAIRO_OPERATOR_DARKEN */
328
	"LIGHTEN",	/* CAIRO_OPERATOR_LIGHTEN */
329
	"DODGE",	/* CAIRO_OPERATOR_COLOR_DODGE */
330
	"BURN",		/* CAIRO_OPERATOR_COLOR_BURN */
331
	"HARD_LIGHT",	/* CAIRO_OPERATOR_HARD_LIGHT */
332
	"SOFT_LIGHT",	/* CAIRO_OPERATOR_SOFT_LIGHT */
333
	"DIFFERENCE",	/* CAIRO_OPERATOR_DIFFERENCE */
334
	"EXCLUSION",	/* CAIRO_OPERATOR_EXCLUSION */
335
	"HSL_HUE",	/* CAIRO_OPERATOR_HSL_HUE */
336
	"HSL_SATURATION", /* CAIRO_OPERATOR_HSL_SATURATION */
337
	"HSL_COLOR",	/* CAIRO_OPERATOR_HSL_COLOR */
338
	"HSL_LUMINOSITY" /* CAIRO_OPERATOR_HSL_LUMINOSITY */
339
    };
340
    assert (op < ARRAY_LENGTH (names));
341
    return names[op];
342
}
343
 
344
static const char *
345
_extend_to_string (cairo_extend_t extend)
346
{
347
    static const char *names[] = {
348
	"EXTEND_NONE",		/* CAIRO_EXTEND_NONE */
349
	"EXTEND_REPEAT",	/* CAIRO_EXTEND_REPEAT */
350
	"EXTEND_REFLECT",	/* CAIRO_EXTEND_REFLECT */
351
	"EXTEND_PAD"		/* CAIRO_EXTEND_PAD */
352
    };
353
    assert (extend < ARRAY_LENGTH (names));
354
    return names[extend];
355
}
356
 
357
static const char *
358
_filter_to_string (cairo_filter_t filter)
359
{
360
    static const char *names[] = {
361
	"FILTER_FAST",		/* CAIRO_FILTER_FAST */
362
	"FILTER_GOOD",		/* CAIRO_FILTER_GOOD */
363
	"FILTER_BEST",		/* CAIRO_FILTER_BEST */
364
	"FILTER_NEAREST",	/* CAIRO_FILTER_NEAREST */
365
	"FILTER_BILINEAR",	/* CAIRO_FILTER_BILINEAR */
366
	"FILTER_GAUSSIAN",	/* CAIRO_FILTER_GAUSSIAN */
367
    };
368
    assert (filter < ARRAY_LENGTH (names));
369
    return names[filter];
370
}
371
 
372
static const char *
373
_fill_rule_to_string (cairo_fill_rule_t rule)
374
{
375
    static const char *names[] = {
376
	"WINDING",	/* CAIRO_FILL_RULE_WINDING */
377
	"EVEN_ODD"	/* CAIRO_FILL_RILE_EVEN_ODD */
378
    };
379
    assert (rule < ARRAY_LENGTH (names));
380
    return names[rule];
381
}
382
 
383
static const char *
384
_antialias_to_string (cairo_antialias_t antialias)
385
{
386
    static const char *names[] = {
387
	"ANTIALIAS_DEFAULT",	/* CAIRO_ANTIALIAS_DEFAULT */
388
	"ANTIALIAS_NONE",	/* CAIRO_ANTIALIAS_NONE */
389
	"ANTIALIAS_GRAY",	/* CAIRO_ANTIALIAS_GRAY */
390
	"ANTIALIAS_SUBPIXEL",	/* CAIRO_ANTIALIAS_SUBPIXEL */
391
	"ANTIALIAS_FAST",	/* CAIRO_ANTIALIAS_FAST */
392
	"ANTIALIAS_GOOD",	/* CAIRO_ANTIALIAS_GOOD */
393
	"ANTIALIAS_BEST"	/* CAIRO_ANTIALIAS_BEST */
394
    };
395
    assert (antialias < ARRAY_LENGTH (names));
396
    return names[antialias];
397
}
398
 
399
static const char *
400
_line_cap_to_string (cairo_line_cap_t line_cap)
401
{
402
    static const char *names[] = {
403
	"LINE_CAP_BUTT",	/* CAIRO_LINE_CAP_BUTT */
404
	"LINE_CAP_ROUND",	/* CAIRO_LINE_CAP_ROUND */
405
	"LINE_CAP_SQUARE"	/* CAIRO_LINE_CAP_SQUARE */
406
    };
407
    assert (line_cap < ARRAY_LENGTH (names));
408
    return names[line_cap];
409
}
410
 
411
static const char *
412
_line_join_to_string (cairo_line_join_t line_join)
413
{
414
    static const char *names[] = {
415
	"LINE_JOIN_MITER",	/* CAIRO_LINE_JOIN_MITER */
416
	"LINE_JOIN_ROUND",	/* CAIRO_LINE_JOIN_ROUND */
417
	"LINE_JOIN_BEVEL",	/* CAIRO_LINE_JOIN_BEVEL */
418
    };
419
    assert (line_join < ARRAY_LENGTH (names));
420
    return names[line_join];
421
}
422
 
423
static inline cairo_script_context_t *
424
to_context (cairo_script_surface_t *surface)
425
{
426
    return (cairo_script_context_t *) surface->base.device;
427
}
428
 
429
static cairo_bool_t
430
target_is_active (cairo_script_surface_t *surface)
431
{
432
    return cairo_list_is_first (&surface->operand.link,
433
				&to_context (surface)->operands);
434
}
435
 
436
static void
437
target_push (cairo_script_surface_t *surface)
438
{
439
    cairo_list_move (&surface->operand.link, &to_context (surface)->operands);
440
}
441
 
442
static int
443
target_depth (cairo_script_surface_t *surface)
444
{
445
    cairo_list_t *link;
446
    int depth = 0;
447
 
448
    cairo_list_foreach (link, &to_context (surface)->operands) {
449
	if (link == &surface->operand.link)
450
	    break;
451
	depth++;
452
    }
453
 
454
    return depth;
455
}
456
 
457
static void
458
_get_target (cairo_script_surface_t *surface)
459
{
460
    cairo_script_context_t *ctx = to_context (surface);
461
 
462
    if (target_is_active (surface)) {
463
	_cairo_output_stream_puts (ctx->stream, "dup ");
464
	return;
465
    }
466
 
467
    if (surface->defined) {
468
	_cairo_output_stream_printf (ctx->stream, "s%u ",
469
				     surface->base.unique_id);
470
    } else {
471
	int depth = target_depth (surface);
472
 
473
	assert (! cairo_list_is_empty (&surface->operand.link));
474
	assert (! target_is_active (surface));
475
 
476
	if (ctx->active) {
477
	    _cairo_output_stream_printf (ctx->stream, "%d index ", depth);
478
	    _cairo_output_stream_puts (ctx->stream, "/target get exch pop ");
479
	} else {
480
	    if (depth == 1) {
481
		_cairo_output_stream_puts (ctx->stream, "exch ");
482
	    } else {
483
		_cairo_output_stream_printf (ctx->stream,
484
					     "%d -1 roll ", depth);
485
	    }
486
	    target_push (surface);
487
	    _cairo_output_stream_puts (ctx->stream, "dup ");
488
	}
489
    }
490
}
491
 
492
static const char *
493
_content_to_string (cairo_content_t content)
494
{
495
    switch (content) {
496
    case CAIRO_CONTENT_ALPHA: return "ALPHA";
497
    case CAIRO_CONTENT_COLOR: return "COLOR";
498
    default:
499
    case CAIRO_CONTENT_COLOR_ALPHA: return "COLOR_ALPHA";
500
    }
501
}
502
 
503
static cairo_status_t
504
_emit_surface (cairo_script_surface_t *surface)
505
{
506
    cairo_script_context_t *ctx = to_context (surface);
507
 
508
    _cairo_output_stream_printf (ctx->stream,
509
				 "<< /content //%s",
510
				 _content_to_string (surface->base.content));
511
    if (surface->width != -1 && surface->height != -1) {
512
	_cairo_output_stream_printf (ctx->stream,
513
				     " /width %f /height %f",
514
				     surface->width,
515
				     surface->height);
516
    }
517
 
518
    if (surface->base.x_fallback_resolution !=
519
	CAIRO_SURFACE_FALLBACK_RESOLUTION_DEFAULT ||
520
	surface->base.y_fallback_resolution !=
521
	CAIRO_SURFACE_FALLBACK_RESOLUTION_DEFAULT)
522
    {
523
	_cairo_output_stream_printf (ctx->stream,
524
				     " /fallback-resolution [%f %f]",
525
				     surface->base.x_fallback_resolution,
526
				     surface->base.y_fallback_resolution);
527
    }
528
 
529
    if (surface->base.device_transform.x0 != 0. ||
530
	surface->base.device_transform.y0 != 0.)
531
    {
532
	/* XXX device offset is encoded into the pattern matrices etc. */
533
	if (0) {
534
	_cairo_output_stream_printf (ctx->stream,
535
				     " /device-offset [%f %f]",
536
				     surface->base.device_transform.x0,
537
				     surface->base.device_transform.y0);
538
	}
539
    }
540
 
541
    _cairo_output_stream_puts (ctx->stream, " >> surface context\n");
542
    surface->emitted = TRUE;
543
    return CAIRO_STATUS_SUCCESS;
544
}
545
 
546
static cairo_status_t
547
_emit_context (cairo_script_surface_t *surface)
548
{
549
    cairo_script_context_t *ctx = to_context (surface);
550
 
551
    if (target_is_active (surface))
552
	return CAIRO_STATUS_SUCCESS;
553
 
554
    while (! cairo_list_is_empty (&ctx->operands)) {
555
	operand_t *op;
556
	cairo_script_surface_t *old;
557
 
558
	op = cairo_list_first_entry (&ctx->operands,
559
				     operand_t,
560
				     link);
561
	if (op->type == DEFERRED)
562
	    break;
563
 
564
	old = cairo_container_of (op, cairo_script_surface_t, operand);
565
	if (old == surface)
566
	    break;
567
	if (old->active)
568
	    break;
569
 
570
	if (! old->defined) {
571
	    assert (old->emitted);
572
	    _cairo_output_stream_printf (ctx->stream,
573
					 "/target get /s%u exch def pop\n",
574
					 old->base.unique_id);
575
	    old->defined = TRUE;
576
	} else {
577
	    _cairo_output_stream_puts (ctx->stream, "pop\n");
578
	}
579
 
580
	cairo_list_del (&old->operand.link);
581
    }
582
 
583
    if (target_is_active (surface))
584
	return CAIRO_STATUS_SUCCESS;
585
 
586
    if (! surface->emitted) {
587
	cairo_status_t status;
588
 
589
	status = _emit_surface (surface);
590
	if (unlikely (status))
591
	    return status;
592
    } else if (cairo_list_is_empty (&surface->operand.link)) {
593
	assert (surface->defined);
594
	_cairo_output_stream_printf (ctx->stream,
595
				     "s%u context\n",
596
				     surface->base.unique_id);
597
	_cairo_script_implicit_context_reset (&surface->cr);
598
	_cairo_surface_clipper_reset (&surface->clipper);
599
    } else {
600
	int depth = target_depth (surface);
601
	if (depth == 1) {
602
	    _cairo_output_stream_puts (ctx->stream, "exch\n");
603
	} else {
604
	    _cairo_output_stream_printf (ctx->stream,
605
					 "%d -1 roll\n",
606
					 depth);
607
	}
608
    }
609
    target_push (surface);
610
 
611
    return CAIRO_STATUS_SUCCESS;
612
}
613
 
614
static cairo_status_t
615
_emit_operator (cairo_script_surface_t *surface,
616
		cairo_operator_t op)
617
{
618
    assert (target_is_active (surface));
619
 
620
    if (surface->cr.current_operator == op)
621
	return CAIRO_STATUS_SUCCESS;
622
 
623
    surface->cr.current_operator = op;
624
 
625
    _cairo_output_stream_printf (to_context (surface)->stream,
626
				 "//%s set-operator\n",
627
				 _operator_to_string (op));
628
    return CAIRO_STATUS_SUCCESS;
629
}
630
 
631
static cairo_status_t
632
_emit_fill_rule (cairo_script_surface_t *surface,
633
		 cairo_fill_rule_t fill_rule)
634
{
635
    assert (target_is_active (surface));
636
 
637
    if (surface->cr.current_fill_rule == fill_rule)
638
	return CAIRO_STATUS_SUCCESS;
639
 
640
    surface->cr.current_fill_rule = fill_rule;
641
 
642
    _cairo_output_stream_printf (to_context (surface)->stream,
643
				 "//%s set-fill-rule\n",
644
				 _fill_rule_to_string (fill_rule));
645
    return CAIRO_STATUS_SUCCESS;
646
}
647
 
648
static cairo_status_t
649
_emit_tolerance (cairo_script_surface_t *surface,
650
		 double tolerance,
651
		 cairo_bool_t force)
652
{
653
    assert (target_is_active (surface));
654
 
655
    if ((! force ||
656
	 fabs (tolerance - CAIRO_GSTATE_TOLERANCE_DEFAULT) < 1e-5) &&
657
	surface->cr.current_tolerance == tolerance)
658
    {
659
	return CAIRO_STATUS_SUCCESS;
660
    }
661
 
662
    surface->cr.current_tolerance = tolerance;
663
 
664
    _cairo_output_stream_printf (to_context (surface)->stream,
665
				 "%f set-tolerance\n",
666
				 tolerance);
667
    return CAIRO_STATUS_SUCCESS;
668
}
669
 
670
static cairo_status_t
671
_emit_antialias (cairo_script_surface_t *surface,
672
		 cairo_antialias_t antialias)
673
{
674
    assert (target_is_active (surface));
675
 
676
    if (surface->cr.current_antialias == antialias)
677
	return CAIRO_STATUS_SUCCESS;
678
 
679
    surface->cr.current_antialias = antialias;
680
 
681
    _cairo_output_stream_printf (to_context (surface)->stream,
682
				 "//%s set-antialias\n",
683
				 _antialias_to_string (antialias));
684
 
685
    return CAIRO_STATUS_SUCCESS;
686
}
687
 
688
static cairo_status_t
689
_emit_line_width (cairo_script_surface_t *surface,
690
		 double line_width,
691
		 cairo_bool_t force)
692
{
693
    assert (target_is_active (surface));
694
 
695
    if ((! force ||
696
	 fabs (line_width - CAIRO_GSTATE_LINE_WIDTH_DEFAULT) < 1e-5) &&
697
	surface->cr.current_style.line_width == line_width)
698
    {
699
	return CAIRO_STATUS_SUCCESS;
700
    }
701
 
702
    surface->cr.current_style.line_width = line_width;
703
 
704
    _cairo_output_stream_printf (to_context (surface)->stream,
705
				 "%f set-line-width\n",
706
				 line_width);
707
    return CAIRO_STATUS_SUCCESS;
708
}
709
 
710
static cairo_status_t
711
_emit_line_cap (cairo_script_surface_t *surface,
712
		cairo_line_cap_t line_cap)
713
{
714
    assert (target_is_active (surface));
715
 
716
    if (surface->cr.current_style.line_cap == line_cap)
717
	return CAIRO_STATUS_SUCCESS;
718
 
719
    surface->cr.current_style.line_cap = line_cap;
720
 
721
    _cairo_output_stream_printf (to_context (surface)->stream,
722
				 "//%s set-line-cap\n",
723
				 _line_cap_to_string (line_cap));
724
    return CAIRO_STATUS_SUCCESS;
725
}
726
 
727
static cairo_status_t
728
_emit_line_join (cairo_script_surface_t *surface,
729
		 cairo_line_join_t line_join)
730
{
731
    assert (target_is_active (surface));
732
 
733
    if (surface->cr.current_style.line_join == line_join)
734
	return CAIRO_STATUS_SUCCESS;
735
 
736
    surface->cr.current_style.line_join = line_join;
737
 
738
    _cairo_output_stream_printf (to_context (surface)->stream,
739
				 "//%s set-line-join\n",
740
				 _line_join_to_string (line_join));
741
    return CAIRO_STATUS_SUCCESS;
742
}
743
 
744
static cairo_status_t
745
_emit_miter_limit (cairo_script_surface_t *surface,
746
		   double miter_limit,
747
		   cairo_bool_t force)
748
{
749
    assert (target_is_active (surface));
750
 
751
    if ((! force ||
752
	 fabs (miter_limit - CAIRO_GSTATE_MITER_LIMIT_DEFAULT) < 1e-5) &&
753
	surface->cr.current_style.miter_limit == miter_limit)
754
    {
755
	return CAIRO_STATUS_SUCCESS;
756
    }
757
 
758
    surface->cr.current_style.miter_limit = miter_limit;
759
 
760
    _cairo_output_stream_printf (to_context (surface)->stream,
761
				 "%f set-miter-limit\n",
762
				 miter_limit);
763
    return CAIRO_STATUS_SUCCESS;
764
}
765
 
766
static cairo_bool_t
767
_dashes_equal (const double *a, const double *b, int num_dashes)
768
{
769
    while (num_dashes--) {
770
	if (fabs (*a - *b) > 1e-5)
771
	    return FALSE;
772
	a++, b++;
773
    }
774
 
775
    return TRUE;
776
}
777
 
778
static cairo_status_t
779
_emit_dash (cairo_script_surface_t *surface,
780
	    const double *dash,
781
	    unsigned int num_dashes,
782
	    double offset,
783
	    cairo_bool_t force)
784
{
785
    unsigned int n;
786
 
787
    assert (target_is_active (surface));
788
 
789
    if (force &&
790
	num_dashes == 0 &&
791
	surface->cr.current_style.num_dashes == 0)
792
    {
793
	return CAIRO_STATUS_SUCCESS;
794
    }
795
 
796
    if (! force &&
797
	(surface->cr.current_style.num_dashes == num_dashes &&
798
	 (num_dashes == 0 ||
799
	  (fabs (surface->cr.current_style.dash_offset - offset) < 1e-5 &&
800
	   _dashes_equal (surface->cr.current_style.dash, dash, num_dashes)))))
801
    {
802
	return CAIRO_STATUS_SUCCESS;
803
    }
804
 
805
 
806
    if (num_dashes) {
807
	surface->cr.current_style.dash = _cairo_realloc_ab
808
	    (surface->cr.current_style.dash, num_dashes, sizeof (double));
809
	if (unlikely (surface->cr.current_style.dash == NULL))
810
	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
811
 
812
	memcpy (surface->cr.current_style.dash, dash,
813
		sizeof (double) * num_dashes);
814
    } else {
815
	free (surface->cr.current_style.dash);
816
	surface->cr.current_style.dash = NULL;
817
    }
818
 
819
    surface->cr.current_style.num_dashes = num_dashes;
820
    surface->cr.current_style.dash_offset = offset;
821
 
822
    _cairo_output_stream_puts (to_context (surface)->stream, "[");
823
    for (n = 0; n < num_dashes; n++) {
824
	_cairo_output_stream_printf (to_context (surface)->stream, "%f", dash[n]);
825
	if (n < num_dashes-1)
826
	    _cairo_output_stream_puts (to_context (surface)->stream, " ");
827
    }
828
    _cairo_output_stream_printf (to_context (surface)->stream,
829
				 "] %f set-dash\n",
830
				 offset);
831
 
832
    return CAIRO_STATUS_SUCCESS;
833
}
834
 
835
static cairo_status_t
836
_emit_stroke_style (cairo_script_surface_t *surface,
837
		    const cairo_stroke_style_t *style,
838
		    cairo_bool_t force)
839
{
840
    cairo_status_t status;
841
 
842
    assert (target_is_active (surface));
843
 
844
    status = _emit_line_width (surface, style->line_width, force);
845
    if (unlikely (status))
846
	return status;
847
 
848
    status = _emit_line_cap (surface, style->line_cap);
849
    if (unlikely (status))
850
	return status;
851
 
852
    status = _emit_line_join (surface, style->line_join);
853
    if (unlikely (status))
854
	return status;
855
 
856
    status = _emit_miter_limit (surface, style->miter_limit, force);
857
    if (unlikely (status))
858
	return status;
859
 
860
    status = _emit_dash (surface,
861
			 style->dash, style->num_dashes, style->dash_offset,
862
			 force);
863
    if (unlikely (status))
864
	return status;
865
 
866
    return CAIRO_STATUS_SUCCESS;
867
}
868
 
869
static const char *
870
_format_to_string (cairo_format_t format)
871
{
872
    switch (format) {
873
    case CAIRO_FORMAT_ARGB32:  return "ARGB32";
874
    case CAIRO_FORMAT_RGB30:   return "RGB30";
875
    case CAIRO_FORMAT_RGB24:   return "RGB24";
876
    case CAIRO_FORMAT_RGB16_565: return "RGB16_565";
877
    case CAIRO_FORMAT_A8:      return "A8";
878
    case CAIRO_FORMAT_A1:      return "A1";
879
    case CAIRO_FORMAT_INVALID: return "INVALID";
880
    }
881
    ASSERT_NOT_REACHED;
882
    return "INVALID";
883
}
884
 
885
static cairo_status_t
886
_emit_solid_pattern (cairo_script_surface_t *surface,
887
		     const cairo_pattern_t *pattern)
888
{
889
    cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *) pattern;
890
    cairo_script_context_t *ctx = to_context (surface);
891
 
892
    if (! CAIRO_COLOR_IS_OPAQUE (&solid->color))
893
    {
894
	if (! (surface->base.content & CAIRO_CONTENT_COLOR) ||
895
	    ((solid->color.red_short   == 0 || solid->color.red_short   == 0xffff) &&
896
	     (solid->color.green_short == 0 || solid->color.green_short == 0xffff) &&
897
	     (solid->color.blue_short  == 0 || solid->color.blue_short  == 0xffff) ))
898
	{
899
	    _cairo_output_stream_printf (ctx->stream,
900
					 "%f a",
901
					 solid->color.alpha);
902
	}
903
	else
904
	{
905
	    _cairo_output_stream_printf (ctx->stream,
906
					 "%f %f %f %f rgba",
907
					 solid->color.red,
908
					 solid->color.green,
909
					 solid->color.blue,
910
					 solid->color.alpha);
911
	}
912
    }
913
    else
914
    {
915
	if (solid->color.red_short == solid->color.green_short &&
916
	    solid->color.red_short == solid->color.blue_short)
917
	{
918
	    _cairo_output_stream_printf (ctx->stream,
919
					 "%f g",
920
					 solid->color.red);
921
	}
922
	else
923
	{
924
	    _cairo_output_stream_printf (ctx->stream,
925
					 "%f %f %f rgb",
926
					 solid->color.red,
927
					 solid->color.green,
928
					 solid->color.blue);
929
	}
930
    }
931
 
932
    return CAIRO_STATUS_SUCCESS;
933
}
934
 
935
 
936
static cairo_status_t
937
_emit_gradient_color_stops (cairo_gradient_pattern_t *gradient,
938
			    cairo_output_stream_t *output)
939
{
940
    unsigned int n;
941
 
942
    for (n = 0; n < gradient->n_stops; n++) {
943
	_cairo_output_stream_printf (output,
944
				     "\n  %f %f %f %f %f add-color-stop",
945
				     gradient->stops[n].offset,
946
				     gradient->stops[n].color.red,
947
				     gradient->stops[n].color.green,
948
				     gradient->stops[n].color.blue,
949
				     gradient->stops[n].color.alpha);
950
    }
951
 
952
    return CAIRO_STATUS_SUCCESS;
953
}
954
 
955
static cairo_status_t
956
_emit_linear_pattern (cairo_script_surface_t *surface,
957
		      const cairo_pattern_t *pattern)
958
{
959
    cairo_script_context_t *ctx = to_context (surface);
960
    cairo_linear_pattern_t *linear;
961
 
962
    linear = (cairo_linear_pattern_t *) pattern;
963
 
964
    _cairo_output_stream_printf (ctx->stream,
965
				 "%f %f %f %f linear",
966
				 linear->pd1.x, linear->pd1.y,
967
				 linear->pd2.x, linear->pd2.y);
968
    return _emit_gradient_color_stops (&linear->base, ctx->stream);
969
}
970
 
971
static cairo_status_t
972
_emit_radial_pattern (cairo_script_surface_t *surface,
973
		      const cairo_pattern_t *pattern)
974
{
975
    cairo_script_context_t *ctx = to_context (surface);
976
    cairo_radial_pattern_t *radial;
977
 
978
    radial = (cairo_radial_pattern_t *) pattern;
979
 
980
    _cairo_output_stream_printf (ctx->stream,
981
				 "%f %f %f %f %f %f radial",
982
				 radial->cd1.center.x,
983
				 radial->cd1.center.y,
984
				 radial->cd1.radius,
985
				 radial->cd2.center.x,
986
				 radial->cd2.center.y,
987
				 radial->cd2.radius);
988
    return _emit_gradient_color_stops (&radial->base, ctx->stream);
989
}
990
 
991
static cairo_status_t
992
_emit_mesh_pattern (cairo_script_surface_t *surface,
993
		    const cairo_pattern_t *pattern)
994
{
995
    cairo_script_context_t *ctx = to_context (surface);
996
    cairo_pattern_t *mesh;
997
    cairo_status_t status;
998
    unsigned int i, n;
999
 
1000
    mesh = (cairo_pattern_t *) pattern;
1001
    status = cairo_mesh_pattern_get_patch_count (mesh, &n);
1002
    if (unlikely (status))
1003
	return status;
1004
 
1005
    _cairo_output_stream_printf (ctx->stream, "mesh");
1006
    for (i = 0; i < n; i++) {
1007
	cairo_path_t *path;
1008
	cairo_path_data_t *data;
1009
	int j;
1010
 
1011
	_cairo_output_stream_printf (ctx->stream, "\n  begin-patch");
1012
 
1013
	path = cairo_mesh_pattern_get_path (mesh, i);
1014
	if (unlikely (path->status))
1015
	    return path->status;
1016
 
1017
	for (j = 0; j < path->num_data; j+=data[0].header.length) {
1018
	    data = &path->data[j];
1019
	    switch (data->header.type) {
1020
	    case CAIRO_PATH_MOVE_TO:
1021
		_cairo_output_stream_printf (ctx->stream,
1022
					     "\n  %f %f m",
1023
					     data[1].point.x, data[1].point.y);
1024
		break;
1025
	    case CAIRO_PATH_LINE_TO:
1026
		_cairo_output_stream_printf (ctx->stream,
1027
					     "\n  %f %f l",
1028
					     data[1].point.x, data[1].point.y);
1029
		break;
1030
	    case CAIRO_PATH_CURVE_TO:
1031
		_cairo_output_stream_printf (ctx->stream,
1032
					     "\n  %f %f %f %f %f %f c",
1033
					     data[1].point.x, data[1].point.y,
1034
					     data[2].point.x, data[2].point.y,
1035
					     data[3].point.x, data[3].point.y);
1036
		break;
1037
	    case CAIRO_PATH_CLOSE_PATH:
1038
		break;
1039
	    }
1040
	}
1041
	cairo_path_destroy (path);
1042
 
1043
	for (j = 0; j < 4; j++) {
1044
	    double x, y;
1045
 
1046
	    status = cairo_mesh_pattern_get_control_point (mesh, i, j, &x, &y);
1047
	    if (unlikely (status))
1048
		return status;
1049
	    _cairo_output_stream_printf (ctx->stream,
1050
					 "\n  %d %f %f set-control-point",
1051
					 j, x, y);
1052
	}
1053
 
1054
	for (j = 0; j < 4; j++) {
1055
	    double r, g, b, a;
1056
 
1057
	    status = cairo_mesh_pattern_get_corner_color_rgba (mesh, i, j, &r, &g, &b, &a);
1058
	    if (unlikely (status))
1059
		return status;
1060
 
1061
	    _cairo_output_stream_printf (ctx->stream,
1062
					 "\n  %d %f %f %f %f set-corner-color",
1063
					 j, r, g, b, a);
1064
	}
1065
 
1066
	_cairo_output_stream_printf (ctx->stream, "\n  end-patch");
1067
    }
1068
 
1069
    return CAIRO_STATUS_SUCCESS;
1070
}
1071
 
1072
struct script_snapshot {
1073
    cairo_surface_t base;
1074
};
1075
 
1076
static cairo_status_t
1077
script_snapshot_finish (void *abstract_surface)
1078
{
1079
    return CAIRO_STATUS_SUCCESS;
1080
}
1081
 
1082
static const cairo_surface_backend_t script_snapshot_backend = {
1083
    CAIRO_SURFACE_TYPE_SCRIPT,
1084
    script_snapshot_finish,
1085
};
1086
 
1087
static void
1088
detach_snapshot (cairo_surface_t *abstract_surface)
1089
{
1090
    cairo_script_surface_t *surface = (cairo_script_surface_t *)abstract_surface;
1091
    cairo_script_context_t *ctx = to_context (surface);
1092
 
1093
    _cairo_output_stream_printf (ctx->stream,
1094
				 "/s%d undef\n",
1095
				 surface->base.unique_id);
1096
}
1097
 
1098
static void
1099
attach_snapshot (cairo_script_context_t *ctx,
1100
		 cairo_surface_t *source)
1101
{
1102
    struct script_snapshot *surface;
1103
 
1104
    if (! ctx->attach_snapshots)
1105
	return;
1106
 
1107
    surface = malloc (sizeof (*surface));
1108
    if (unlikely (surface == NULL))
1109
	return;
1110
 
1111
    _cairo_surface_init (&surface->base,
1112
			 &script_snapshot_backend,
1113
			 &ctx->base,
1114
			 source->content);
1115
 
1116
    _cairo_output_stream_printf (ctx->stream,
1117
				 "dup /s%d exch def ",
1118
				 surface->base.unique_id);
1119
 
1120
    _cairo_surface_attach_snapshot (source, &surface->base, detach_snapshot);
1121
    cairo_surface_destroy (&surface->base);
1122
}
1123
 
1124
static cairo_status_t
1125
_emit_recording_surface_pattern (cairo_script_surface_t *surface,
1126
				 cairo_recording_surface_t *source)
1127
{
1128
    cairo_script_implicit_context_t old_cr;
1129
    cairo_script_context_t *ctx = to_context (surface);
1130
    cairo_script_surface_t *similar;
1131
    cairo_surface_t *snapshot;
1132
    cairo_rectangle_t r, *extents;
1133
    cairo_status_t status;
1134
 
1135
    snapshot = _cairo_surface_has_snapshot (&source->base, &script_snapshot_backend);
1136
    if (snapshot) {
1137
	_cairo_output_stream_printf (ctx->stream, "s%d", snapshot->unique_id);
1138
	return CAIRO_INT_STATUS_SUCCESS;
1139
    }
1140
 
1141
    extents = NULL;
1142
    if (_cairo_recording_surface_get_bounds (&source->base, &r))
1143
	extents = &r;
1144
 
1145
    similar = _cairo_script_surface_create_internal (ctx,
1146
						     source->base.content,
1147
						     extents,
1148
						     NULL);
1149
    if (unlikely (similar->base.status))
1150
	return similar->base.status;
1151
 
1152
    similar->base.is_clear = TRUE;
1153
 
1154
    _cairo_output_stream_printf (ctx->stream, "//%s ",
1155
				 _content_to_string (source->base.content));
1156
    if (extents) {
1157
	_cairo_output_stream_printf (ctx->stream, "[%f %f %f %f]",
1158
				     extents->x, extents->y,
1159
				     extents->width, extents->height);
1160
    } else
1161
	_cairo_output_stream_puts (ctx->stream, "[]");
1162
    _cairo_output_stream_puts (ctx->stream, " record\n");
1163
 
1164
    attach_snapshot (ctx, &source->base);
1165
 
1166
    _cairo_output_stream_puts (ctx->stream, "dup context\n");
1167
 
1168
    target_push (similar);
1169
    similar->emitted = TRUE;
1170
 
1171
 
1172
    old_cr = surface->cr;
1173
    _cairo_script_implicit_context_init (&surface->cr);
1174
    status = _cairo_recording_surface_replay (&source->base, &similar->base);
1175
    surface->cr = old_cr;
1176
 
1177
    if (unlikely (status)) {
1178
	cairo_surface_destroy (&similar->base);
1179
	return status;
1180
    }
1181
 
1182
    cairo_list_del (&similar->operand.link);
1183
    assert (target_is_active (surface));
1184
 
1185
    _cairo_output_stream_puts (ctx->stream, "pop ");
1186
    cairo_surface_destroy (&similar->base);
1187
 
1188
    return CAIRO_STATUS_SUCCESS;
1189
}
1190
 
1191
static cairo_status_t
1192
_emit_script_surface_pattern (cairo_script_surface_t *surface,
1193
			      cairo_script_surface_t *source)
1194
{
1195
    _get_target (source);
1196
 
1197
    return CAIRO_STATUS_SUCCESS;
1198
}
1199
 
1200
static cairo_status_t
1201
_write_image_surface (cairo_output_stream_t *output,
1202
		      const cairo_image_surface_t *image)
1203
{
1204
    int stride, row, width;
1205
    uint8_t row_stack[CAIRO_STACK_BUFFER_SIZE];
1206
    uint8_t *rowdata;
1207
    uint8_t *data;
1208
 
1209
    stride = image->stride;
1210
    width = image->width;
1211
    data = image->data;
1212
#if WORDS_BIGENDIAN
1213
    switch (image->format) {
1214
    case CAIRO_FORMAT_A1:
1215
	for (row = image->height; row--; ) {
1216
	    _cairo_output_stream_write (output, data, (width+7)/8);
1217
	    data += stride;
1218
	}
1219
	break;
1220
    case CAIRO_FORMAT_A8:
1221
	for (row = image->height; row--; ) {
1222
	    _cairo_output_stream_write (output, data, width);
1223
	    data += stride;
1224
	}
1225
	break;
1226
    case CAIRO_FORMAT_RGB16_565:
1227
	for (row = image->height; row--; ) {
1228
	    _cairo_output_stream_write (output, data, 2*width);
1229
	    data += stride;
1230
	}
1231
	break;
1232
    case CAIRO_FORMAT_RGB24:
1233
	for (row = image->height; row--; ) {
1234
	    int col;
1235
	    rowdata = data;
1236
	    for (col = width; col--; ) {
1237
		_cairo_output_stream_write (output, rowdata, 3);
1238
		rowdata+=4;
1239
	    }
1240
	    data += stride;
1241
	}
1242
	break;
1243
    case CAIRO_FORMAT_ARGB32:
1244
	for (row = image->height; row--; ) {
1245
	    _cairo_output_stream_write (output, data, 4*width);
1246
	    data += stride;
1247
	}
1248
	break;
1249
    case CAIRO_FORMAT_INVALID:
1250
    default:
1251
	ASSERT_NOT_REACHED;
1252
	break;
1253
    }
1254
#else
1255
    if (stride > ARRAY_LENGTH (row_stack)) {
1256
	rowdata = malloc (stride);
1257
	if (unlikely (rowdata == NULL))
1258
	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1259
    } else
1260
	rowdata = row_stack;
1261
 
1262
    switch (image->format) {
1263
    case CAIRO_FORMAT_A1:
1264
	for (row = image->height; row--; ) {
1265
	    int col;
1266
	    for (col = 0; col < (width + 7)/8; col++)
1267
		rowdata[col] = CAIRO_BITSWAP8 (data[col]);
1268
	    _cairo_output_stream_write (output, rowdata, (width+7)/8);
1269
	    data += stride;
1270
	}
1271
	break;
1272
    case CAIRO_FORMAT_A8:
1273
	for (row = image->height; row--; ) {
1274
	    _cairo_output_stream_write (output, data, width);
1275
	    data += stride;
1276
	}
1277
	break;
1278
    case CAIRO_FORMAT_RGB16_565:
1279
	for (row = image->height; row--; ) {
1280
	    uint16_t *src = (uint16_t *) data;
1281
	    uint16_t *dst = (uint16_t *) rowdata;
1282
	    int col;
1283
	    for (col = 0; col < width; col++)
1284
		dst[col] = bswap_16 (src[col]);
1285
	    _cairo_output_stream_write (output, rowdata, 2*width);
1286
	    data += stride;
1287
	}
1288
	break;
1289
    case CAIRO_FORMAT_RGB24:
1290
	for (row = image->height; row--; ) {
1291
	    uint8_t *src = data;
1292
	    int col;
1293
	    for (col = 0; col < width; col++) {
1294
		rowdata[3*col+2] = *src++;
1295
		rowdata[3*col+1] = *src++;
1296
		rowdata[3*col+0] = *src++;
1297
		src++;
1298
	    }
1299
	    _cairo_output_stream_write (output, rowdata, 3*width);
1300
	    data += stride;
1301
	}
1302
	break;
1303
    case CAIRO_FORMAT_RGB30:
1304
    case CAIRO_FORMAT_ARGB32:
1305
	for (row = image->height; row--; ) {
1306
	    uint32_t *src = (uint32_t *) data;
1307
	    uint32_t *dst = (uint32_t *) rowdata;
1308
	    int col;
1309
	    for (col = 0; col < width; col++)
1310
		dst[col] = bswap_32 (src[col]);
1311
	    _cairo_output_stream_write (output, rowdata, 4*width);
1312
	    data += stride;
1313
	}
1314
	break;
1315
    case CAIRO_FORMAT_INVALID:
1316
    default:
1317
	ASSERT_NOT_REACHED;
1318
	break;
1319
    }
1320
    if (rowdata != row_stack)
1321
	free (rowdata);
1322
#endif
1323
 
1324
    return CAIRO_STATUS_SUCCESS;
1325
}
1326
 
1327
static cairo_int_status_t
1328
_emit_png_surface (cairo_script_surface_t *surface,
1329
		   cairo_image_surface_t *image)
1330
{
1331
    cairo_script_context_t *ctx = to_context (surface);
1332
    cairo_output_stream_t *base85_stream;
1333
    cairo_status_t status;
1334
    const uint8_t *mime_data;
1335
    unsigned long mime_data_length;
1336
 
1337
    cairo_surface_get_mime_data (&image->base, CAIRO_MIME_TYPE_PNG,
1338
				 &mime_data, &mime_data_length);
1339
    if (mime_data == NULL)
1340
	return CAIRO_INT_STATUS_UNSUPPORTED;
1341
 
1342
    _cairo_output_stream_printf (ctx->stream,
1343
				 "<< "
1344
				 "/width %d "
1345
				 "/height %d "
1346
				 "/format //%s "
1347
				 "/mime-type (image/png) "
1348
				 "/source <~",
1349
				 image->width, image->height,
1350
				 _format_to_string (image->format));
1351
 
1352
    base85_stream = _cairo_base85_stream_create (ctx->stream);
1353
    _cairo_output_stream_write (base85_stream, mime_data, mime_data_length);
1354
    status = _cairo_output_stream_destroy (base85_stream);
1355
    if (unlikely (status))
1356
	return status;
1357
 
1358
    _cairo_output_stream_puts (ctx->stream, "~> >> image ");
1359
    return CAIRO_STATUS_SUCCESS;
1360
}
1361
 
1362
static cairo_int_status_t
1363
_emit_image_surface (cairo_script_surface_t *surface,
1364
		     cairo_image_surface_t *image)
1365
{
1366
    cairo_script_context_t *ctx = to_context (surface);
1367
    cairo_output_stream_t *base85_stream;
1368
    cairo_output_stream_t *zlib_stream;
1369
    cairo_int_status_t status, status2;
1370
    cairo_surface_t *snapshot;
1371
    const uint8_t *mime_data;
1372
    unsigned long mime_data_length;
1373
 
1374
    snapshot = _cairo_surface_has_snapshot (&image->base,
1375
					    &script_snapshot_backend);
1376
    if (snapshot) {
1377
	_cairo_output_stream_printf (ctx->stream, "s%u ", snapshot->unique_id);
1378
	return CAIRO_INT_STATUS_SUCCESS;
1379
    }
1380
 
1381
    status = _emit_png_surface (surface, image);
1382
    if (_cairo_int_status_is_error (status)) {
1383
	return status;
1384
    } else if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
1385
	cairo_image_surface_t *clone;
1386
	uint32_t len;
1387
 
1388
	if (image->format == CAIRO_FORMAT_INVALID) {
1389
	    clone = _cairo_image_surface_coerce (image);
1390
	} else {
1391
	    clone = (cairo_image_surface_t *)
1392
		cairo_surface_reference (&image->base);
1393
	}
1394
 
1395
	_cairo_output_stream_printf (ctx->stream,
1396
				     "<< "
1397
				     "/width %d "
1398
				     "/height %d "
1399
				     "/format //%s "
1400
				     "/source ",
1401
				     clone->width, clone->height,
1402
				     _format_to_string (clone->format));
1403
 
1404
	switch (clone->format) {
1405
	case CAIRO_FORMAT_A1:
1406
	    len = (clone->width + 7)/8;
1407
	    break;
1408
	case CAIRO_FORMAT_A8:
1409
	    len = clone->width;
1410
	    break;
1411
	case CAIRO_FORMAT_RGB16_565:
1412
	    len = clone->width * 2;
1413
	    break;
1414
	case CAIRO_FORMAT_RGB24:
1415
	    len = clone->width * 3;
1416
	    break;
1417
	case CAIRO_FORMAT_RGB30:
1418
	case CAIRO_FORMAT_ARGB32:
1419
	    len = clone->width * 4;
1420
	    break;
1421
	case CAIRO_FORMAT_INVALID:
1422
	default:
1423
	    ASSERT_NOT_REACHED;
1424
	    len = 0;
1425
	    break;
1426
	}
1427
	len *= clone->height;
1428
 
1429
	if (len > 24) {
1430
	    _cairo_output_stream_puts (ctx->stream, "<|");
1431
 
1432
	    base85_stream = _cairo_base85_stream_create (ctx->stream);
1433
 
1434
	    len = to_be32 (len);
1435
	    _cairo_output_stream_write (base85_stream, &len, sizeof (len));
1436
 
1437
	    zlib_stream = _cairo_deflate_stream_create (base85_stream);
1438
	    status = _write_image_surface (zlib_stream, clone);
1439
 
1440
	    status2 = _cairo_output_stream_destroy (zlib_stream);
1441
	    if (status == CAIRO_INT_STATUS_SUCCESS)
1442
		status = status2;
1443
	    status2 = _cairo_output_stream_destroy (base85_stream);
1444
	    if (status == CAIRO_INT_STATUS_SUCCESS)
1445
		status = status2;
1446
	    if (unlikely (status))
1447
		return status;
1448
	} else {
1449
	    _cairo_output_stream_puts (ctx->stream, "<~");
1450
 
1451
	    base85_stream = _cairo_base85_stream_create (ctx->stream);
1452
	    status = _write_image_surface (base85_stream, clone);
1453
	    status2 = _cairo_output_stream_destroy (base85_stream);
1454
	    if (status == CAIRO_INT_STATUS_SUCCESS)
1455
		status = status2;
1456
	    if (unlikely (status))
1457
		return status;
1458
	}
1459
	_cairo_output_stream_puts (ctx->stream, "~> >> image ");
1460
 
1461
	cairo_surface_destroy (&clone->base);
1462
    }
1463
 
1464
    cairo_surface_get_mime_data (&image->base, CAIRO_MIME_TYPE_JPEG,
1465
				 &mime_data, &mime_data_length);
1466
    if (mime_data != NULL) {
1467
	_cairo_output_stream_printf (ctx->stream,
1468
				     "\n  (%s) <~",
1469
				     CAIRO_MIME_TYPE_JPEG);
1470
 
1471
	base85_stream = _cairo_base85_stream_create (ctx->stream);
1472
	_cairo_output_stream_write (base85_stream, mime_data, mime_data_length);
1473
	status = _cairo_output_stream_destroy (base85_stream);
1474
	if (unlikely (status))
1475
	    return status;
1476
 
1477
	_cairo_output_stream_puts (ctx->stream, "~> set-mime-data\n");
1478
    }
1479
 
1480
    cairo_surface_get_mime_data (&image->base, CAIRO_MIME_TYPE_JP2,
1481
				 &mime_data, &mime_data_length);
1482
    if (mime_data != NULL) {
1483
	_cairo_output_stream_printf (ctx->stream,
1484
				     "\n  (%s) <~",
1485
				     CAIRO_MIME_TYPE_JP2);
1486
 
1487
	base85_stream = _cairo_base85_stream_create (ctx->stream);
1488
	_cairo_output_stream_write (base85_stream, mime_data, mime_data_length);
1489
	status = _cairo_output_stream_destroy (base85_stream);
1490
	if (unlikely (status))
1491
	    return status;
1492
 
1493
	_cairo_output_stream_puts (ctx->stream, "~> set-mime-data\n");
1494
    }
1495
 
1496
    return CAIRO_INT_STATUS_SUCCESS;
1497
}
1498
 
1499
static cairo_int_status_t
1500
_emit_image_surface_pattern (cairo_script_surface_t *surface,
1501
			     cairo_surface_t *source)
1502
{
1503
    cairo_image_surface_t *image;
1504
    cairo_status_t status;
1505
    void *extra;
1506
 
1507
    status = _cairo_surface_acquire_source_image (source, &image, &extra);
1508
    if (likely (status == CAIRO_STATUS_SUCCESS)) {
1509
	status = _emit_image_surface (surface, image);
1510
	_cairo_surface_release_source_image (source, image, extra);
1511
    }
1512
 
1513
    return status;
1514
}
1515
 
1516
static cairo_int_status_t
1517
_emit_subsurface_pattern (cairo_script_surface_t *surface,
1518
			  cairo_surface_subsurface_t *sub)
1519
{
1520
    cairo_surface_t *source = sub->target;
1521
    cairo_int_status_t status;
1522
 
1523
    switch ((int) source->backend->type) {
1524
    case CAIRO_SURFACE_TYPE_RECORDING:
1525
	status = _emit_recording_surface_pattern (surface, (cairo_recording_surface_t *) source);
1526
	break;
1527
    case CAIRO_SURFACE_TYPE_SCRIPT:
1528
	status = _emit_script_surface_pattern (surface, (cairo_script_surface_t *) source);
1529
	break;
1530
    default:
1531
	status = _emit_image_surface_pattern (surface, source);
1532
	break;
1533
    }
1534
    if (unlikely (status))
1535
	return status;
1536
 
1537
    _cairo_output_stream_printf (to_context (surface)->stream,
1538
				 "%d %d %d %d subsurface ",
1539
				 sub->extents.x,
1540
				 sub->extents.y,
1541
				 sub->extents.width,
1542
				 sub->extents.height);
1543
    return CAIRO_INT_STATUS_SUCCESS;
1544
}
1545
 
1546
static cairo_int_status_t
1547
_emit_surface_pattern (cairo_script_surface_t *surface,
1548
		       const cairo_pattern_t *pattern)
1549
{
1550
    cairo_script_context_t *ctx = to_context (surface);
1551
    cairo_surface_pattern_t *surface_pattern;
1552
    cairo_surface_t *source, *snapshot, *free_me = NULL;
1553
    cairo_surface_t *take_snapshot = NULL;
1554
    cairo_int_status_t status;
1555
 
1556
    surface_pattern = (cairo_surface_pattern_t *) pattern;
1557
    source = surface_pattern->surface;
1558
 
1559
    if (_cairo_surface_is_snapshot (source)) {
1560
	snapshot = _cairo_surface_has_snapshot (source, &script_snapshot_backend);
1561
	if (snapshot) {
1562
	    _cairo_output_stream_printf (ctx->stream,
1563
					 "s%d pattern ",
1564
					 snapshot->unique_id);
1565
	    return CAIRO_INT_STATUS_SUCCESS;
1566
	}
1567
 
1568
	if (_cairo_surface_snapshot_is_reused (source))
1569
	    take_snapshot = source;
1570
 
1571
	free_me = source = _cairo_surface_snapshot_get_target (source);
1572
    }
1573
 
1574
    switch ((int) source->backend->type) {
1575
    case CAIRO_SURFACE_TYPE_RECORDING:
1576
	status = _emit_recording_surface_pattern (surface, (cairo_recording_surface_t *) source);
1577
	break;
1578
    case CAIRO_SURFACE_TYPE_SCRIPT:
1579
	status = _emit_script_surface_pattern (surface, (cairo_script_surface_t *) source);
1580
	break;
1581
    case CAIRO_SURFACE_TYPE_SUBSURFACE:
1582
	status = _emit_subsurface_pattern (surface, (cairo_surface_subsurface_t *) source);
1583
	break;
1584
    default:
1585
	status = _emit_image_surface_pattern (surface, source);
1586
	break;
1587
    }
1588
    cairo_surface_destroy (free_me);
1589
    if (unlikely (status))
1590
	return status;
1591
 
1592
    if (take_snapshot)
1593
	attach_snapshot (ctx, take_snapshot);
1594
 
1595
    _cairo_output_stream_puts (ctx->stream, "pattern");
1596
    return CAIRO_INT_STATUS_SUCCESS;
1597
}
1598
 
1599
static cairo_int_status_t
1600
_emit_raster_pattern (cairo_script_surface_t *surface,
1601
		      const cairo_pattern_t *pattern)
1602
{
1603
    cairo_surface_t *source;
1604
    cairo_int_status_t status;
1605
 
1606
    source = _cairo_raster_source_pattern_acquire (pattern, &surface->base, NULL);
1607
    if (unlikely (source == NULL)) {
1608
	ASSERT_NOT_REACHED;
1609
	return CAIRO_INT_STATUS_UNSUPPORTED;
1610
    }
1611
    if (unlikely (source->status))
1612
	return source->status;
1613
 
1614
    status = _emit_image_surface_pattern (surface, source);
1615
    _cairo_raster_source_pattern_release (pattern, source);
1616
    if (unlikely (status))
1617
	return status;
1618
 
1619
    _cairo_output_stream_puts (to_context(surface)->stream, "pattern");
1620
    return CAIRO_INT_STATUS_SUCCESS;
1621
}
1622
 
1623
static cairo_int_status_t
1624
_emit_pattern (cairo_script_surface_t *surface,
1625
	       const cairo_pattern_t *pattern)
1626
{
1627
    cairo_script_context_t *ctx = to_context (surface);
1628
    cairo_int_status_t status;
1629
    cairo_bool_t is_default_extend;
1630
    cairo_bool_t need_newline = TRUE;
1631
 
1632
    switch (pattern->type) {
1633
    case CAIRO_PATTERN_TYPE_SOLID:
1634
	/* solid colors do not need filter/extend/matrix */
1635
	return _emit_solid_pattern (surface, pattern);
1636
 
1637
    case CAIRO_PATTERN_TYPE_LINEAR:
1638
	status = _emit_linear_pattern (surface, pattern);
1639
	is_default_extend = pattern->extend == CAIRO_EXTEND_GRADIENT_DEFAULT;
1640
	break;
1641
    case CAIRO_PATTERN_TYPE_RADIAL:
1642
	status = _emit_radial_pattern (surface, pattern);
1643
	is_default_extend = pattern->extend == CAIRO_EXTEND_GRADIENT_DEFAULT;
1644
	break;
1645
    case CAIRO_PATTERN_TYPE_MESH:
1646
	status = _emit_mesh_pattern (surface, pattern);
1647
	is_default_extend = TRUE;
1648
	break;
1649
    case CAIRO_PATTERN_TYPE_SURFACE:
1650
	status = _emit_surface_pattern (surface, pattern);
1651
	is_default_extend = pattern->extend == CAIRO_EXTEND_SURFACE_DEFAULT;
1652
	break;
1653
    case CAIRO_PATTERN_TYPE_RASTER_SOURCE:
1654
	status = _emit_raster_pattern (surface, pattern);
1655
	is_default_extend = pattern->extend == CAIRO_EXTEND_SURFACE_DEFAULT;
1656
	break;
1657
 
1658
    default:
1659
	ASSERT_NOT_REACHED;
1660
	status = CAIRO_INT_STATUS_UNSUPPORTED;
1661
    }
1662
    if (unlikely (status))
1663
	return status;
1664
 
1665
    if (! _cairo_matrix_is_identity (&pattern->matrix)) {
1666
	if (need_newline) {
1667
	    _cairo_output_stream_puts (ctx->stream, "\n ");
1668
	    need_newline = FALSE;
1669
	}
1670
 
1671
	_cairo_output_stream_printf (ctx->stream,
1672
				     " [%f %f %f %f %f %f] set-matrix\n ",
1673
				     pattern->matrix.xx, pattern->matrix.yx,
1674
				     pattern->matrix.xy, pattern->matrix.yy,
1675
				     pattern->matrix.x0, pattern->matrix.y0);
1676
    }
1677
 
1678
    /* XXX need to discriminate the user explicitly setting the default */
1679
    if (pattern->filter != CAIRO_FILTER_DEFAULT) {
1680
	if (need_newline) {
1681
	    _cairo_output_stream_puts (ctx->stream, "\n ");
1682
	    need_newline = FALSE;
1683
	}
1684
 
1685
	_cairo_output_stream_printf (ctx->stream,
1686
				     " //%s set-filter\n ",
1687
				     _filter_to_string (pattern->filter));
1688
    }
1689
    if (! is_default_extend ){
1690
	if (need_newline) {
1691
	    _cairo_output_stream_puts (ctx->stream, "\n ");
1692
	    need_newline = FALSE;
1693
	}
1694
 
1695
	_cairo_output_stream_printf (ctx->stream,
1696
				     " //%s set-extend\n ",
1697
				     _extend_to_string (pattern->extend));
1698
    }
1699
 
1700
    if (need_newline)
1701
	_cairo_output_stream_puts (ctx->stream, "\n ");
1702
 
1703
    return CAIRO_INT_STATUS_SUCCESS;
1704
}
1705
 
1706
static cairo_int_status_t
1707
_emit_identity (cairo_script_surface_t *surface,
1708
		cairo_bool_t *matrix_updated)
1709
{
1710
    assert (target_is_active (surface));
1711
 
1712
    if (_cairo_matrix_is_identity (&surface->cr.current_ctm))
1713
	return CAIRO_INT_STATUS_SUCCESS;
1714
 
1715
    _cairo_output_stream_puts (to_context (surface)->stream,
1716
			       "identity set-matrix\n");
1717
 
1718
    *matrix_updated = TRUE;
1719
    cairo_matrix_init_identity (&surface->cr.current_ctm);
1720
 
1721
    return CAIRO_INT_STATUS_SUCCESS;
1722
}
1723
 
1724
static cairo_int_status_t
1725
_emit_source (cairo_script_surface_t *surface,
1726
	      cairo_operator_t op,
1727
	      const cairo_pattern_t *source)
1728
{
1729
    cairo_bool_t matrix_updated = FALSE;
1730
    cairo_int_status_t status;
1731
 
1732
    assert (target_is_active (surface));
1733
 
1734
    if (op == CAIRO_OPERATOR_CLEAR) {
1735
	/* the source is ignored, so don't change it */
1736
	return CAIRO_INT_STATUS_SUCCESS;
1737
    }
1738
 
1739
    if (_cairo_pattern_equal (&surface->cr.current_source.base, source))
1740
	return CAIRO_INT_STATUS_SUCCESS;
1741
 
1742
    _cairo_pattern_fini (&surface->cr.current_source.base);
1743
    status = _cairo_pattern_init_copy (&surface->cr.current_source.base,
1744
				       source);
1745
    if (unlikely (status))
1746
	return status;
1747
 
1748
    status = _emit_identity (surface, &matrix_updated);
1749
    if (unlikely (status))
1750
	return status;
1751
 
1752
    status = _emit_pattern (surface, source);
1753
    if (unlikely (status))
1754
	return status;
1755
 
1756
    assert (target_is_active (surface));
1757
    _cairo_output_stream_puts (to_context (surface)->stream,
1758
			       " set-source\n");
1759
    return CAIRO_INT_STATUS_SUCCESS;
1760
}
1761
 
1762
static cairo_status_t
1763
_path_move_to (void *closure,
1764
	       const cairo_point_t *point)
1765
{
1766
    _cairo_output_stream_printf (closure,
1767
				 " %f %f m",
1768
				 _cairo_fixed_to_double (point->x),
1769
				 _cairo_fixed_to_double (point->y));
1770
 
1771
    return CAIRO_STATUS_SUCCESS;
1772
}
1773
 
1774
static cairo_status_t
1775
_path_line_to (void *closure,
1776
	       const cairo_point_t *point)
1777
{
1778
    _cairo_output_stream_printf (closure,
1779
				 " %f %f l",
1780
				 _cairo_fixed_to_double (point->x),
1781
				 _cairo_fixed_to_double (point->y));
1782
 
1783
    return CAIRO_STATUS_SUCCESS;
1784
}
1785
 
1786
static cairo_status_t
1787
_path_curve_to (void *closure,
1788
		const cairo_point_t *p1,
1789
		const cairo_point_t *p2,
1790
		const cairo_point_t *p3)
1791
{
1792
    _cairo_output_stream_printf (closure,
1793
				 " %f %f %f %f %f %f c",
1794
				 _cairo_fixed_to_double (p1->x),
1795
				 _cairo_fixed_to_double (p1->y),
1796
				 _cairo_fixed_to_double (p2->x),
1797
				 _cairo_fixed_to_double (p2->y),
1798
				 _cairo_fixed_to_double (p3->x),
1799
				 _cairo_fixed_to_double (p3->y));
1800
 
1801
    return CAIRO_STATUS_SUCCESS;
1802
}
1803
 
1804
static cairo_status_t
1805
_path_close (void *closure)
1806
{
1807
    _cairo_output_stream_printf (closure,
1808
				 " h");
1809
 
1810
    return CAIRO_STATUS_SUCCESS;
1811
}
1812
 
1813
static cairo_status_t
1814
_emit_path_boxes (cairo_script_surface_t *surface,
1815
		  const cairo_path_fixed_t *path)
1816
{
1817
    cairo_script_context_t *ctx = to_context (surface);
1818
    cairo_path_fixed_iter_t iter;
1819
    cairo_status_t status;
1820
    struct _cairo_boxes_chunk *chunk;
1821
    cairo_boxes_t boxes;
1822
    cairo_box_t box;
1823
    int i;
1824
 
1825
    _cairo_boxes_init (&boxes);
1826
    _cairo_path_fixed_iter_init (&iter, path);
1827
    while (_cairo_path_fixed_iter_is_fill_box (&iter, &box)) {
1828
	if (box.p1.y == box.p2.y || box.p1.x == box.p2.x)
1829
	    continue;
1830
 
1831
	status = _cairo_boxes_add (&boxes, CAIRO_ANTIALIAS_DEFAULT, &box);
1832
	if (unlikely (status)) {
1833
	    _cairo_boxes_fini (&boxes);
1834
	    return status;
1835
	}
1836
    }
1837
 
1838
    if (! _cairo_path_fixed_iter_at_end (&iter)) {
1839
	_cairo_boxes_fini (&boxes);
1840
	return FALSE;
1841
    }
1842
 
1843
    for (chunk = &boxes.chunks; chunk; chunk = chunk->next) {
1844
	for (i = 0; i < chunk->count; i++) {
1845
	    const cairo_box_t *b = &chunk->base[i];
1846
	    double x1 = _cairo_fixed_to_double (b->p1.x);
1847
	    double y1 = _cairo_fixed_to_double (b->p1.y);
1848
	    double x2 = _cairo_fixed_to_double (b->p2.x);
1849
	    double y2 = _cairo_fixed_to_double (b->p2.y);
1850
 
1851
	    _cairo_output_stream_printf (ctx->stream,
1852
					 "\n  %f %f %f %f rectangle",
1853
					 x1, y1, x2 - x1, y2 - y1);
1854
	}
1855
    }
1856
 
1857
    _cairo_boxes_fini (&boxes);
1858
    return status;
1859
}
1860
 
1861
static cairo_status_t
1862
_emit_path (cairo_script_surface_t *surface,
1863
	    const cairo_path_fixed_t *path,
1864
	    cairo_bool_t is_fill)
1865
{
1866
    cairo_script_context_t *ctx = to_context (surface);
1867
    cairo_box_t box;
1868
    cairo_int_status_t status;
1869
 
1870
    assert (target_is_active (surface));
1871
    assert (_cairo_matrix_is_identity (&surface->cr.current_ctm));
1872
 
1873
    if (_cairo_path_fixed_equal (&surface->cr.current_path, path))
1874
	return CAIRO_STATUS_SUCCESS;
1875
 
1876
    _cairo_path_fixed_fini (&surface->cr.current_path);
1877
 
1878
    _cairo_output_stream_puts (ctx->stream, "n");
1879
 
1880
    if (path == NULL) {
1881
	_cairo_path_fixed_init (&surface->cr.current_path);
1882
	_cairo_output_stream_puts (ctx->stream, "\n");
1883
	return CAIRO_STATUS_SUCCESS;
1884
    }
1885
 
1886
    status = _cairo_path_fixed_init_copy (&surface->cr.current_path, path);
1887
    if (unlikely (status))
1888
	return status;
1889
 
1890
    status = CAIRO_INT_STATUS_UNSUPPORTED;
1891
    if (_cairo_path_fixed_is_rectangle (path, &box)) {
1892
	double x1 = _cairo_fixed_to_double (box.p1.x);
1893
	double y1 = _cairo_fixed_to_double (box.p1.y);
1894
	double x2 = _cairo_fixed_to_double (box.p2.x);
1895
	double y2 = _cairo_fixed_to_double (box.p2.y);
1896
 
1897
	assert (x1 > -9999);
1898
 
1899
	_cairo_output_stream_printf (ctx->stream,
1900
				     " %f %f %f %f rectangle",
1901
				     x1, y1, x2 - x1, y2 - y1);
1902
	status = CAIRO_INT_STATUS_SUCCESS;
1903
    } else if (is_fill && _cairo_path_fixed_fill_is_rectilinear (path)) {
1904
	status = _emit_path_boxes (surface, path);
1905
    }
1906
 
1907
    if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
1908
	status = _cairo_path_fixed_interpret (path,
1909
					      _path_move_to,
1910
					      _path_line_to,
1911
					      _path_curve_to,
1912
					      _path_close,
1913
					      ctx->stream);
1914
    }
1915
 
1916
    _cairo_output_stream_puts (ctx->stream, "\n");
1917
 
1918
    return status;
1919
}
1920
static cairo_bool_t
1921
_scaling_matrix_equal (const cairo_matrix_t *a,
1922
		       const cairo_matrix_t *b)
1923
{
1924
    return fabs (a->xx - b->xx) < 1e-5 &&
1925
	   fabs (a->xy - b->xy) < 1e-5 &&
1926
	   fabs (a->yx - b->yx) < 1e-5 &&
1927
	   fabs (a->yy - b->yy) < 1e-5;
1928
}
1929
 
1930
static cairo_status_t
1931
_emit_scaling_matrix (cairo_script_surface_t *surface,
1932
		      const cairo_matrix_t *ctm,
1933
		      cairo_bool_t *matrix_updated)
1934
{
1935
    cairo_script_context_t *ctx = to_context (surface);
1936
    cairo_bool_t was_identity;
1937
    assert (target_is_active (surface));
1938
 
1939
    if (_scaling_matrix_equal (&surface->cr.current_ctm, ctm))
1940
	return CAIRO_STATUS_SUCCESS;
1941
 
1942
    was_identity = _cairo_matrix_is_identity (&surface->cr.current_ctm);
1943
 
1944
    *matrix_updated = TRUE;
1945
    surface->cr.current_ctm = *ctm;
1946
    surface->cr.current_ctm.x0 = 0.;
1947
    surface->cr.current_ctm.y0 = 0.;
1948
 
1949
    if (_cairo_matrix_is_identity (&surface->cr.current_ctm)) {
1950
	_cairo_output_stream_puts (ctx->stream,
1951
				   "identity set-matrix\n");
1952
    } else if (was_identity && fabs (ctm->yx) < 1e-5 && fabs (ctm->xy) < 1e-5) {
1953
	_cairo_output_stream_printf (ctx->stream,
1954
				     "%f %f scale\n",
1955
				     ctm->xx, ctm->yy);
1956
    } else {
1957
	_cairo_output_stream_printf (ctx->stream,
1958
				     "[%f %f %f %f 0 0] set-matrix\n",
1959
				     ctm->xx, ctm->yx,
1960
				     ctm->xy, ctm->yy);
1961
    }
1962
 
1963
    return CAIRO_STATUS_SUCCESS;
1964
}
1965
 
1966
static cairo_status_t
1967
_emit_font_matrix (cairo_script_surface_t *surface,
1968
		   const cairo_matrix_t *font_matrix)
1969
{
1970
    cairo_script_context_t *ctx = to_context (surface);
1971
    assert (target_is_active (surface));
1972
 
1973
    if (memcmp (&surface->cr.current_font_matrix,
1974
		font_matrix,
1975
		sizeof (cairo_matrix_t)) == 0)
1976
    {
1977
	return CAIRO_STATUS_SUCCESS;
1978
    }
1979
 
1980
    surface->cr.current_font_matrix = *font_matrix;
1981
 
1982
    if (_cairo_matrix_is_identity (font_matrix)) {
1983
	_cairo_output_stream_puts (ctx->stream,
1984
				   "identity set-font-matrix\n");
1985
    } else {
1986
	_cairo_output_stream_printf (ctx->stream,
1987
				     "[%f %f %f %f %f %f] set-font-matrix\n",
1988
				     font_matrix->xx, font_matrix->yx,
1989
				     font_matrix->xy, font_matrix->yy,
1990
				     font_matrix->x0, font_matrix->y0);
1991
    }
1992
 
1993
    return CAIRO_STATUS_SUCCESS;
1994
}
1995
 
1996
static cairo_surface_t *
1997
_cairo_script_surface_create_similar (void	       *abstract_surface,
1998
				      cairo_content_t	content,
1999
				      int		width,
2000
				      int		height)
2001
{
2002
    cairo_script_surface_t *surface, *other = abstract_surface;
2003
    cairo_surface_t *passthrough = NULL;
2004
    cairo_script_context_t *ctx;
2005
    cairo_rectangle_t extents;
2006
    cairo_status_t status;
2007
 
2008
    ctx = to_context (other);
2009
 
2010
    status = cairo_device_acquire (&ctx->base);
2011
    if (unlikely (status))
2012
	return _cairo_surface_create_in_error (status);
2013
 
2014
    if (! other->emitted) {
2015
	status = _emit_surface (other);
2016
	if (unlikely (status)) {
2017
	    cairo_device_release (&ctx->base);
2018
	    return _cairo_surface_create_in_error (status);
2019
	}
2020
 
2021
	target_push (other);
2022
    }
2023
 
2024
    if (_cairo_surface_wrapper_is_active (&other->wrapper)) {
2025
	passthrough =
2026
	    _cairo_surface_wrapper_create_similar (&other->wrapper,
2027
						   content, width, height);
2028
	if (unlikely (passthrough->status)) {
2029
	    cairo_device_release (&ctx->base);
2030
	    return passthrough;
2031
	}
2032
    }
2033
 
2034
    extents.x = extents.y = 0;
2035
    extents.width = width;
2036
    extents.height = height;
2037
    surface = _cairo_script_surface_create_internal (ctx, content,
2038
						     &extents, passthrough);
2039
    cairo_surface_destroy (passthrough);
2040
 
2041
    if (unlikely (surface->base.status)) {
2042
	cairo_device_release (&ctx->base);
2043
	return &surface->base;
2044
    }
2045
 
2046
    _get_target (other);
2047
    _cairo_output_stream_printf (ctx->stream,
2048
				 "%u %u //%s similar dup /s%u exch def context\n",
2049
				 width, height,
2050
				 _content_to_string (content),
2051
				 surface->base.unique_id);
2052
 
2053
    surface->emitted = TRUE;
2054
    surface->defined = TRUE;
2055
    surface->base.is_clear = TRUE;
2056
    target_push (surface);
2057
 
2058
    cairo_device_release (&ctx->base);
2059
    return &surface->base;
2060
}
2061
 
2062
static cairo_status_t
2063
_device_flush (void *abstract_device)
2064
{
2065
    cairo_script_context_t *ctx = abstract_device;
2066
 
2067
    return _cairo_output_stream_flush (ctx->stream);
2068
}
2069
 
2070
static void
2071
_device_destroy (void *abstract_device)
2072
{
2073
    cairo_script_context_t *ctx = abstract_device;
2074
    cairo_status_t status;
2075
 
2076
    while (! cairo_list_is_empty (&ctx->fonts)) {
2077
	cairo_script_font_t *font;
2078
 
2079
	font = cairo_list_first_entry (&ctx->fonts, cairo_script_font_t, link);
2080
	cairo_list_del (&font->base.link);
2081
	cairo_list_del (&font->link);
2082
	free (font);
2083
    }
2084
 
2085
    _bitmap_fini (ctx->surface_id.next);
2086
    _bitmap_fini (ctx->font_id.next);
2087
 
2088
    if (ctx->owns_stream)
2089
	status = _cairo_output_stream_destroy (ctx->stream);
2090
 
2091
    free (ctx);
2092
}
2093
 
2094
static cairo_surface_t *
2095
_cairo_script_surface_source (void                    *abstract_surface,
2096
			      cairo_rectangle_int_t	*extents)
2097
{
2098
    cairo_script_surface_t *surface = abstract_surface;
2099
 
2100
    if (extents) {
2101
	extents->x = extents->y = 0;
2102
	extents->width  = surface->width;
2103
	extents->height = surface->height;
2104
    }
2105
 
2106
    return &surface->base;
2107
}
2108
 
2109
static cairo_status_t
2110
_cairo_script_surface_acquire_source_image (void                    *abstract_surface,
2111
					    cairo_image_surface_t  **image_out,
2112
					    void                   **image_extra)
2113
{
2114
    cairo_script_surface_t *surface = abstract_surface;
2115
 
2116
    if (_cairo_surface_wrapper_is_active (&surface->wrapper)) {
2117
	return _cairo_surface_wrapper_acquire_source_image (&surface->wrapper,
2118
							    image_out,
2119
							    image_extra);
2120
    }
2121
 
2122
    return CAIRO_INT_STATUS_UNSUPPORTED;
2123
}
2124
 
2125
static void
2126
_cairo_script_surface_release_source_image (void                   *abstract_surface,
2127
					   cairo_image_surface_t  *image,
2128
					   void                   *image_extra)
2129
{
2130
    cairo_script_surface_t *surface = abstract_surface;
2131
 
2132
    assert (_cairo_surface_wrapper_is_active (&surface->wrapper));
2133
    _cairo_surface_wrapper_release_source_image (&surface->wrapper,
2134
						 image,
2135
						 image_extra);
2136
}
2137
 
2138
static cairo_status_t
2139
_cairo_script_surface_finish (void *abstract_surface)
2140
{
2141
    cairo_script_surface_t *surface = abstract_surface;
2142
    cairo_script_context_t *ctx = to_context (surface);
2143
    cairo_status_t status = CAIRO_STATUS_SUCCESS, status2;
2144
 
2145
    _cairo_surface_wrapper_fini (&surface->wrapper);
2146
 
2147
    free (surface->cr.current_style.dash);
2148
    surface->cr.current_style.dash = NULL;
2149
 
2150
    _cairo_pattern_fini (&surface->cr.current_source.base);
2151
    _cairo_path_fixed_fini (&surface->cr.current_path);
2152
    _cairo_surface_clipper_reset (&surface->clipper);
2153
 
2154
    status = cairo_device_acquire (&ctx->base);
2155
    if (unlikely (status))
2156
	return status;
2157
 
2158
    if (surface->emitted) {
2159
	assert (! surface->active);
2160
 
2161
	if (! cairo_list_is_empty (&surface->operand.link)) {
2162
	    if (! ctx->active) {
2163
		if (target_is_active (surface)) {
2164
		    _cairo_output_stream_printf (ctx->stream,
2165
						 "pop\n");
2166
		} else {
2167
		    int depth = target_depth (surface);
2168
		    if (depth == 1) {
2169
			_cairo_output_stream_printf (ctx->stream,
2170
						     "exch pop\n");
2171
		    } else {
2172
			_cairo_output_stream_printf (ctx->stream,
2173
						     "%d -1 roll pop\n",
2174
						     depth);
2175
		    }
2176
		}
2177
		cairo_list_del (&surface->operand.link);
2178
	    } else {
2179
		struct deferred_finish *link = malloc (sizeof (*link));
2180
		if (link == NULL) {
2181
		    status2 = _cairo_error (CAIRO_STATUS_NO_MEMORY);
2182
		    if (status == CAIRO_STATUS_SUCCESS)
2183
			status = status2;
2184
		    cairo_list_del (&surface->operand.link);
2185
		} else {
2186
		    link->operand.type = DEFERRED;
2187
		    cairo_list_swap (&link->operand.link,
2188
				     &surface->operand.link);
2189
		    cairo_list_add (&link->link, &ctx->deferred);
2190
		}
2191
	    }
2192
	}
2193
 
2194
	if (surface->defined) {
2195
	    _cairo_output_stream_printf (ctx->stream,
2196
					 "/s%u undef\n",
2197
					 surface->base.unique_id);
2198
	}
2199
    }
2200
 
2201
    if (status == CAIRO_STATUS_SUCCESS)
2202
	status = _cairo_output_stream_flush (to_context (surface)->stream);
2203
 
2204
    cairo_device_release (&ctx->base);
2205
 
2206
    return status;
2207
}
2208
 
2209
static cairo_int_status_t
2210
_cairo_script_surface_copy_page (void *abstract_surface)
2211
{
2212
    cairo_script_surface_t *surface = abstract_surface;
2213
    cairo_status_t status;
2214
 
2215
    status = cairo_device_acquire (surface->base.device);
2216
    if (unlikely (status))
2217
	return status;
2218
 
2219
    status = _emit_context (surface);
2220
    if (unlikely (status))
2221
	goto BAIL;
2222
 
2223
    _cairo_output_stream_puts (to_context (surface)->stream, "copy-page\n");
2224
 
2225
BAIL:
2226
    cairo_device_release (surface->base.device);
2227
    return status;
2228
}
2229
 
2230
static cairo_int_status_t
2231
_cairo_script_surface_show_page (void *abstract_surface)
2232
{
2233
    cairo_script_surface_t *surface = abstract_surface;
2234
    cairo_status_t status;
2235
 
2236
    status = cairo_device_acquire (surface->base.device);
2237
    if (unlikely (status))
2238
	return status;
2239
 
2240
    status = _emit_context (surface);
2241
    if (unlikely (status))
2242
	goto BAIL;
2243
 
2244
    _cairo_output_stream_puts (to_context (surface)->stream, "show-page\n");
2245
 
2246
BAIL:
2247
    cairo_device_release (surface->base.device);
2248
    return status;
2249
}
2250
 
2251
static cairo_status_t
2252
_cairo_script_surface_clipper_intersect_clip_path (cairo_surface_clipper_t *clipper,
2253
						   cairo_path_fixed_t	*path,
2254
						   cairo_fill_rule_t	 fill_rule,
2255
						   double		 tolerance,
2256
						   cairo_antialias_t	 antialias)
2257
{
2258
    cairo_script_surface_t *surface = cairo_container_of (clipper,
2259
							  cairo_script_surface_t,
2260
							  clipper);
2261
    cairo_script_context_t *ctx = to_context (surface);
2262
    cairo_bool_t matrix_updated = FALSE;
2263
    cairo_status_t status;
2264
    cairo_box_t box;
2265
 
2266
    status = _emit_context (surface);
2267
    if (unlikely (status))
2268
	return status;
2269
 
2270
    if (path == NULL) {
2271
	if (surface->cr.has_clip) {
2272
	    _cairo_output_stream_puts (ctx->stream, "reset-clip\n");
2273
	    surface->cr.has_clip = FALSE;
2274
	}
2275
	return CAIRO_STATUS_SUCCESS;
2276
    }
2277
 
2278
    /* skip the trivial clip covering the surface extents */
2279
    if (surface->width >= 0 && surface->height >= 0 &&
2280
	_cairo_path_fixed_is_box (path, &box))
2281
    {
2282
	if (box.p1.x <= 0 && box.p1.y <= 0 &&
2283
	    box.p2.x >= _cairo_fixed_from_double (surface->width) &&
2284
	    box.p2.y >= _cairo_fixed_from_double (surface->height))
2285
	{
2286
	    return CAIRO_STATUS_SUCCESS;
2287
	}
2288
    }
2289
 
2290
    status = _emit_identity (surface, &matrix_updated);
2291
    if (unlikely (status))
2292
	return status;
2293
 
2294
    status = _emit_fill_rule (surface, fill_rule);
2295
    if (unlikely (status))
2296
	return status;
2297
 
2298
    if (path->has_curve_to) {
2299
	status = _emit_tolerance (surface, tolerance, matrix_updated);
2300
	if (unlikely (status))
2301
	    return status;
2302
    }
2303
 
2304
    if (! _cairo_path_fixed_fill_maybe_region (path)) {
2305
	status = _emit_antialias (surface, antialias);
2306
	if (unlikely (status))
2307
	    return status;
2308
    }
2309
 
2310
    status = _emit_path (surface, path, TRUE);
2311
    if (unlikely (status))
2312
	return status;
2313
 
2314
    _cairo_output_stream_puts (ctx->stream, "clip+\n");
2315
    surface->cr.has_clip = TRUE;
2316
 
2317
    return CAIRO_STATUS_SUCCESS;
2318
}
2319
 
2320
static cairo_status_t
2321
active (cairo_script_surface_t *surface)
2322
{
2323
    cairo_status_t status;
2324
 
2325
    status = cairo_device_acquire (surface->base.device);
2326
    if (unlikely (status))
2327
	return status;
2328
 
2329
    if (surface->active++ == 0)
2330
	to_context (surface)->active++;
2331
 
2332
    return CAIRO_STATUS_SUCCESS;
2333
}
2334
 
2335
static void
2336
inactive (cairo_script_surface_t *surface)
2337
{
2338
    cairo_script_context_t *ctx = to_context (surface);
2339
    cairo_list_t sorted;
2340
 
2341
    assert (surface->active > 0);
2342
    if (--surface->active)
2343
	goto DONE;
2344
 
2345
    assert (ctx->active > 0);
2346
    if (--ctx->active)
2347
	goto DONE;
2348
 
2349
    cairo_list_init (&sorted);
2350
    while (! cairo_list_is_empty (&ctx->deferred)) {
2351
	struct deferred_finish *df;
2352
	cairo_list_t *operand;
2353
	int depth;
2354
 
2355
	df = cairo_list_first_entry (&ctx->deferred,
2356
				     struct deferred_finish,
2357
				     link);
2358
 
2359
	depth = 0;
2360
	cairo_list_foreach (operand, &ctx->operands) {
2361
	    if (operand == &df->operand.link)
2362
		break;
2363
	    depth++;
2364
	}
2365
 
2366
	df->operand.type = depth;
2367
 
2368
	if (cairo_list_is_empty (&sorted)) {
2369
	    cairo_list_move (&df->link, &sorted);
2370
	} else {
2371
	    struct deferred_finish *pos;
2372
 
2373
	    cairo_list_foreach_entry (pos, struct deferred_finish,
2374
				      &sorted,
2375
				      link)
2376
	    {
2377
		if (df->operand.type < pos->operand.type)
2378
		    break;
2379
	    }
2380
	    cairo_list_move_tail (&df->link, &pos->link);
2381
	}
2382
    }
2383
 
2384
    while (! cairo_list_is_empty (&sorted)) {
2385
	struct deferred_finish *df;
2386
	cairo_list_t *operand;
2387
	int depth;
2388
 
2389
	df = cairo_list_first_entry (&sorted,
2390
				     struct deferred_finish,
2391
				     link);
2392
 
2393
	depth = 0;
2394
	cairo_list_foreach (operand, &ctx->operands) {
2395
	    if (operand == &df->operand.link)
2396
		break;
2397
	    depth++;
2398
	}
2399
 
2400
	if (depth == 0) {
2401
	    _cairo_output_stream_printf (ctx->stream,
2402
					 "pop\n");
2403
	} else if (depth == 1) {
2404
	    _cairo_output_stream_printf (ctx->stream,
2405
					 "exch pop\n");
2406
	} else {
2407
	    _cairo_output_stream_printf (ctx->stream,
2408
					 "%d -1 roll pop\n",
2409
					 depth);
2410
	}
2411
 
2412
	cairo_list_del (&df->operand.link);
2413
	cairo_list_del (&df->link);
2414
	free (df);
2415
    }
2416
 
2417
DONE:
2418
    cairo_device_release (surface->base.device);
2419
}
2420
 
2421
static cairo_int_status_t
2422
_cairo_script_surface_paint (void			*abstract_surface,
2423
			     cairo_operator_t		 op,
2424
			     const cairo_pattern_t	*source,
2425
			     const cairo_clip_t		*clip)
2426
{
2427
    cairo_script_surface_t *surface = abstract_surface;
2428
    cairo_status_t status;
2429
 
2430
    status = active (surface);
2431
    if (unlikely (status))
2432
	return status;
2433
 
2434
    status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
2435
    if (unlikely (status))
2436
	goto BAIL;
2437
 
2438
    status = _emit_context (surface);
2439
    if (unlikely (status))
2440
	goto BAIL;
2441
 
2442
    status = _emit_source (surface, op, source);
2443
    if (unlikely (status))
2444
	goto BAIL;
2445
 
2446
    status = _emit_operator (surface, op);
2447
    if (unlikely (status))
2448
	goto BAIL;
2449
 
2450
    _cairo_output_stream_puts (to_context (surface)->stream,
2451
			       "paint\n");
2452
 
2453
    inactive (surface);
2454
 
2455
    if (_cairo_surface_wrapper_is_active (&surface->wrapper)) {
2456
	return _cairo_surface_wrapper_paint (&surface->wrapper,
2457
					     op, source, clip);
2458
    }
2459
 
2460
    return CAIRO_STATUS_SUCCESS;
2461
 
2462
BAIL:
2463
    inactive (surface);
2464
    return status;
2465
}
2466
 
2467
static cairo_int_status_t
2468
_cairo_script_surface_mask (void			*abstract_surface,
2469
			    cairo_operator_t		 op,
2470
			    const cairo_pattern_t	*source,
2471
			    const cairo_pattern_t	*mask,
2472
			    const cairo_clip_t		*clip)
2473
{
2474
    cairo_script_surface_t *surface = abstract_surface;
2475
    cairo_status_t status;
2476
 
2477
    status = active (surface);
2478
    if (unlikely (status))
2479
	return status;
2480
 
2481
    status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
2482
    if (unlikely (status))
2483
	goto BAIL;
2484
 
2485
    status = _emit_context (surface);
2486
    if (unlikely (status))
2487
	goto BAIL;
2488
 
2489
    status = _emit_source (surface, op, source);
2490
    if (unlikely (status))
2491
	goto BAIL;
2492
 
2493
    status = _emit_operator (surface, op);
2494
    if (unlikely (status))
2495
	goto BAIL;
2496
 
2497
    if (_cairo_pattern_equal (source, mask)) {
2498
	_cairo_output_stream_puts (to_context (surface)->stream, "/source get");
2499
    } else {
2500
	status = _emit_pattern (surface, mask);
2501
	if (unlikely (status))
2502
	    goto BAIL;
2503
    }
2504
 
2505
    assert (surface->cr.current_operator == op);
2506
 
2507
    _cairo_output_stream_puts (to_context (surface)->stream,
2508
			       " mask\n");
2509
 
2510
    inactive (surface);
2511
 
2512
    if (_cairo_surface_wrapper_is_active (&surface->wrapper)) {
2513
	return _cairo_surface_wrapper_mask (&surface->wrapper,
2514
					    op, source, mask, clip);
2515
    }
2516
 
2517
    return CAIRO_STATUS_SUCCESS;
2518
 
2519
BAIL:
2520
    inactive (surface);
2521
    return status;
2522
}
2523
 
2524
static cairo_int_status_t
2525
_cairo_script_surface_stroke (void				*abstract_surface,
2526
			      cairo_operator_t			 op,
2527
			      const cairo_pattern_t		*source,
2528
			      const cairo_path_fixed_t		*path,
2529
			      const cairo_stroke_style_t	*style,
2530
			      const cairo_matrix_t		*ctm,
2531
			      const cairo_matrix_t		*ctm_inverse,
2532
			      double				 tolerance,
2533
			      cairo_antialias_t			 antialias,
2534
			      const cairo_clip_t		*clip)
2535
{
2536
    cairo_script_surface_t *surface = abstract_surface;
2537
    cairo_bool_t matrix_updated = FALSE;
2538
    cairo_status_t status;
2539
 
2540
    status = active (surface);
2541
    if (unlikely (status))
2542
	return status;
2543
 
2544
    status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
2545
    if (unlikely (status))
2546
	goto BAIL;
2547
 
2548
    status = _emit_context (surface);
2549
    if (unlikely (status))
2550
	goto BAIL;
2551
 
2552
    status = _emit_identity (surface, &matrix_updated);
2553
    if (unlikely (status))
2554
	goto BAIL;
2555
 
2556
    status = _emit_path (surface, path, FALSE);
2557
    if (unlikely (status))
2558
	goto BAIL;
2559
 
2560
    status = _emit_source (surface, op, source);
2561
    if (unlikely (status))
2562
	goto BAIL;
2563
 
2564
    status = _emit_scaling_matrix (surface, ctm, &matrix_updated);
2565
    if (unlikely (status))
2566
	goto BAIL;
2567
 
2568
    status = _emit_operator (surface, op);
2569
    if (unlikely (status))
2570
	goto BAIL;
2571
 
2572
    if (_scaling_matrix_equal (&surface->cr.current_ctm,
2573
			       &surface->cr.current_stroke_matrix))
2574
    {
2575
	matrix_updated = FALSE;
2576
    }
2577
    else
2578
    {
2579
	matrix_updated = TRUE;
2580
	surface->cr.current_stroke_matrix = surface->cr.current_ctm;
2581
    }
2582
 
2583
    status = _emit_stroke_style (surface, style, matrix_updated);
2584
    if (unlikely (status))
2585
	goto BAIL;
2586
 
2587
    status = _emit_tolerance (surface, tolerance, matrix_updated);
2588
    if (unlikely (status))
2589
	goto BAIL;
2590
 
2591
    status = _emit_antialias (surface, antialias);
2592
    if (unlikely (status))
2593
	goto BAIL;
2594
 
2595
    _cairo_output_stream_puts (to_context (surface)->stream, "stroke+\n");
2596
 
2597
    inactive (surface);
2598
 
2599
    if (_cairo_surface_wrapper_is_active (&surface->wrapper)) {
2600
	return _cairo_surface_wrapper_stroke (&surface->wrapper,
2601
					      op, source, path,
2602
					      style,
2603
					      ctm, ctm_inverse,
2604
					      tolerance, antialias,
2605
					      clip);
2606
    }
2607
 
2608
    return CAIRO_STATUS_SUCCESS;
2609
 
2610
BAIL:
2611
    inactive (surface);
2612
    return status;
2613
}
2614
 
2615
static cairo_int_status_t
2616
_cairo_script_surface_fill (void			*abstract_surface,
2617
			    cairo_operator_t		 op,
2618
			    const cairo_pattern_t	*source,
2619
			    const cairo_path_fixed_t	*path,
2620
			    cairo_fill_rule_t		 fill_rule,
2621
			    double			 tolerance,
2622
			    cairo_antialias_t		 antialias,
2623
			    const cairo_clip_t		*clip)
2624
{
2625
    cairo_script_surface_t *surface = abstract_surface;
2626
    cairo_bool_t matrix_updated = FALSE;
2627
    cairo_status_t status;
2628
    cairo_box_t box;
2629
 
2630
    status = active (surface);
2631
    if (unlikely (status))
2632
	return status;
2633
 
2634
    status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
2635
    if (unlikely (status))
2636
	goto BAIL;
2637
 
2638
    status = _emit_context (surface);
2639
    if (unlikely (status))
2640
	goto BAIL;
2641
 
2642
    status = _emit_identity (surface, &matrix_updated);
2643
    if (unlikely (status))
2644
	goto BAIL;
2645
 
2646
    status = _emit_source (surface, op, source);
2647
    if (unlikely (status))
2648
	goto BAIL;
2649
 
2650
    if (! _cairo_path_fixed_is_box (path, &box)) {
2651
	status = _emit_fill_rule (surface, fill_rule);
2652
	if (unlikely (status))
2653
	    goto BAIL;
2654
    }
2655
 
2656
    if (path->has_curve_to) {
2657
	status = _emit_tolerance (surface, tolerance, matrix_updated);
2658
	if (unlikely (status))
2659
	    goto BAIL;
2660
    }
2661
 
2662
    if (! _cairo_path_fixed_fill_maybe_region (path)) {
2663
	status = _emit_antialias (surface, antialias);
2664
	if (unlikely (status))
2665
	    goto BAIL;
2666
    }
2667
 
2668
    status = _emit_path (surface, path, TRUE);
2669
    if (unlikely (status))
2670
	goto BAIL;
2671
 
2672
    status = _emit_operator (surface, op);
2673
    if (unlikely (status))
2674
	goto BAIL;
2675
 
2676
    _cairo_output_stream_puts (to_context (surface)->stream, "fill+\n");
2677
 
2678
    inactive (surface);
2679
 
2680
    if (_cairo_surface_wrapper_is_active (&surface->wrapper)) {
2681
	return _cairo_surface_wrapper_fill (&surface->wrapper,
2682
					    op, source, path,
2683
					    fill_rule,
2684
					    tolerance,
2685
					    antialias,
2686
					    clip);
2687
    }
2688
 
2689
    return CAIRO_STATUS_SUCCESS;
2690
 
2691
BAIL:
2692
    inactive (surface);
2693
    return status;
2694
}
2695
 
2696
static cairo_surface_t *
2697
_cairo_script_surface_snapshot (void *abstract_surface)
2698
{
2699
    cairo_script_surface_t *surface = abstract_surface;
2700
 
2701
    if (_cairo_surface_wrapper_is_active (&surface->wrapper))
2702
	return _cairo_surface_wrapper_snapshot (&surface->wrapper);
2703
 
2704
    return NULL;
2705
}
2706
 
2707
static cairo_bool_t
2708
_cairo_script_surface_has_show_text_glyphs (void *abstract_surface)
2709
{
2710
    return TRUE;
2711
}
2712
 
2713
static const char *
2714
_subpixel_order_to_string (cairo_subpixel_order_t subpixel_order)
2715
{
2716
    static const char *names[] = {
2717
	"SUBPIXEL_ORDER_DEFAULT",	/* CAIRO_SUBPIXEL_ORDER_DEFAULT */
2718
	"SUBPIXEL_ORDER_RGB",		/* CAIRO_SUBPIXEL_ORDER_RGB */
2719
	"SUBPIXEL_ORDER_BGR",		/* CAIRO_SUBPIXEL_ORDER_BGR */
2720
	"SUBPIXEL_ORDER_VRGB",		/* CAIRO_SUBPIXEL_ORDER_VRGB */
2721
	"SUBPIXEL_ORDER_VBGR"		/* CAIRO_SUBPIXEL_ORDER_VBGR */
2722
    };
2723
    return names[subpixel_order];
2724
}
2725
static const char *
2726
_hint_style_to_string (cairo_hint_style_t hint_style)
2727
{
2728
    static const char *names[] = {
2729
	"HINT_STYLE_DEFAULT",	/* CAIRO_HINT_STYLE_DEFAULT */
2730
	"HINT_STYLE_NONE",	/* CAIRO_HINT_STYLE_NONE */
2731
	"HINT_STYLE_SLIGHT",	/* CAIRO_HINT_STYLE_SLIGHT */
2732
	"HINT_STYLE_MEDIUM",	/* CAIRO_HINT_STYLE_MEDIUM */
2733
	"HINT_STYLE_FULL"	/* CAIRO_HINT_STYLE_FULL */
2734
    };
2735
    return names[hint_style];
2736
}
2737
static const char *
2738
_hint_metrics_to_string (cairo_hint_metrics_t hint_metrics)
2739
{
2740
    static const char *names[] = {
2741
	 "HINT_METRICS_DEFAULT",	/* CAIRO_HINT_METRICS_DEFAULT */
2742
	 "HINT_METRICS_OFF",		/* CAIRO_HINT_METRICS_OFF */
2743
	 "HINT_METRICS_ON"		/* CAIRO_HINT_METRICS_ON */
2744
    };
2745
    return names[hint_metrics];
2746
}
2747
 
2748
static cairo_status_t
2749
_emit_font_options (cairo_script_surface_t *surface,
2750
		    cairo_font_options_t *font_options)
2751
{
2752
    cairo_script_context_t *ctx = to_context (surface);
2753
 
2754
    if (cairo_font_options_equal (&surface->cr.current_font_options,
2755
				  font_options))
2756
    {
2757
	return CAIRO_STATUS_SUCCESS;
2758
    }
2759
 
2760
    _cairo_output_stream_printf (ctx->stream, "<<");
2761
 
2762
    if (font_options->antialias != surface->cr.current_font_options.antialias) {
2763
	_cairo_output_stream_printf (ctx->stream,
2764
				     " /antialias //%s",
2765
				     _antialias_to_string (font_options->antialias));
2766
    }
2767
 
2768
    if (font_options->subpixel_order !=
2769
	surface->cr.current_font_options.subpixel_order)
2770
    {
2771
	_cairo_output_stream_printf (ctx->stream,
2772
				     " /subpixel-order //%s",
2773
				     _subpixel_order_to_string (font_options->subpixel_order));
2774
    }
2775
 
2776
    if (font_options->hint_style !=
2777
	surface->cr.current_font_options.hint_style)
2778
    {
2779
	_cairo_output_stream_printf (ctx->stream,
2780
				     " /hint-style //%s",
2781
				     _hint_style_to_string (font_options->hint_style));
2782
    }
2783
 
2784
    if (font_options->hint_metrics !=
2785
	surface->cr.current_font_options.hint_metrics)
2786
    {
2787
	_cairo_output_stream_printf (ctx->stream,
2788
				     " /hint-metrics //%s",
2789
				     _hint_metrics_to_string (font_options->hint_metrics));
2790
    }
2791
 
2792
    _cairo_output_stream_printf (ctx->stream,
2793
				 " >> set-font-options\n");
2794
 
2795
    surface->cr.current_font_options = *font_options;
2796
    return CAIRO_STATUS_SUCCESS;
2797
}
2798
 
2799
static void
2800
_cairo_script_scaled_font_fini (cairo_scaled_font_private_t *abstract_private,
2801
				cairo_scaled_font_t *scaled_font)
2802
{
2803
    cairo_script_font_t *priv = (cairo_script_font_t *)abstract_private;
2804
    cairo_script_context_t *ctx = (cairo_script_context_t *)abstract_private->key;
2805
    cairo_status_t status;
2806
 
2807
    status = cairo_device_acquire (&ctx->base);
2808
    if (likely (status == CAIRO_STATUS_SUCCESS)) {
2809
	_cairo_output_stream_printf (ctx->stream,
2810
				     "/f%lu undef /sf%lu undef\n",
2811
				     priv->id,
2812
				     priv->id);
2813
 
2814
	_bitmap_release_id (&ctx->font_id, priv->id);
2815
	cairo_device_release (&ctx->base);
2816
    }
2817
 
2818
    cairo_list_del (&priv->link);
2819
    cairo_list_del (&priv->base.link);
2820
    free (priv);
2821
}
2822
 
2823
static cairo_script_font_t *
2824
_cairo_script_font_get (cairo_script_context_t *ctx, cairo_scaled_font_t *font)
2825
{
2826
    return (cairo_script_font_t *) _cairo_scaled_font_find_private (font, ctx);
2827
}
2828
 
2829
static long unsigned
2830
_cairo_script_font_id (cairo_script_context_t *ctx, cairo_scaled_font_t *font)
2831
{
2832
    return _cairo_script_font_get (ctx, font)->id;
2833
}
2834
 
2835
static cairo_status_t
2836
_emit_type42_font (cairo_script_surface_t *surface,
2837
		   cairo_scaled_font_t *scaled_font)
2838
{
2839
    cairo_script_context_t *ctx = to_context (surface);
2840
    const cairo_scaled_font_backend_t *backend;
2841
    cairo_output_stream_t *base85_stream;
2842
    cairo_output_stream_t *zlib_stream;
2843
    cairo_status_t status, status2;
2844
    unsigned long size;
2845
    unsigned int load_flags;
2846
    uint32_t len;
2847
    uint8_t *buf;
2848
 
2849
    backend = scaled_font->backend;
2850
    if (backend->load_truetype_table == NULL)
2851
	return CAIRO_INT_STATUS_UNSUPPORTED;
2852
 
2853
    size = 0;
2854
    status = backend->load_truetype_table (scaled_font, 0, 0, NULL, &size);
2855
    if (unlikely (status))
2856
	return status;
2857
 
2858
    buf = malloc (size);
2859
    if (unlikely (buf == NULL))
2860
	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
2861
 
2862
    status = backend->load_truetype_table (scaled_font, 0, 0, buf, &size);
2863
    if (unlikely (status)) {
2864
	free (buf);
2865
	return status;
2866
    }
2867
 
2868
#if CAIRO_HAS_FT_FONT
2869
    load_flags = _cairo_ft_scaled_font_get_load_flags (scaled_font);
2870
#else
2871
    load_flags = 0;
2872
#endif
2873
    _cairo_output_stream_printf (ctx->stream,
2874
				 "<< "
2875
				 "/type 42 "
2876
				 "/index 0 "
2877
				 "/flags %d "
2878
				 "/source <|",
2879
				 load_flags);
2880
 
2881
    base85_stream = _cairo_base85_stream_create (ctx->stream);
2882
    len = to_be32 (size);
2883
    _cairo_output_stream_write (base85_stream, &len, sizeof (len));
2884
 
2885
    zlib_stream = _cairo_deflate_stream_create (base85_stream);
2886
 
2887
    _cairo_output_stream_write (zlib_stream, buf, size);
2888
    free (buf);
2889
 
2890
    status2 = _cairo_output_stream_destroy (zlib_stream);
2891
    if (status == CAIRO_STATUS_SUCCESS)
2892
	status = status2;
2893
 
2894
    status2 = _cairo_output_stream_destroy (base85_stream);
2895
    if (status == CAIRO_STATUS_SUCCESS)
2896
	status = status2;
2897
 
2898
    _cairo_output_stream_printf (ctx->stream,
2899
				 "~> >> font dup /f%lu exch def set-font-face",
2900
				 _cairo_script_font_id (ctx, scaled_font));
2901
 
2902
    return status;
2903
}
2904
 
2905
static cairo_status_t
2906
_emit_scaled_font_init (cairo_script_surface_t *surface,
2907
			cairo_scaled_font_t *scaled_font,
2908
			cairo_script_font_t **font_out)
2909
{
2910
    cairo_script_context_t *ctx = to_context (surface);
2911
    cairo_script_font_t *font_private;
2912
    cairo_int_status_t status;
2913
 
2914
    font_private = malloc (sizeof (cairo_script_font_t));
2915
    if (unlikely (font_private == NULL))
2916
	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
2917
 
2918
    _cairo_scaled_font_attach_private (scaled_font, &font_private->base, ctx,
2919
				       _cairo_script_scaled_font_fini);
2920
 
2921
    font_private->parent = scaled_font;
2922
    font_private->subset_glyph_index = 0;
2923
    font_private->has_sfnt = TRUE;
2924
 
2925
    cairo_list_add (&font_private->link, &ctx->fonts);
2926
 
2927
    status = _bitmap_next_id (&ctx->font_id,
2928
			      &font_private->id);
2929
    if (unlikely (status)) {
2930
	free (font_private);
2931
	return status;
2932
    }
2933
 
2934
    status = _emit_context (surface);
2935
    if (unlikely (status)) {
2936
	free (font_private);
2937
	return status;
2938
    }
2939
 
2940
    status = _emit_type42_font (surface, scaled_font);
2941
    if (status != CAIRO_INT_STATUS_UNSUPPORTED) {
2942
	*font_out = font_private;
2943
	return status;
2944
    }
2945
 
2946
    font_private->has_sfnt = FALSE;
2947
    _cairo_output_stream_printf (ctx->stream,
2948
				 "dict\n"
2949
				 "  /type 3 set\n"
2950
				 "  /metrics [%f %f %f %f %f] set\n"
2951
				 "  /glyphs array set\n"
2952
				 "  font dup /f%lu exch def set-font-face",
2953
				 scaled_font->fs_extents.ascent,
2954
				 scaled_font->fs_extents.descent,
2955
				 scaled_font->fs_extents.height,
2956
				 scaled_font->fs_extents.max_x_advance,
2957
				 scaled_font->fs_extents.max_y_advance,
2958
				 font_private->id);
2959
 
2960
    *font_out = font_private;
2961
    return CAIRO_STATUS_SUCCESS;
2962
}
2963
 
2964
static cairo_status_t
2965
_emit_scaled_font (cairo_script_surface_t *surface,
2966
		   cairo_scaled_font_t *scaled_font)
2967
{
2968
    cairo_script_context_t *ctx = to_context (surface);
2969
    cairo_matrix_t matrix;
2970
    cairo_font_options_t options;
2971
    cairo_bool_t matrix_updated = FALSE;
2972
    cairo_status_t status;
2973
    cairo_script_font_t *font_private;
2974
 
2975
    cairo_scaled_font_get_ctm (scaled_font, &matrix);
2976
    status = _emit_scaling_matrix (surface, &matrix, &matrix_updated);
2977
    if (unlikely (status))
2978
	return status;
2979
 
2980
    if (! matrix_updated && surface->cr.current_scaled_font == scaled_font)
2981
	return CAIRO_STATUS_SUCCESS;
2982
 
2983
    surface->cr.current_scaled_font = scaled_font;
2984
 
2985
    font_private = _cairo_script_font_get (ctx, scaled_font);
2986
    if (font_private == NULL) {
2987
	cairo_scaled_font_get_font_matrix (scaled_font, &matrix);
2988
	status = _emit_font_matrix (surface, &matrix);
2989
	if (unlikely (status))
2990
	    return status;
2991
 
2992
	cairo_scaled_font_get_font_options (scaled_font, &options);
2993
	status = _emit_font_options (surface, &options);
2994
	if (unlikely (status))
2995
	    return status;
2996
 
2997
	status = _emit_scaled_font_init (surface, scaled_font, &font_private);
2998
	if (unlikely (status))
2999
	    return status;
3000
 
3001
	assert (target_is_active (surface));
3002
	_cairo_output_stream_printf (ctx->stream,
3003
				     " /scaled-font get /sf%lu exch def\n",
3004
				     font_private->id);
3005
    } else {
3006
	_cairo_output_stream_printf (ctx->stream,
3007
				     "sf%lu set-scaled-font\n",
3008
				     font_private->id);
3009
    }
3010
 
3011
    return CAIRO_STATUS_SUCCESS;
3012
}
3013
 
3014
static cairo_status_t
3015
_emit_scaled_glyph_vector (cairo_script_surface_t *surface,
3016
			   cairo_scaled_font_t *scaled_font,
3017
			   cairo_script_font_t *font_private,
3018
			   cairo_scaled_glyph_t *scaled_glyph)
3019
{
3020
    cairo_script_context_t *ctx = to_context (surface);
3021
    cairo_script_implicit_context_t old_cr;
3022
    cairo_status_t status;
3023
    unsigned long index;
3024
 
3025
    index = ++font_private->subset_glyph_index;
3026
    scaled_glyph->dev_private_key = ctx;
3027
    scaled_glyph->dev_private = (void *) index;
3028
 
3029
    _cairo_output_stream_printf (ctx->stream,
3030
				 "%lu <<\n"
3031
				 "  /metrics [%f %f %f %f %f %f]\n"
3032
				 "  /render {\n",
3033
				 index,
3034
				 scaled_glyph->fs_metrics.x_bearing,
3035
				 scaled_glyph->fs_metrics.y_bearing,
3036
				 scaled_glyph->fs_metrics.width,
3037
				 scaled_glyph->fs_metrics.height,
3038
				 scaled_glyph->fs_metrics.x_advance,
3039
				 scaled_glyph->fs_metrics.y_advance);
3040
 
3041
    if (! _cairo_matrix_is_identity (&scaled_font->scale_inverse)) {
3042
	_cairo_output_stream_printf (ctx->stream,
3043
				     "[%f %f %f %f %f %f] transform\n",
3044
				     scaled_font->scale_inverse.xx,
3045
				     scaled_font->scale_inverse.yx,
3046
				     scaled_font->scale_inverse.xy,
3047
				     scaled_font->scale_inverse.yy,
3048
				     scaled_font->scale_inverse.x0,
3049
				     scaled_font->scale_inverse.y0);
3050
    }
3051
 
3052
    old_cr = surface->cr;
3053
    _cairo_script_implicit_context_init (&surface->cr);
3054
    status = _cairo_recording_surface_replay (scaled_glyph->recording_surface,
3055
					      &surface->base);
3056
    surface->cr = old_cr;
3057
 
3058
    _cairo_output_stream_puts (ctx->stream, "} >> set\n");
3059
 
3060
    return status;
3061
}
3062
 
3063
static cairo_status_t
3064
_emit_scaled_glyph_bitmap (cairo_script_surface_t *surface,
3065
			   cairo_scaled_font_t *scaled_font,
3066
			   cairo_script_font_t *font_private,
3067
			   cairo_scaled_glyph_t *scaled_glyph)
3068
{
3069
    cairo_script_context_t *ctx = to_context (surface);
3070
    cairo_status_t status;
3071
    unsigned long index;
3072
 
3073
    index = ++font_private->subset_glyph_index;
3074
    scaled_glyph->dev_private_key = ctx;
3075
    scaled_glyph->dev_private = (void *) index;
3076
 
3077
    _cairo_output_stream_printf (ctx->stream,
3078
				 "%lu <<\n"
3079
				 "  /metrics [%f %f %f %f %f %f]\n"
3080
				 "  /render {\n"
3081
				 "%f %f translate\n",
3082
				 index,
3083
				 scaled_glyph->fs_metrics.x_bearing,
3084
				 scaled_glyph->fs_metrics.y_bearing,
3085
				 scaled_glyph->fs_metrics.width,
3086
				 scaled_glyph->fs_metrics.height,
3087
				 scaled_glyph->fs_metrics.x_advance,
3088
				 scaled_glyph->fs_metrics.y_advance,
3089
				 scaled_glyph->fs_metrics.x_bearing,
3090
				 scaled_glyph->fs_metrics.y_bearing);
3091
 
3092
    status = _emit_image_surface (surface, scaled_glyph->surface);
3093
    if (unlikely (status))
3094
	return status;
3095
 
3096
    _cairo_output_stream_puts (ctx->stream, "pattern ");
3097
 
3098
    if (! _cairo_matrix_is_identity (&scaled_font->font_matrix)) {
3099
	_cairo_output_stream_printf (ctx->stream,
3100
				     "\n  [%f %f %f %f %f %f] set-matrix\n",
3101
				     scaled_font->font_matrix.xx,
3102
				     scaled_font->font_matrix.yx,
3103
				     scaled_font->font_matrix.xy,
3104
				     scaled_font->font_matrix.yy,
3105
				     scaled_font->font_matrix.x0,
3106
				     scaled_font->font_matrix.y0);
3107
    }
3108
    _cairo_output_stream_puts (ctx->stream,
3109
				 "mask\n} >> set\n");
3110
 
3111
    return CAIRO_STATUS_SUCCESS;
3112
}
3113
 
3114
static cairo_status_t
3115
_emit_scaled_glyph_prologue (cairo_script_surface_t *surface,
3116
			     cairo_scaled_font_t *scaled_font)
3117
{
3118
    cairo_script_context_t *ctx = to_context (surface);
3119
 
3120
    _cairo_output_stream_printf (ctx->stream, "f%lu /glyphs get\n",
3121
				 _cairo_script_font_id (ctx, scaled_font));
3122
 
3123
    return CAIRO_STATUS_SUCCESS;
3124
}
3125
 
3126
static cairo_status_t
3127
_emit_scaled_glyphs (cairo_script_surface_t *surface,
3128
		     cairo_scaled_font_t *scaled_font,
3129
		     cairo_glyph_t *glyphs,
3130
		     unsigned int num_glyphs)
3131
{
3132
    cairo_script_context_t *ctx = to_context (surface);
3133
    cairo_script_font_t *font_private;
3134
    cairo_status_t status;
3135
    unsigned int n;
3136
    cairo_bool_t have_glyph_prologue = FALSE;
3137
 
3138
    if (num_glyphs == 0)
3139
	return CAIRO_STATUS_SUCCESS;
3140
 
3141
    font_private = _cairo_script_font_get (ctx, scaled_font);
3142
    if (font_private->has_sfnt)
3143
	return CAIRO_STATUS_SUCCESS;
3144
 
3145
    _cairo_scaled_font_freeze_cache (scaled_font);
3146
    for (n = 0; n < num_glyphs; n++) {
3147
	cairo_scaled_glyph_t *scaled_glyph;
3148
 
3149
	status = _cairo_scaled_glyph_lookup (scaled_font,
3150
					     glyphs[n].index,
3151
					     CAIRO_SCALED_GLYPH_INFO_METRICS,
3152
					     &scaled_glyph);
3153
	if (unlikely (status))
3154
	    break;
3155
 
3156
	if (scaled_glyph->dev_private_key == ctx)
3157
	    continue;
3158
 
3159
	status = _cairo_scaled_glyph_lookup (scaled_font,
3160
					     glyphs[n].index,
3161
					     CAIRO_SCALED_GLYPH_INFO_RECORDING_SURFACE,
3162
					     &scaled_glyph);
3163
	if (_cairo_status_is_error (status))
3164
	    break;
3165
 
3166
	if (status == CAIRO_STATUS_SUCCESS) {
3167
	    if (! have_glyph_prologue) {
3168
		status = _emit_scaled_glyph_prologue (surface, scaled_font);
3169
		if (unlikely (status))
3170
		    break;
3171
 
3172
		have_glyph_prologue = TRUE;
3173
	    }
3174
 
3175
	    status = _emit_scaled_glyph_vector (surface,
3176
						scaled_font, font_private,
3177
						scaled_glyph);
3178
	    if (unlikely (status))
3179
		break;
3180
 
3181
	    continue;
3182
	}
3183
 
3184
	status = _cairo_scaled_glyph_lookup (scaled_font,
3185
					     glyphs[n].index,
3186
					     CAIRO_SCALED_GLYPH_INFO_SURFACE,
3187
					     &scaled_glyph);
3188
	if (_cairo_status_is_error (status))
3189
	    break;
3190
 
3191
	if (status == CAIRO_STATUS_SUCCESS) {
3192
	    if (! have_glyph_prologue) {
3193
		status = _emit_scaled_glyph_prologue (surface, scaled_font);
3194
		if (unlikely (status))
3195
		    break;
3196
 
3197
		have_glyph_prologue = TRUE;
3198
	    }
3199
 
3200
	    status = _emit_scaled_glyph_bitmap (surface,
3201
						scaled_font,
3202
						font_private,
3203
						scaled_glyph);
3204
	    if (unlikely (status))
3205
		break;
3206
 
3207
	    continue;
3208
	}
3209
    }
3210
    _cairo_scaled_font_thaw_cache (scaled_font);
3211
 
3212
    if (have_glyph_prologue) {
3213
	_cairo_output_stream_puts (to_context (surface)->stream, "pop pop\n");
3214
    }
3215
 
3216
    return status;
3217
}
3218
 
3219
static void
3220
to_octal (int value, char *buf, size_t size)
3221
{
3222
    do {
3223
	buf[--size] = '0' + (value & 7);
3224
	value >>= 3;
3225
    } while (size);
3226
}
3227
 
3228
static void
3229
_emit_string_literal (cairo_script_surface_t *surface,
3230
		      const char *utf8, int len)
3231
{
3232
    cairo_script_context_t *ctx = to_context (surface);
3233
    char c;
3234
    const char *end;
3235
 
3236
    _cairo_output_stream_puts (ctx->stream, "(");
3237
 
3238
    if (utf8 == NULL) {
3239
	end = utf8;
3240
    } else {
3241
	if (len < 0)
3242
	    len = strlen (utf8);
3243
	end = utf8 + len;
3244
    }
3245
 
3246
    while (utf8 < end) {
3247
	switch ((c = *utf8++)) {
3248
	case '\n':
3249
	    c = 'n';
3250
	    goto ESCAPED_CHAR;
3251
	case '\r':
3252
	    c = 'r';
3253
	    goto ESCAPED_CHAR;
3254
	case '\t':
3255
	    c = 't';
3256
	    goto ESCAPED_CHAR;
3257
	case '\b':
3258
	    c = 'b';
3259
	    goto ESCAPED_CHAR;
3260
	case '\f':
3261
	    c = 'f';
3262
	    goto ESCAPED_CHAR;
3263
	case '\\':
3264
	case '(':
3265
	case ')':
3266
ESCAPED_CHAR:
3267
	    _cairo_output_stream_printf (ctx->stream, "\\%c", c);
3268
	    break;
3269
	default:
3270
	    if (isprint (c) || isspace (c)) {
3271
		_cairo_output_stream_printf (ctx->stream, "%c", c);
3272
	    } else {
3273
		char buf[4] = { '\\' };
3274
 
3275
		to_octal (c, buf+1, 3);
3276
		_cairo_output_stream_write (ctx->stream, buf, 4);
3277
	    }
3278
	    break;
3279
	}
3280
    }
3281
    _cairo_output_stream_puts (ctx->stream, ")");
3282
}
3283
 
3284
static cairo_int_status_t
3285
_cairo_script_surface_show_text_glyphs (void			    *abstract_surface,
3286
					cairo_operator_t	     op,
3287
					const cairo_pattern_t	    *source,
3288
					const char		    *utf8,
3289
					int			     utf8_len,
3290
					cairo_glyph_t		    *glyphs,
3291
					int			     num_glyphs,
3292
					const cairo_text_cluster_t  *clusters,
3293
					int			     num_clusters,
3294
					cairo_text_cluster_flags_t   backward,
3295
					cairo_scaled_font_t	    *scaled_font,
3296
					const cairo_clip_t	    *clip)
3297
{
3298
    cairo_script_surface_t *surface = abstract_surface;
3299
    cairo_script_context_t *ctx = to_context (surface);
3300
    cairo_script_font_t *font_private;
3301
    cairo_scaled_glyph_t *scaled_glyph;
3302
    cairo_matrix_t matrix;
3303
    cairo_status_t status;
3304
    double x, y, ix, iy;
3305
    int n;
3306
    cairo_output_stream_t *base85_stream = NULL;
3307
 
3308
    status = active (surface);
3309
    if (unlikely (status))
3310
	return status;
3311
 
3312
    status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
3313
    if (unlikely (status))
3314
	goto BAIL;
3315
 
3316
    status = _emit_context (surface);
3317
    if (unlikely (status))
3318
	goto BAIL;
3319
 
3320
    status = _emit_source (surface, op, source);
3321
    if (unlikely (status))
3322
	goto BAIL;
3323
 
3324
    status = _emit_scaled_font (surface, scaled_font);
3325
    if (unlikely (status))
3326
	goto BAIL;
3327
 
3328
    status = _emit_operator (surface, op);
3329
    if (unlikely (status))
3330
	goto BAIL;
3331
 
3332
    status = _emit_scaled_glyphs (surface, scaled_font, glyphs, num_glyphs);
3333
    if (unlikely (status))
3334
	goto BAIL;
3335
 
3336
    /* (utf8) [cx cy [glyphs]] [clusters] backward show_text_glyphs */
3337
    /* [cx cy [glyphs]] show_glyphs */
3338
 
3339
    if (utf8 != NULL && clusters != NULL) {
3340
	_emit_string_literal (surface, utf8, utf8_len);
3341
	_cairo_output_stream_puts (ctx->stream, " ");
3342
    }
3343
 
3344
    matrix = surface->cr.current_ctm;
3345
    status = cairo_matrix_invert (&matrix);
3346
    assert (status == CAIRO_STATUS_SUCCESS);
3347
 
3348
    ix = x = glyphs[0].x;
3349
    iy = y = glyphs[0].y;
3350
    cairo_matrix_transform_point (&matrix, &ix, &iy);
3351
    ix -= scaled_font->font_matrix.x0;
3352
    iy -= scaled_font->font_matrix.y0;
3353
 
3354
    _cairo_scaled_font_freeze_cache (scaled_font);
3355
    font_private = _cairo_script_font_get (ctx, scaled_font);
3356
 
3357
    _cairo_output_stream_printf (ctx->stream,
3358
				 "[%f %f ",
3359
				 ix, iy);
3360
 
3361
    for (n = 0; n < num_glyphs; n++) {
3362
	if (font_private->has_sfnt) {
3363
	    if (glyphs[n].index > 256)
3364
		break;
3365
	} else {
3366
	    status = _cairo_scaled_glyph_lookup (scaled_font,
3367
						 glyphs[n].index,
3368
						 CAIRO_SCALED_GLYPH_INFO_METRICS,
3369
						 &scaled_glyph);
3370
	    if (unlikely (status)) {
3371
		_cairo_scaled_font_thaw_cache (scaled_font);
3372
		goto BAIL;
3373
	    }
3374
 
3375
	    if ((long unsigned) scaled_glyph->dev_private > 256)
3376
		break;
3377
	}
3378
    }
3379
 
3380
    if (n == num_glyphs) {
3381
	_cairo_output_stream_puts (ctx->stream, "<~");
3382
	base85_stream = _cairo_base85_stream_create (ctx->stream);
3383
    } else
3384
	_cairo_output_stream_puts (ctx->stream, "[");
3385
 
3386
    for (n = 0; n < num_glyphs; n++) {
3387
	double dx, dy;
3388
 
3389
	status = _cairo_scaled_glyph_lookup (scaled_font,
3390
					     glyphs[n].index,
3391
					     CAIRO_SCALED_GLYPH_INFO_METRICS,
3392
					     &scaled_glyph);
3393
	if (unlikely (status)) {
3394
	    _cairo_scaled_font_thaw_cache (scaled_font);
3395
	    goto BAIL;
3396
	}
3397
 
3398
	if (fabs (glyphs[n].x - x) > 1e-5 || fabs (glyphs[n].y - y) > 1e-5) {
3399
	    if (fabs (glyphs[n].y - y) < 1e-5) {
3400
		if (base85_stream != NULL) {
3401
		    status = _cairo_output_stream_destroy (base85_stream);
3402
		    if (unlikely (status)) {
3403
			base85_stream = NULL;
3404
			break;
3405
		    }
3406
 
3407
		    _cairo_output_stream_printf (ctx->stream,
3408
						 "~> %f <~", glyphs[n].x - x);
3409
		    base85_stream = _cairo_base85_stream_create (ctx->stream);
3410
		} else {
3411
		    _cairo_output_stream_printf (ctx->stream,
3412
						 " ] %f [ ", glyphs[n].x - x);
3413
		}
3414
 
3415
		x = glyphs[n].x;
3416
	    } else {
3417
		ix = x = glyphs[n].x;
3418
		iy = y = glyphs[n].y;
3419
		cairo_matrix_transform_point (&matrix, &ix, &iy);
3420
		ix -= scaled_font->font_matrix.x0;
3421
		iy -= scaled_font->font_matrix.y0;
3422
		if (base85_stream != NULL) {
3423
		    status = _cairo_output_stream_destroy (base85_stream);
3424
		    if (unlikely (status)) {
3425
			base85_stream = NULL;
3426
			break;
3427
		    }
3428
 
3429
		    _cairo_output_stream_printf (ctx->stream,
3430
						 "~> %f %f <~",
3431
						 ix, iy);
3432
		    base85_stream = _cairo_base85_stream_create (ctx->stream);
3433
		} else {
3434
		    _cairo_output_stream_printf (ctx->stream,
3435
						 " ] %f %f [ ",
3436
						 ix, iy);
3437
		}
3438
	    }
3439
	}
3440
	if (base85_stream != NULL) {
3441
	    uint8_t c;
3442
 
3443
	    if (font_private->has_sfnt)
3444
		c = glyphs[n].index;
3445
	    else
3446
		c = (uint8_t) (long unsigned) scaled_glyph->dev_private;
3447
 
3448
	    _cairo_output_stream_write (base85_stream, &c, 1);
3449
	} else {
3450
	    if (font_private->has_sfnt)
3451
		_cairo_output_stream_printf (ctx->stream, " %lu",
3452
					     glyphs[n].index);
3453
	    else
3454
		_cairo_output_stream_printf (ctx->stream, " %lu",
3455
					     (long unsigned) scaled_glyph->dev_private);
3456
	}
3457
 
3458
        dx = scaled_glyph->metrics.x_advance;
3459
        dy = scaled_glyph->metrics.y_advance;
3460
	cairo_matrix_transform_distance (&scaled_font->ctm, &dx, &dy);
3461
	x += dx;
3462
	y += dy;
3463
    }
3464
    _cairo_scaled_font_thaw_cache (scaled_font);
3465
 
3466
    if (base85_stream != NULL) {
3467
	cairo_status_t status2;
3468
 
3469
	status2 = _cairo_output_stream_destroy (base85_stream);
3470
	if (status == CAIRO_STATUS_SUCCESS)
3471
	    status = status2;
3472
 
3473
	_cairo_output_stream_printf (ctx->stream, "~>");
3474
    } else {
3475
	_cairo_output_stream_puts (ctx->stream, " ]");
3476
    }
3477
    if (unlikely (status))
3478
	return status;
3479
 
3480
    if (utf8 != NULL && clusters != NULL) {
3481
	for (n = 0; n < num_clusters; n++) {
3482
	    if (clusters[n].num_bytes > UCHAR_MAX ||
3483
		clusters[n].num_glyphs > UCHAR_MAX)
3484
	    {
3485
		break;
3486
	    }
3487
	}
3488
 
3489
	if (n < num_clusters) {
3490
	    _cairo_output_stream_puts (ctx->stream, "] [ ");
3491
	    for (n = 0; n < num_clusters; n++) {
3492
		_cairo_output_stream_printf (ctx->stream,
3493
					     "%d %d ",
3494
					     clusters[n].num_bytes,
3495
					     clusters[n].num_glyphs);
3496
	    }
3497
	    _cairo_output_stream_puts (ctx->stream, "]");
3498
	}
3499
	else
3500
	{
3501
	    _cairo_output_stream_puts (ctx->stream, "] <~");
3502
	    base85_stream = _cairo_base85_stream_create (ctx->stream);
3503
	    for (n = 0; n < num_clusters; n++) {
3504
		uint8_t c[2];
3505
		c[0] = clusters[n].num_bytes;
3506
		c[1] = clusters[n].num_glyphs;
3507
		_cairo_output_stream_write (base85_stream, c, 2);
3508
	    }
3509
	    status = _cairo_output_stream_destroy (base85_stream);
3510
	    if (unlikely (status))
3511
		goto BAIL;
3512
 
3513
	    _cairo_output_stream_puts (ctx->stream, "~>");
3514
	}
3515
 
3516
	_cairo_output_stream_printf (ctx->stream,
3517
				     " //%s show-text-glyphs\n",
3518
				     _direction_to_string (backward));
3519
    } else {
3520
	_cairo_output_stream_puts (ctx->stream,
3521
				   "] show-glyphs\n");
3522
    }
3523
 
3524
    inactive (surface);
3525
 
3526
    if (_cairo_surface_wrapper_is_active (&surface->wrapper)){
3527
	return _cairo_surface_wrapper_show_text_glyphs (&surface->wrapper,
3528
							op, source,
3529
							utf8, utf8_len,
3530
							glyphs, num_glyphs,
3531
							clusters, num_clusters,
3532
							backward,
3533
							scaled_font,
3534
							clip);
3535
    }
3536
 
3537
    return CAIRO_STATUS_SUCCESS;
3538
 
3539
BAIL:
3540
    inactive (surface);
3541
    return status;
3542
}
3543
 
3544
static cairo_bool_t
3545
_cairo_script_surface_get_extents (void *abstract_surface,
3546
				   cairo_rectangle_int_t *rectangle)
3547
{
3548
    cairo_script_surface_t *surface = abstract_surface;
3549
 
3550
    if (_cairo_surface_wrapper_is_active (&surface->wrapper)) {
3551
	return _cairo_surface_wrapper_get_extents (&surface->wrapper,
3552
						   rectangle);
3553
    }
3554
 
3555
    if (surface->width < 0 || surface->height < 0)
3556
	return FALSE;
3557
 
3558
    rectangle->x = 0;
3559
    rectangle->y = 0;
3560
    rectangle->width = surface->width;
3561
    rectangle->height = surface->height;
3562
 
3563
    return TRUE;
3564
}
3565
 
3566
static const cairo_surface_backend_t
3567
_cairo_script_surface_backend = {
3568
    CAIRO_SURFACE_TYPE_SCRIPT,
3569
    _cairo_script_surface_finish,
3570
 
3571
    _cairo_default_context_create,
3572
 
3573
    _cairo_script_surface_create_similar,
3574
    NULL, /* create similar image */
3575
    NULL, /* map to image */
3576
    NULL, /* unmap image */
3577
 
3578
    _cairo_script_surface_source,
3579
    _cairo_script_surface_acquire_source_image,
3580
    _cairo_script_surface_release_source_image,
3581
    _cairo_script_surface_snapshot,
3582
 
3583
    _cairo_script_surface_copy_page,
3584
    _cairo_script_surface_show_page,
3585
 
3586
    _cairo_script_surface_get_extents,
3587
    NULL, /* get_font_options */
3588
 
3589
    NULL, /* flush */
3590
    NULL, /* mark_dirty_rectangle */
3591
 
3592
    _cairo_script_surface_paint,
3593
    _cairo_script_surface_mask,
3594
    _cairo_script_surface_stroke,
3595
    _cairo_script_surface_fill,
3596
    NULL, /* fill/stroke */
3597
    NULL, /* glyphs */
3598
    _cairo_script_surface_has_show_text_glyphs,
3599
    _cairo_script_surface_show_text_glyphs
3600
};
3601
 
3602
static void
3603
_cairo_script_implicit_context_init (cairo_script_implicit_context_t *cr)
3604
{
3605
    cr->current_operator = CAIRO_GSTATE_OPERATOR_DEFAULT;
3606
    cr->current_fill_rule = CAIRO_GSTATE_FILL_RULE_DEFAULT;
3607
    cr->current_tolerance = CAIRO_GSTATE_TOLERANCE_DEFAULT;
3608
    cr->current_antialias = CAIRO_ANTIALIAS_DEFAULT;
3609
    _cairo_stroke_style_init (&cr->current_style);
3610
    _cairo_pattern_init_solid (&cr->current_source.solid,
3611
			       CAIRO_COLOR_BLACK);
3612
    _cairo_path_fixed_init (&cr->current_path);
3613
    cairo_matrix_init_identity (&cr->current_ctm);
3614
    cairo_matrix_init_identity (&cr->current_stroke_matrix);
3615
    cairo_matrix_init_identity (&cr->current_font_matrix);
3616
    _cairo_font_options_init_default (&cr->current_font_options);
3617
    cr->current_scaled_font = NULL;
3618
    cr->has_clip = FALSE;
3619
}
3620
 
3621
static void
3622
_cairo_script_implicit_context_reset (cairo_script_implicit_context_t *cr)
3623
{
3624
    free (cr->current_style.dash);
3625
    cr->current_style.dash = NULL;
3626
 
3627
    _cairo_pattern_fini (&cr->current_source.base);
3628
    _cairo_path_fixed_fini (&cr->current_path);
3629
 
3630
    _cairo_script_implicit_context_init (cr);
3631
}
3632
 
3633
static cairo_script_surface_t *
3634
_cairo_script_surface_create_internal (cairo_script_context_t *ctx,
3635
				       cairo_content_t content,
3636
				       cairo_rectangle_t *extents,
3637
				       cairo_surface_t *passthrough)
3638
{
3639
    cairo_script_surface_t *surface;
3640
 
3641
    if (unlikely (ctx == NULL))
3642
	return (cairo_script_surface_t *) _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NULL_POINTER));
3643
 
3644
    surface = malloc (sizeof (cairo_script_surface_t));
3645
    if (unlikely (surface == NULL))
3646
	return (cairo_script_surface_t *) _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
3647
 
3648
    _cairo_surface_init (&surface->base,
3649
			 &_cairo_script_surface_backend,
3650
			 &ctx->base,
3651
			 content);
3652
 
3653
    _cairo_surface_wrapper_init (&surface->wrapper, passthrough);
3654
 
3655
    _cairo_surface_clipper_init (&surface->clipper,
3656
				 _cairo_script_surface_clipper_intersect_clip_path);
3657
 
3658
    surface->width = surface->height = -1;
3659
    if (extents) {
3660
	surface->width = extents->width;
3661
	surface->height = extents->height;
3662
	cairo_surface_set_device_offset (&surface->base,
3663
					 -extents->x, -extents->y);
3664
    }
3665
 
3666
    surface->emitted = FALSE;
3667
    surface->defined = FALSE;
3668
    surface->active = FALSE;
3669
    surface->operand.type = SURFACE;
3670
    cairo_list_init (&surface->operand.link);
3671
 
3672
    _cairo_script_implicit_context_init (&surface->cr);
3673
 
3674
    return surface;
3675
}
3676
 
3677
static const cairo_device_backend_t _cairo_script_device_backend = {
3678
    CAIRO_DEVICE_TYPE_SCRIPT,
3679
 
3680
    NULL, NULL, /* lock, unlock */
3681
 
3682
    _device_flush,  /* flush */
3683
    NULL,  /* finish */
3684
    _device_destroy
3685
};
3686
 
3687
cairo_device_t *
3688
_cairo_script_context_create_internal (cairo_output_stream_t *stream)
3689
{
3690
    cairo_script_context_t *ctx;
3691
 
3692
    ctx = malloc (sizeof (cairo_script_context_t));
3693
    if (unlikely (ctx == NULL))
3694
	return _cairo_device_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
3695
 
3696
    memset (ctx, 0, sizeof (cairo_script_context_t));
3697
 
3698
    _cairo_device_init (&ctx->base, &_cairo_script_device_backend);
3699
 
3700
    cairo_list_init (&ctx->operands);
3701
    cairo_list_init (&ctx->deferred);
3702
    ctx->stream = stream;
3703
    ctx->mode = CAIRO_SCRIPT_MODE_ASCII;
3704
 
3705
    cairo_list_init (&ctx->fonts);
3706
    cairo_list_init (&ctx->defines);
3707
 
3708
    ctx->attach_snapshots = TRUE;
3709
 
3710
    return &ctx->base;
3711
}
3712
 
3713
void
3714
_cairo_script_context_attach_snapshots (cairo_device_t *device,
3715
					cairo_bool_t enable)
3716
{
3717
    cairo_script_context_t *ctx;
3718
 
3719
    ctx = (cairo_script_context_t *) device;
3720
    ctx->attach_snapshots = enable;
3721
}
3722
 
3723
static cairo_device_t *
3724
_cairo_script_context_create (cairo_output_stream_t *stream)
3725
{
3726
    cairo_script_context_t *ctx;
3727
 
3728
    ctx = (cairo_script_context_t *)
3729
	_cairo_script_context_create_internal (stream);
3730
    if (unlikely (ctx->base.status))
3731
	return &ctx->base;
3732
 
3733
    ctx->owns_stream = TRUE;
3734
    _cairo_output_stream_puts (ctx->stream, "%!CairoScript\n");
3735
    return &ctx->base;
3736
}
3737
 
3738
/**
3739
 * cairo_script_create:
3740
 * @filename: the name (path) of the file to write the script to
3741
 *
3742
 * Creates a output device for emitting the script, used when
3743
 * creating the individual surfaces.
3744
 *
3745
 * Return value: a pointer to the newly created device. The caller
3746
 * owns the surface and should call cairo_device_destroy() when done
3747
 * with it.
3748
 *
3749
 * This function always returns a valid pointer, but it will return a
3750
 * pointer to a "nil" device if an error such as out of memory
3751
 * occurs. You can use cairo_device_status() to check for this.
3752
 *
3753
 * Since: 1.12
3754
 **/
3755
cairo_device_t *
3756
cairo_script_create (const char *filename)
3757
{
3758
    cairo_output_stream_t *stream;
3759
    cairo_status_t status;
3760
 
3761
    stream = _cairo_output_stream_create_for_filename (filename);
3762
    if ((status = _cairo_output_stream_get_status (stream)))
3763
	return _cairo_device_create_in_error (status);
3764
 
3765
    return _cairo_script_context_create (stream);
3766
}
3767
 
3768
/**
3769
 * cairo_script_create_for_stream:
3770
 * @write_func: callback function passed the bytes written to the script
3771
 * @closure: user data to be passed to the callback
3772
 *
3773
 * Creates a output device for emitting the script, used when
3774
 * creating the individual surfaces.
3775
 *
3776
 * Return value: a pointer to the newly created device. The caller
3777
 * owns the surface and should call cairo_device_destroy() when done
3778
 * with it.
3779
 *
3780
 * This function always returns a valid pointer, but it will return a
3781
 * pointer to a "nil" device if an error such as out of memory
3782
 * occurs. You can use cairo_device_status() to check for this.
3783
 *
3784
 * Since: 1.12
3785
 **/
3786
cairo_device_t *
3787
cairo_script_create_for_stream (cairo_write_func_t	 write_func,
3788
				void			*closure)
3789
{
3790
    cairo_output_stream_t *stream;
3791
    cairo_status_t status;
3792
 
3793
    stream = _cairo_output_stream_create (write_func, NULL, closure);
3794
    if ((status = _cairo_output_stream_get_status (stream)))
3795
	return _cairo_device_create_in_error (status);
3796
 
3797
    return _cairo_script_context_create (stream);
3798
}
3799
 
3800
/**
3801
 * cairo_script_write_comment:
3802
 * @script: the script (output device)
3803
 * @comment: the string to emit
3804
 * @len:the length of the sting to write, or -1 to use strlen()
3805
 *
3806
 * Emit a string verbatim into the script.
3807
 *
3808
 * Since: 1.12
3809
 **/
3810
void
3811
cairo_script_write_comment (cairo_device_t *script,
3812
			    const char *comment,
3813
			    int len)
3814
{
3815
    cairo_script_context_t *context = (cairo_script_context_t *) script;
3816
 
3817
    if (len < 0)
3818
	len = strlen (comment);
3819
 
3820
    _cairo_output_stream_puts (context->stream, "% ");
3821
    _cairo_output_stream_write (context->stream, comment, len);
3822
    _cairo_output_stream_puts (context->stream, "\n");
3823
}
3824
 
3825
/**
3826
 * cairo_script_set_mode:
3827
 * @script: The script (output device)
3828
 * @mode: the new mode
3829
 *
3830
 * Change the output mode of the script
3831
 *
3832
 * Since: 1.12
3833
 **/
3834
void
3835
cairo_script_set_mode (cairo_device_t *script,
3836
		       cairo_script_mode_t mode)
3837
{
3838
    cairo_script_context_t *context = (cairo_script_context_t *) script;
3839
 
3840
    context->mode = mode;
3841
}
3842
 
3843
/**
3844
 * cairo_script_get_mode:
3845
 * @script: The script (output device) to query
3846
 *
3847
 * Queries the script for its current output mode.
3848
 *
3849
 * Return value: the current output mode of the script
3850
 *
3851
 * Since: 1.12
3852
 **/
3853
cairo_script_mode_t
3854
cairo_script_get_mode (cairo_device_t *script)
3855
{
3856
    cairo_script_context_t *context = (cairo_script_context_t *) script;
3857
 
3858
    return context->mode;
3859
}
3860
 
3861
/**
3862
 * cairo_script_surface_create:
3863
 * @script: the script (output device)
3864
 * @content: the content of the surface
3865
 * @width: width in pixels
3866
 * @height: height in pixels
3867
 *
3868
 * Create a new surface that will emit its rendering through @script
3869
 *
3870
 * Return value: a pointer to the newly created surface. The caller
3871
 * owns the surface and should call cairo_surface_destroy() when done
3872
 * with it.
3873
 *
3874
 * This function always returns a valid pointer, but it will return a
3875
 * pointer to a "nil" surface if an error such as out of memory
3876
 * occurs. You can use cairo_surface_status() to check for this.
3877
 *
3878
 * Since: 1.12
3879
 **/
3880
cairo_surface_t *
3881
cairo_script_surface_create (cairo_device_t *script,
3882
			     cairo_content_t content,
3883
			     double width,
3884
			     double height)
3885
{
3886
    cairo_rectangle_t *extents, r;
3887
 
3888
    if (unlikely (script->backend->type != CAIRO_DEVICE_TYPE_SCRIPT))
3889
	return _cairo_surface_create_in_error (CAIRO_STATUS_DEVICE_TYPE_MISMATCH);
3890
 
3891
    if (unlikely (script->status))
3892
	return _cairo_surface_create_in_error (script->status);
3893
 
3894
    extents = NULL;
3895
    if (width > 0 && height > 0) {
3896
	r.x = r.y = 0;
3897
	r.width  = width;
3898
	r.height = height;
3899
	extents = &r;
3900
    }
3901
    return &_cairo_script_surface_create_internal ((cairo_script_context_t *) script,
3902
						   content, extents,
3903
						   NULL)->base;
3904
}
3905
slim_hidden_def (cairo_script_surface_create);
3906
 
3907
/**
3908
 * cairo_script_surface_create_for_target:
3909
 * @script: the script (output device)
3910
 * @target: a target surface to wrap
3911
 *
3912
 * Create a pxoy surface that will render to @target and record
3913
 * the operations to @device.
3914
 *
3915
 * Return value: a pointer to the newly created surface. The caller
3916
 * owns the surface and should call cairo_surface_destroy() when done
3917
 * with it.
3918
 *
3919
 * This function always returns a valid pointer, but it will return a
3920
 * pointer to a "nil" surface if an error such as out of memory
3921
 * occurs. You can use cairo_surface_status() to check for this.
3922
 *
3923
 * Since: 1.12
3924
 **/
3925
cairo_surface_t *
3926
cairo_script_surface_create_for_target (cairo_device_t *script,
3927
					cairo_surface_t *target)
3928
{
3929
    cairo_rectangle_int_t extents;
3930
    cairo_rectangle_t rect, *r;
3931
 
3932
    if (unlikely (script->backend->type != CAIRO_DEVICE_TYPE_SCRIPT))
3933
	return _cairo_surface_create_in_error (CAIRO_STATUS_DEVICE_TYPE_MISMATCH);
3934
 
3935
    if (unlikely (script->status))
3936
	return _cairo_surface_create_in_error (script->status);
3937
 
3938
    if (unlikely (target->status))
3939
	return _cairo_surface_create_in_error (target->status);
3940
 
3941
    r = NULL;
3942
    if (_cairo_surface_get_extents (target, &extents)) {
3943
	rect.x = rect.y = 0;
3944
	rect.width = extents.width;
3945
	rect.height = extents.height;
3946
	r= ▭
3947
    }
3948
    return &_cairo_script_surface_create_internal ((cairo_script_context_t *) script,
3949
						   target->content, r,
3950
						   target)->base;
3951
}
3952
 
3953
/**
3954
 * cairo_script_from_recording_surface:
3955
 * @script: the script (output device)
3956
 * @recording_surface: the recording surface to replay
3957
 *
3958
 * Converts the record operations in @recording_surface into a script.
3959
 *
3960
 * Return value: #CAIRO_STATUS_SUCCESS on successful completion or an error code.
3961
 *
3962
 * Since: 1.12
3963
 **/
3964
cairo_status_t
3965
cairo_script_from_recording_surface (cairo_device_t *script,
3966
				     cairo_surface_t *recording_surface)
3967
{
3968
    cairo_rectangle_t r, *extents;
3969
    cairo_surface_t *surface;
3970
    cairo_status_t status;
3971
 
3972
    if (unlikely (script->backend->type != CAIRO_DEVICE_TYPE_SCRIPT))
3973
	return _cairo_error (CAIRO_STATUS_DEVICE_TYPE_MISMATCH);
3974
 
3975
    if (unlikely (script->status))
3976
	return _cairo_error (script->status);
3977
 
3978
    if (unlikely (recording_surface->status))
3979
	return recording_surface->status;
3980
 
3981
    if (unlikely (! _cairo_surface_is_recording (recording_surface)))
3982
	return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
3983
 
3984
    extents = NULL;
3985
    if (_cairo_recording_surface_get_bounds (recording_surface, &r))
3986
	extents = &r;
3987
 
3988
    surface = &_cairo_script_surface_create_internal ((cairo_script_context_t *) script,
3989
						      recording_surface->content,
3990
						      extents,
3991
						      NULL)->base;
3992
    if (unlikely (surface->status))
3993
	return surface->status;
3994
 
3995
    status = _cairo_recording_surface_replay (recording_surface, surface);
3996
    cairo_surface_destroy (surface);
3997
 
3998
    return status;
3999
}