1
/* cairo - a vector graphics library with display and print output
2
 *
3
 * Copyright © 2005 Red Hat, Inc
4
 * Copyright © 2007 Adrian Johnson
5
 * Copyright © 2009 Chris Wilson
6
 *
7
 * This library is free software; you can redistribute it and/or
8
 * modify it either under the terms of the GNU Lesser General Public
9
 * License version 2.1 as published by the Free Software Foundation
10
 * (the "LGPL") or, at your option, under the terms of the Mozilla
11
 * Public License Version 1.1 (the "MPL"). If you do not alter this
12
 * notice, a recipient may use your version of this file under either
13
 * the MPL or the LGPL.
14
 *
15
 * You should have received a copy of the LGPL along with this library
16
 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
17
 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
18
 * You should have received a copy of the MPL along with this library
19
 * in the file COPYING-MPL-1.1
20
 *
21
 * The contents of this file are subject to the Mozilla Public License
22
 * Version 1.1 (the "License"); you may not use this file except in
23
 * compliance with the License. You may obtain a copy of the License at
24
 * http://www.mozilla.org/MPL/
25
 *
26
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
27
 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
28
 * the specific language governing rights and limitations.
29
 *
30
 * The Original Code is the cairo graphics library.
31
 *
32
 * The Initial Developer of the Original Code is Red Hat, Inc.
33
 *
34
 * Contributor(s):
35
 *      Chris Wilson <chris@chris-wilson.co.uk>
36
 */
37

            
38
#include "cairoint.h"
39

            
40
#include "cairo-clip-inline.h"
41
#include "cairo-error-private.h"
42
#include "cairo-pattern-private.h"
43
#include "cairo-surface-offset-private.h"
44

            
45
/* A collection of routines to facilitate drawing to an alternate surface. */
46

            
47
static void
48
87
_copy_transformed_pattern (cairo_pattern_t *pattern,
49
			   const cairo_pattern_t *original,
50
			   const cairo_matrix_t  *ctm_inverse)
51
{
52
87
    _cairo_pattern_init_static_copy (pattern, original);
53

            
54
87
    if (! _cairo_matrix_is_identity (ctm_inverse))
55
87
	_cairo_pattern_transform (pattern, ctm_inverse);
56
87
}
57

            
58
cairo_status_t
59
3
_cairo_surface_offset_paint (cairo_surface_t		*target,
60
			     int x, int y,
61
			     cairo_operator_t		 op,
62
			     const cairo_pattern_t	*source,
63
			     const cairo_clip_t		*clip)
64
{
65
    cairo_status_t status;
66
3
    cairo_clip_t *dev_clip = (cairo_clip_t *) clip;
67
    cairo_pattern_union_t source_copy;
68

            
69
3
    if (unlikely (target->status))
70
	return target->status;
71

            
72
3
    if (_cairo_clip_is_all_clipped (clip))
73
	return CAIRO_STATUS_SUCCESS;
74

            
75
3
    if (x | y) {
76
	cairo_matrix_t m;
77

            
78
3
	dev_clip = _cairo_clip_copy_with_translation (clip, -x, -y);
79

            
80
3
	cairo_matrix_init_translate (&m, x, y);
81
3
	_copy_transformed_pattern (&source_copy.base, source, &m);
82
3
	source = &source_copy.base;
83
    }
84

            
85
3
    status = _cairo_surface_paint (target, op, source, dev_clip);
86

            
87
3
    if (dev_clip != clip)
88
3
	_cairo_clip_destroy (dev_clip);
89

            
90
3
    return status;
91
}
92

            
93
cairo_status_t
94
_cairo_surface_offset_mask (cairo_surface_t		*target,
95
			    int x, int y,
96
			    cairo_operator_t		 op,
97
			    const cairo_pattern_t	*source,
98
			    const cairo_pattern_t	*mask,
99
			    const cairo_clip_t		*clip)
100
{
101
    cairo_status_t status;
102
    cairo_clip_t *dev_clip = (cairo_clip_t *) clip;
103
    cairo_pattern_union_t source_copy;
104
    cairo_pattern_union_t mask_copy;
105

            
106
    if (unlikely (target->status))
107
	return target->status;
108

            
109
    if (_cairo_clip_is_all_clipped (clip))
110
	return CAIRO_STATUS_SUCCESS;
111

            
112
    if (x | y) {
113
	cairo_matrix_t m;
114

            
115
	dev_clip = _cairo_clip_copy_with_translation (clip, -x, -y);
116

            
117
	cairo_matrix_init_translate (&m, x, y);
118
	_copy_transformed_pattern (&source_copy.base, source, &m);
119
	_copy_transformed_pattern (&mask_copy.base, mask, &m);
120
	source = &source_copy.base;
121
	mask = &mask_copy.base;
122
    }
123

            
124
    status = _cairo_surface_mask (target, op,
125
				  source, mask,
126
				  dev_clip);
127

            
128
    if (dev_clip != clip)
129
	_cairo_clip_destroy (dev_clip);
130

            
131
    return status;
132
}
133

            
134
cairo_status_t
135
_cairo_surface_offset_stroke (cairo_surface_t		*surface,
136
			      int x, int y,
137
			      cairo_operator_t		 op,
138
			      const cairo_pattern_t	*source,
139
			      const cairo_path_fixed_t	*path,
140
			      const cairo_stroke_style_t*stroke_style,
141
			      const cairo_matrix_t	*ctm,
142
			      const cairo_matrix_t	*ctm_inverse,
143
			      double			 tolerance,
144
			      cairo_antialias_t		 antialias,
145
			      const cairo_clip_t		*clip)
146
{
147
    cairo_path_fixed_t path_copy, *dev_path = (cairo_path_fixed_t *) path;
148
    cairo_clip_t *dev_clip = (cairo_clip_t *) clip;
149
    cairo_matrix_t dev_ctm = *ctm;
150
    cairo_matrix_t dev_ctm_inverse = *ctm_inverse;
151
    cairo_pattern_union_t source_copy;
152
    cairo_status_t status;
153

            
154
    if (unlikely (surface->status))
155
	return surface->status;
156

            
157
    if (_cairo_clip_is_all_clipped (clip))
158
	return CAIRO_STATUS_SUCCESS;
159

            
160
    if (x | y) {
161
	cairo_matrix_t m;
162

            
163
	dev_clip = _cairo_clip_copy_with_translation (clip, -x, -y);
164

            
165
	status = _cairo_path_fixed_init_copy (&path_copy, dev_path);
166
	if (unlikely (status))
167
	    goto FINISH;
168

            
169
	_cairo_path_fixed_translate (&path_copy,
170
				     _cairo_fixed_from_int (-x),
171
				     _cairo_fixed_from_int (-y));
172
	dev_path = &path_copy;
173

            
174
	cairo_matrix_init_translate (&m, -x, -y);
175
	cairo_matrix_multiply (&dev_ctm, &dev_ctm, &m);
176

            
177
	cairo_matrix_init_translate (&m, x, y);
178
	_copy_transformed_pattern (&source_copy.base, source, &m);
179
	source = &source_copy.base;
180
	cairo_matrix_multiply (&dev_ctm_inverse, &m, &dev_ctm_inverse);
181
    }
182

            
183
    status = _cairo_surface_stroke (surface, op, source,
184
				    dev_path, stroke_style,
185
				    &dev_ctm, &dev_ctm_inverse,
186
				    tolerance, antialias,
187
				    dev_clip);
188

            
189
FINISH:
190
    if (dev_path != path)
191
	_cairo_path_fixed_fini (dev_path);
192
    if (dev_clip != clip)
193
	_cairo_clip_destroy (dev_clip);
194

            
195
    return status;
196
}
197

            
198
cairo_status_t
199
60
_cairo_surface_offset_fill (cairo_surface_t	*surface,
200
			    int x, int y,
201
			    cairo_operator_t	 op,
202
			    const cairo_pattern_t*source,
203
			    const cairo_path_fixed_t	*path,
204
			    cairo_fill_rule_t	 fill_rule,
205
			    double		 tolerance,
206
			    cairo_antialias_t	 antialias,
207
			    const cairo_clip_t	*clip)
208
{
209
    cairo_status_t status;
210
60
    cairo_path_fixed_t path_copy, *dev_path = (cairo_path_fixed_t *) path;
211
60
    cairo_clip_t *dev_clip = (cairo_clip_t *) clip;
212
    cairo_pattern_union_t source_copy;
213

            
214
60
    if (unlikely (surface->status))
215
	return surface->status;
216

            
217
60
    if (_cairo_clip_is_all_clipped (clip))
218
	return CAIRO_STATUS_SUCCESS;
219

            
220
60
    if (x | y) {
221
	cairo_matrix_t m;
222

            
223
60
	dev_clip = _cairo_clip_copy_with_translation (clip, -x, -y);
224

            
225
60
	status = _cairo_path_fixed_init_copy (&path_copy, dev_path);
226
60
	if (unlikely (status))
227
	    goto FINISH;
228

            
229
60
	_cairo_path_fixed_translate (&path_copy,
230
				     _cairo_fixed_from_int (-x),
231
				     _cairo_fixed_from_int (-y));
232
60
	dev_path = &path_copy;
233

            
234
60
	cairo_matrix_init_translate (&m, x, y);
235
60
	_copy_transformed_pattern (&source_copy.base, source, &m);
236
60
	source = &source_copy.base;
237
    }
238

            
239
60
    status = _cairo_surface_fill (surface, op, source,
240
				  dev_path, fill_rule,
241
				  tolerance, antialias,
242
				  dev_clip);
243

            
244
60
FINISH:
245
60
    if (dev_path != path)
246
60
	_cairo_path_fixed_fini (dev_path);
247
60
    if (dev_clip != clip)
248
60
	_cairo_clip_destroy (dev_clip);
249

            
250
60
    return status;
251
}
252

            
253
cairo_status_t
254
30
_cairo_surface_offset_glyphs (cairo_surface_t		*surface,
255
			      int x, int y,
256
			      cairo_operator_t		 op,
257
			      const cairo_pattern_t	*source,
258
			      cairo_scaled_font_t	*scaled_font,
259
			      cairo_glyph_t		*glyphs,
260
			      int			 num_glyphs,
261
			      const cairo_clip_t	*clip)
262
{
263
    cairo_status_t status;
264
30
    cairo_clip_t *dev_clip = (cairo_clip_t *) clip;
265
    cairo_pattern_union_t source_copy;
266
    cairo_glyph_t *dev_glyphs;
267
    int i;
268

            
269
30
    if (unlikely (surface->status))
270
	return surface->status;
271

            
272
30
    if (_cairo_clip_is_all_clipped (clip))
273
	return CAIRO_STATUS_SUCCESS;
274

            
275
30
    dev_glyphs = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t));
276
30
    if (dev_glyphs == NULL)
277
	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
278

            
279
30
    memcpy (dev_glyphs, glyphs, sizeof (cairo_glyph_t) * num_glyphs);
280

            
281
30
    if (x | y) {
282
	cairo_matrix_t m;
283

            
284
24
	dev_clip = _cairo_clip_copy_with_translation (clip, -x, -y);
285

            
286
24
	cairo_matrix_init_translate (&m, x, y);
287
24
	_copy_transformed_pattern (&source_copy.base, source, &m);
288
24
	source = &source_copy.base;
289

            
290
48
	for (i = 0; i < num_glyphs; i++) {
291
24
	    dev_glyphs[i].x -= x;
292
24
	    dev_glyphs[i].y -= y;
293
	}
294
    }
295

            
296
30
    status = _cairo_surface_show_text_glyphs (surface, op, source,
297
					      NULL, 0,
298
					      dev_glyphs, num_glyphs,
299
					      NULL, 0, 0,
300
					      scaled_font,
301
					      dev_clip);
302

            
303
30
    if (dev_clip != clip)
304
24
	_cairo_clip_destroy (dev_clip);
305
30
    free (dev_glyphs);
306

            
307
30
    return status;
308
}