Coverage Report

Created: 2025-07-12 07:23

/src/cairo/src/cairo-shape-mask-compositor.c
Line
Count
Source (jump to first uncovered line)
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 © 2012 Intel Corporation
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 University of Southern
32
 * California.
33
 *
34
 * Contributor(s):
35
 *  Chris Wilson <chris@chris-wilson.co.uk>
36
 */
37
38
#include "cairoint.h"
39
40
#include "cairo-compositor-private.h"
41
#include "cairo-clip-private.h"
42
#include "cairo-pattern-private.h"
43
#include "cairo-surface-private.h"
44
#include "cairo-surface-offset-private.h"
45
46
static cairo_int_status_t
47
_cairo_shape_mask_compositor_stroke (const cairo_compositor_t *_compositor,
48
             cairo_composite_rectangles_t *extents,
49
             const cairo_path_fixed_t *path,
50
             const cairo_stroke_style_t *style,
51
             const cairo_matrix_t *ctm,
52
             const cairo_matrix_t *ctm_inverse,
53
             double    tolerance,
54
             cairo_antialias_t   antialias)
55
0
{
56
0
    cairo_surface_t *mask;
57
0
    cairo_surface_pattern_t pattern;
58
0
    cairo_int_status_t status;
59
0
    cairo_clip_t *clip;
60
61
0
    if (! extents->is_bounded)
62
0
  return CAIRO_INT_STATUS_UNSUPPORTED;
63
64
0
    TRACE ((stderr, "%s\n", __FUNCTION__));
65
0
    mask = _cairo_surface_create_scratch (extents->surface,
66
0
            CAIRO_CONTENT_ALPHA,
67
0
            extents->bounded.width,
68
0
            extents->bounded.height,
69
0
            NULL);
70
0
    if (unlikely (mask->status))
71
0
  return mask->status;
72
73
0
    clip = extents->clip;
74
0
    if (! _cairo_clip_is_region (clip))
75
0
  clip = _cairo_clip_copy_region (clip);
76
77
0
    if (! mask->is_clear) {
78
0
  status = _cairo_surface_offset_paint (mask,
79
0
                extents->bounded.x,
80
0
                extents->bounded.y,
81
0
                CAIRO_OPERATOR_CLEAR,
82
0
                &_cairo_pattern_clear.base,
83
0
                clip);
84
0
  if (unlikely (status))
85
0
      goto error;
86
0
    }
87
88
0
    status = _cairo_surface_offset_stroke (mask,
89
0
             extents->bounded.x,
90
0
             extents->bounded.y,
91
0
             CAIRO_OPERATOR_ADD,
92
0
             &_cairo_pattern_white.base,
93
0
             path, style, ctm, ctm_inverse,
94
0
             tolerance, antialias,
95
0
             clip);
96
0
    if (unlikely (status))
97
0
  goto error;
98
99
0
    if (clip != extents->clip) {
100
0
  status = _cairo_clip_combine_with_surface (extents->clip, mask,
101
0
               extents->bounded.x,
102
0
               extents->bounded.y);
103
0
  if (unlikely (status))
104
0
      goto error;
105
0
    }
106
107
0
    _cairo_pattern_init_for_surface (&pattern, mask);
108
0
    cairo_matrix_init_translate (&pattern.base.matrix,
109
0
         -extents->bounded.x,
110
0
         -extents->bounded.y);
111
0
    pattern.base.filter = CAIRO_FILTER_NEAREST;
112
0
    pattern.base.extend = CAIRO_EXTEND_NONE;
113
0
    if (extents->op == CAIRO_OPERATOR_SOURCE) {
114
0
  status = _cairo_surface_mask (extents->surface,
115
0
              CAIRO_OPERATOR_DEST_OUT,
116
0
              &_cairo_pattern_white.base,
117
0
              &pattern.base,
118
0
              clip);
119
0
  if (status == CAIRO_INT_STATUS_SUCCESS) {
120
0
      status = _cairo_surface_mask (extents->surface,
121
0
            CAIRO_OPERATOR_ADD,
122
0
            &extents->source_pattern.base,
123
0
            &pattern.base,
124
0
            clip);
125
0
  }
126
0
    } else {
127
0
  status = _cairo_surface_mask (extents->surface,
128
0
              extents->op,
129
0
              &extents->source_pattern.base,
130
0
              &pattern.base,
131
0
              clip);
132
0
    }
133
0
    _cairo_pattern_fini (&pattern.base);
134
135
0
error:
136
0
    cairo_surface_destroy (mask);
137
0
    if (clip != extents->clip)
138
0
  _cairo_clip_destroy (clip);
139
0
    return status;
140
0
}
141
142
static cairo_int_status_t
143
_cairo_shape_mask_compositor_fill (const cairo_compositor_t *_compositor,
144
           cairo_composite_rectangles_t *extents,
145
           const cairo_path_fixed_t *path,
146
           cairo_fill_rule_t   fill_rule,
147
           double      tolerance,
148
           cairo_antialias_t   antialias)
149
0
{
150
0
    cairo_surface_t *mask;
151
0
    cairo_surface_pattern_t pattern;
152
0
    cairo_int_status_t status;
153
0
    cairo_clip_t *clip;
154
155
0
    TRACE ((stderr, "%s\n", __FUNCTION__));
156
157
0
    if (! extents->is_bounded)
158
0
  return CAIRO_INT_STATUS_UNSUPPORTED;
159
160
0
    mask = _cairo_surface_create_scratch (extents->surface,
161
0
            CAIRO_CONTENT_ALPHA,
162
0
            extents->bounded.width,
163
0
            extents->bounded.height,
164
0
            NULL);
165
0
    if (unlikely (mask->status))
166
0
  return mask->status;
167
168
0
    clip = extents->clip;
169
0
    if (! _cairo_clip_is_region (clip))
170
0
  clip = _cairo_clip_copy_region (clip);
171
172
0
    if (! mask->is_clear) {
173
0
  status = _cairo_surface_offset_paint (mask,
174
0
                extents->bounded.x,
175
0
                extents->bounded.y,
176
0
                CAIRO_OPERATOR_CLEAR,
177
0
                &_cairo_pattern_clear.base,
178
0
                clip);
179
0
  if (unlikely (status))
180
0
      goto error;
181
0
    }
182
183
0
    status = _cairo_surface_offset_fill (mask,
184
0
           extents->bounded.x,
185
0
           extents->bounded.y,
186
0
           CAIRO_OPERATOR_ADD,
187
0
           &_cairo_pattern_white.base,
188
0
           path, fill_rule, tolerance, antialias,
189
0
           clip);
190
0
    if (unlikely (status))
191
0
  goto error;
192
193
0
    if (clip != extents->clip) {
194
0
  status = _cairo_clip_combine_with_surface (extents->clip, mask,
195
0
               extents->bounded.x,
196
0
               extents->bounded.y);
197
0
  if (unlikely (status))
198
0
      goto error;
199
0
    }
200
201
0
    _cairo_pattern_init_for_surface (&pattern, mask);
202
0
    cairo_matrix_init_translate (&pattern.base.matrix,
203
0
         -extents->bounded.x,
204
0
         -extents->bounded.y);
205
0
    pattern.base.filter = CAIRO_FILTER_NEAREST;
206
0
    pattern.base.extend = CAIRO_EXTEND_NONE;
207
0
    if (extents->op == CAIRO_OPERATOR_SOURCE) {
208
0
  status = _cairo_surface_mask (extents->surface,
209
0
              CAIRO_OPERATOR_DEST_OUT,
210
0
              &_cairo_pattern_white.base,
211
0
              &pattern.base,
212
0
              clip);
213
0
  if (status == CAIRO_INT_STATUS_SUCCESS) {
214
0
      status = _cairo_surface_mask (extents->surface,
215
0
            CAIRO_OPERATOR_ADD,
216
0
            &extents->source_pattern.base,
217
0
            &pattern.base,
218
0
            clip);
219
0
  }
220
0
    } else {
221
0
  status = _cairo_surface_mask (extents->surface,
222
0
              extents->op,
223
0
              &extents->source_pattern.base,
224
0
              &pattern.base,
225
0
              clip);
226
0
    }
227
0
    _cairo_pattern_fini (&pattern.base);
228
229
0
error:
230
0
    if (clip != extents->clip)
231
0
  _cairo_clip_destroy (clip);
232
0
    cairo_surface_destroy (mask);
233
0
    return status;
234
0
}
235
236
static cairo_int_status_t
237
_cairo_shape_mask_compositor_glyphs (const cairo_compositor_t *_compositor,
238
             cairo_composite_rectangles_t *extents,
239
             cairo_scaled_font_t  *scaled_font,
240
             cairo_glyph_t    *glyphs,
241
             int       num_glyphs,
242
             cairo_bool_t    overlap)
243
0
{
244
0
    cairo_surface_t *mask;
245
0
    cairo_surface_pattern_t pattern;
246
0
    cairo_int_status_t status;
247
0
    cairo_clip_t *clip;
248
249
0
    if (! extents->is_bounded)
250
0
  return CAIRO_INT_STATUS_UNSUPPORTED;
251
252
0
    TRACE ((stderr, "%s\n", __FUNCTION__));
253
0
    mask = _cairo_surface_create_scratch (extents->surface,
254
0
            CAIRO_CONTENT_ALPHA,
255
0
            extents->bounded.width,
256
0
            extents->bounded.height,
257
0
            NULL);
258
0
    if (unlikely (mask->status))
259
0
  return mask->status;
260
261
0
    clip = extents->clip;
262
0
    if (! _cairo_clip_is_region (clip))
263
0
  clip = _cairo_clip_copy_region (clip);
264
265
0
    if (! mask->is_clear) {
266
0
  status = _cairo_surface_offset_paint (mask,
267
0
                extents->bounded.x,
268
0
                extents->bounded.y,
269
0
                CAIRO_OPERATOR_CLEAR,
270
0
                &_cairo_pattern_clear.base,
271
0
                clip);
272
0
  if (unlikely (status))
273
0
      goto error;
274
0
    }
275
276
0
    status = _cairo_surface_offset_glyphs (mask,
277
0
             extents->bounded.x,
278
0
             extents->bounded.y,
279
0
             CAIRO_OPERATOR_ADD,
280
0
             &_cairo_pattern_white.base,
281
0
             scaled_font, glyphs, num_glyphs,
282
0
             clip);
283
0
    if (unlikely (status))
284
0
  goto error;
285
286
0
    if (clip != extents->clip) {
287
0
  status = _cairo_clip_combine_with_surface (extents->clip, mask,
288
0
               extents->bounded.x,
289
0
               extents->bounded.y);
290
0
  if (unlikely (status))
291
0
      goto error;
292
0
    }
293
294
0
    _cairo_pattern_init_for_surface (&pattern, mask);
295
0
    cairo_matrix_init_translate (&pattern.base.matrix,
296
0
         -extents->bounded.x,
297
0
         -extents->bounded.y);
298
0
    pattern.base.filter = CAIRO_FILTER_NEAREST;
299
0
    pattern.base.extend = CAIRO_EXTEND_NONE;
300
0
    if (extents->op == CAIRO_OPERATOR_SOURCE) {
301
0
  status = _cairo_surface_mask (extents->surface,
302
0
              CAIRO_OPERATOR_DEST_OUT,
303
0
              &_cairo_pattern_white.base,
304
0
              &pattern.base,
305
0
              clip);
306
0
  if (status == CAIRO_INT_STATUS_SUCCESS) {
307
0
      status = _cairo_surface_mask (extents->surface,
308
0
            CAIRO_OPERATOR_ADD,
309
0
            &extents->source_pattern.base,
310
0
            &pattern.base,
311
0
            clip);
312
0
  }
313
0
    } else {
314
0
  status = _cairo_surface_mask (extents->surface,
315
0
              extents->op,
316
0
              &extents->source_pattern.base,
317
0
              &pattern.base,
318
0
              clip);
319
0
    }
320
0
    _cairo_pattern_fini (&pattern.base);
321
322
0
error:
323
0
    if (clip != extents->clip)
324
0
  _cairo_clip_destroy (clip);
325
0
    cairo_surface_destroy (mask);
326
0
    return status;
327
0
}
328
329
void
330
_cairo_shape_mask_compositor_init (cairo_compositor_t *compositor,
331
           const cairo_compositor_t  *delegate)
332
2
{
333
2
    compositor->delegate = delegate;
334
335
2
    compositor->paint  = NULL;
336
2
    compositor->mask   = NULL;
337
2
    compositor->fill   = _cairo_shape_mask_compositor_fill;
338
2
    compositor->stroke = _cairo_shape_mask_compositor_stroke;
339
2
    compositor->glyphs = _cairo_shape_mask_compositor_glyphs;
340
2
}