Coverage Report

Created: 2025-07-23 08:13

/src/cairo/src/cairo-analysis-surface.c
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
2
/*
3
 * Copyright © 2006 Keith Packard
4
 * Copyright © 2007 Adrian Johnson
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 Keith Packard
32
 *
33
 * Contributor(s):
34
 *      Keith Packard <keithp@keithp.com>
35
 *      Adrian Johnson <ajohnson@redneon.com>
36
 */
37
38
#include "cairoint.h"
39
40
#include "cairo-analysis-surface-private.h"
41
#include "cairo-box-inline.h"
42
#include "cairo-default-context-private.h"
43
#include "cairo-error-private.h"
44
#include "cairo-paginated-private.h"
45
#include "cairo-recording-surface-inline.h"
46
#include "cairo-surface-snapshot-inline.h"
47
#include "cairo-surface-subsurface-inline.h"
48
#include "cairo-region-private.h"
49
50
typedef struct {
51
    cairo_surface_t base;
52
53
    cairo_surface_t *target;
54
55
    cairo_bool_t first_op;
56
    cairo_bool_t has_supported;
57
    cairo_bool_t has_unsupported;
58
59
    cairo_region_t supported_region;
60
    cairo_region_t fallback_region;
61
    cairo_box_t page_bbox;
62
63
    cairo_bool_t create_region_ids;
64
    unsigned source_region_id;
65
    unsigned mask_region_id;
66
67
    cairo_bool_t has_ctm;
68
    cairo_matrix_t ctm;
69
70
} cairo_analysis_surface_t;
71
72
cairo_int_status_t
73
_cairo_analysis_surface_merge_status (cairo_int_status_t status_a,
74
              cairo_int_status_t status_b)
75
1.19k
{
76
    /* fatal errors should be checked and propagated at source */
77
1.19k
    assert (! _cairo_int_status_is_error (status_a));
78
1.19k
    assert (! _cairo_int_status_is_error (status_b));
79
80
    /* return the most important status */
81
1.19k
    if (status_a == CAIRO_INT_STATUS_UNSUPPORTED ||
82
1.19k
  status_b == CAIRO_INT_STATUS_UNSUPPORTED)
83
0
  return CAIRO_INT_STATUS_UNSUPPORTED;
84
85
1.19k
    if (status_a == CAIRO_INT_STATUS_IMAGE_FALLBACK ||
86
1.19k
  status_b == CAIRO_INT_STATUS_IMAGE_FALLBACK)
87
0
  return CAIRO_INT_STATUS_IMAGE_FALLBACK;
88
89
1.19k
    if (status_a == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN ||
90
1.19k
  status_b == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN)
91
23
  return CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN;
92
93
1.17k
    if (status_a == CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY ||
94
1.17k
  status_b == CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY)
95
0
  return CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY;
96
97
    /* at this point we have checked all the valid internal codes, so... */
98
1.17k
    assert (status_a == CAIRO_INT_STATUS_SUCCESS &&
99
1.17k
      status_b == CAIRO_INT_STATUS_SUCCESS);
100
101
1.17k
    return CAIRO_INT_STATUS_SUCCESS;
102
1.17k
}
103
104
struct proxy {
105
    cairo_surface_t base;
106
    cairo_surface_t *target;
107
};
108
109
static cairo_status_t
110
proxy_finish (void *abstract_surface)
111
548
{
112
548
    return CAIRO_STATUS_SUCCESS;
113
548
}
114
115
static const cairo_surface_backend_t proxy_backend  = {
116
    CAIRO_INTERNAL_SURFACE_TYPE_NULL,
117
    proxy_finish,
118
};
119
120
static cairo_surface_t *
121
attach_proxy (cairo_surface_t *source,
122
        cairo_surface_t *target)
123
548
{
124
548
    struct proxy *proxy;
125
126
548
    proxy = _cairo_calloc (sizeof (*proxy));
127
548
    if (unlikely (proxy == NULL))
128
0
  return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);
129
130
548
    _cairo_surface_init (&proxy->base, &proxy_backend, NULL, target->content, target->is_vector);
131
132
548
    proxy->target = target;
133
548
    _cairo_surface_attach_snapshot (source, &proxy->base, NULL);
134
135
548
    return &proxy->base;
136
548
}
137
138
static void
139
detach_proxy (cairo_surface_t *proxy)
140
548
{
141
548
    cairo_surface_finish (proxy);
142
548
    cairo_surface_destroy (proxy);
143
548
}
144
145
static cairo_int_status_t
146
_add_operation (cairo_analysis_surface_t *surface,
147
    cairo_rectangle_int_t    *rect,
148
    cairo_int_status_t        backend_status)
149
499k
{
150
499k
    cairo_int_status_t status;
151
499k
    cairo_box_t bbox;
152
153
499k
    if (rect->width == 0 || rect->height == 0) {
154
  /* Even though the operation is not visible we must be careful
155
   * to not allow unsupported operations to be replayed to the
156
   * backend during CAIRO_PAGINATED_MODE_RENDER */
157
13
  if (backend_status == CAIRO_INT_STATUS_SUCCESS ||
158
13
      backend_status == CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY ||
159
13
      backend_status == CAIRO_INT_STATUS_NOTHING_TO_DO)
160
13
  {
161
13
      return CAIRO_INT_STATUS_SUCCESS;
162
13
  }
163
0
  else
164
0
  {
165
0
      return CAIRO_INT_STATUS_IMAGE_FALLBACK;
166
0
  }
167
13
    }
168
169
499k
    _cairo_box_from_rectangle (&bbox, rect);
170
171
499k
    if (surface->has_ctm) {
172
1.22k
  int tx, ty;
173
174
1.22k
  if (_cairo_matrix_is_integer_translation (&surface->ctm, &tx, &ty)) {
175
706
      rect->x += tx;
176
706
      rect->y += ty;
177
178
706
      tx = _cairo_fixed_from_int (tx);
179
706
      bbox.p1.x += tx;
180
706
      bbox.p2.x += tx;
181
182
706
      ty = _cairo_fixed_from_int (ty);
183
706
      bbox.p1.y += ty;
184
706
      bbox.p2.y += ty;
185
706
  } else {
186
518
      _cairo_matrix_transform_bounding_box_fixed (&surface->ctm,
187
518
              &bbox, NULL);
188
189
518
      if (bbox.p1.x == bbox.p2.x || bbox.p1.y == bbox.p2.y) {
190
    /* Even though the operation is not visible we must be
191
     * careful to not allow unsupported operations to be
192
     * replayed to the backend during
193
     * CAIRO_PAGINATED_MODE_RENDER */
194
0
    if (backend_status == CAIRO_INT_STATUS_SUCCESS ||
195
0
        backend_status == CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY ||
196
0
        backend_status == CAIRO_INT_STATUS_NOTHING_TO_DO)
197
0
    {
198
0
        return CAIRO_INT_STATUS_SUCCESS;
199
0
    }
200
0
    else
201
0
    {
202
0
        return CAIRO_INT_STATUS_IMAGE_FALLBACK;
203
0
    }
204
0
      }
205
206
518
      _cairo_box_round_to_rectangle (&bbox, rect);
207
518
  }
208
1.22k
    }
209
210
499k
    if (surface->first_op) {
211
1.09k
  surface->first_op = FALSE;
212
1.09k
  surface->page_bbox = bbox;
213
1.09k
    } else
214
498k
  _cairo_box_add_box(&surface->page_bbox, &bbox);
215
216
    /* If the operation is completely enclosed within the fallback
217
     * region there is no benefit in emitting a native operation as
218
     * the fallback image will be painted on top.
219
     */
220
499k
    if (cairo_region_contains_rectangle (&surface->fallback_region, rect) == CAIRO_REGION_OVERLAP_IN)
221
0
  return CAIRO_INT_STATUS_IMAGE_FALLBACK;
222
223
499k
    if (backend_status == CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY) {
224
  /* A status of CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY indicates
225
   * that the backend only supports this operation if the
226
   * transparency removed. If the extents of this operation does
227
   * not intersect any other native operation, the operation is
228
   * natively supported and the backend will blend the
229
   * transparency into the white background.
230
   */
231
0
  if (cairo_region_contains_rectangle (&surface->supported_region, rect) == CAIRO_REGION_OVERLAP_OUT)
232
0
      backend_status = CAIRO_INT_STATUS_SUCCESS;
233
0
    }
234
235
499k
    if (backend_status == CAIRO_INT_STATUS_SUCCESS) {
236
  /* Add the operation to the supported region. Operations in
237
   * this region will be emitted as native operations.
238
   */
239
499k
  surface->has_supported = TRUE;
240
499k
  return cairo_region_union_rectangle (&surface->supported_region, rect);
241
499k
    }
242
243
    /* Add the operation to the unsupported region. This region will
244
     * be painted as an image after all native operations have been
245
     * emitted.
246
     */
247
0
    surface->has_unsupported = TRUE;
248
0
    status = cairo_region_union_rectangle (&surface->fallback_region, rect);
249
250
    /* The status CAIRO_INT_STATUS_IMAGE_FALLBACK is used to indicate
251
     * unsupported operations to the recording surface as using
252
     * CAIRO_INT_STATUS_UNSUPPORTED would cause cairo-surface to
253
     * invoke the cairo-surface-fallback path then return
254
     * CAIRO_STATUS_SUCCESS.
255
     */
256
0
    if (status == CAIRO_INT_STATUS_SUCCESS)
257
0
  return CAIRO_INT_STATUS_IMAGE_FALLBACK;
258
0
    else
259
0
  return status;
260
0
}
261
262
static cairo_int_status_t
263
_analyze_recording_surface_pattern (cairo_analysis_surface_t *surface,
264
            const cairo_pattern_t    *pattern,
265
            cairo_rectangle_int_t    *extents,
266
            unsigned int             *regions_id,
267
            cairo_analysis_source_t   source_type)
268
548
{
269
548
    const cairo_surface_pattern_t *surface_pattern;
270
548
    cairo_analysis_surface_t *tmp;
271
548
    cairo_surface_t *source, *proxy;
272
548
    cairo_matrix_t p2d;
273
548
    cairo_int_status_t status;
274
548
    cairo_int_status_t analysis_status = CAIRO_INT_STATUS_SUCCESS;
275
548
    cairo_bool_t surface_is_unbounded;
276
548
    cairo_bool_t unused;
277
548
    cairo_bool_t replay_all;
278
279
548
    assert (pattern->type == CAIRO_PATTERN_TYPE_SURFACE);
280
548
    surface_pattern = (const cairo_surface_pattern_t *) pattern;
281
548
    assert (surface_pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING);
282
548
    source = surface_pattern->surface;
283
284
548
    proxy = _cairo_surface_has_snapshot (source, &proxy_backend);
285
548
    if (proxy != NULL) {
286
  /* nothing untoward found so far */
287
0
  return CAIRO_STATUS_SUCCESS;
288
0
    }
289
290
548
    tmp = (cairo_analysis_surface_t *)
291
548
  _cairo_analysis_surface_create (surface->target, surface->create_region_ids);
292
548
    if (unlikely (tmp->base.status)) {
293
0
  status = tmp->base.status;
294
0
  goto cleanup1;
295
0
    }
296
548
    proxy = attach_proxy (source, &tmp->base);
297
298
548
    p2d = pattern->matrix;
299
548
    status = cairo_matrix_invert (&p2d);
300
548
    assert (status == CAIRO_INT_STATUS_SUCCESS);
301
548
    _cairo_analysis_surface_set_ctm (&tmp->base, &p2d);
302
303
548
    source = _cairo_surface_get_source (source, NULL);
304
548
    surface_is_unbounded = (pattern->extend == CAIRO_EXTEND_REPEAT
305
548
          || pattern->extend == CAIRO_EXTEND_REFLECT);
306
307
548
    if (surface->create_region_ids) {
308
548
  status = _cairo_recording_surface_region_array_attach (source, regions_id);
309
548
  if (unlikely (status))
310
0
      goto cleanup2;
311
548
    }
312
313
548
    replay_all = FALSE;
314
548
    if (surface->target->backend->analyze_recording_surface) {
315
548
  status = surface->target->backend->analyze_recording_surface (
316
548
      surface->target,
317
548
      surface_pattern,
318
548
      surface->create_region_ids ? *regions_id : 0,
319
548
      source_type,
320
548
      TRUE);
321
548
        if (status == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN) {
322
      /* Ensure all commands are replayed even if previously
323
       * replayed and assigned to a region.*/
324
0
            replay_all = TRUE;
325
0
            status = CAIRO_INT_STATUS_SUCCESS;
326
0
        }
327
548
        if (unlikely (status))
328
0
            goto cleanup3;
329
548
    }
330
331
548
    if (surface->create_region_ids) {
332
548
  status = _cairo_recording_surface_replay_and_create_regions (source,
333
548
                     *regions_id,
334
548
                     &pattern->matrix,
335
548
                     &tmp->base,
336
548
                     surface_is_unbounded,
337
548
                     replay_all);
338
548
  if (unlikely (status))
339
0
      goto cleanup3;
340
548
    } else {
341
0
  status = _cairo_recording_surface_replay_with_transform (source,
342
0
                 &pattern->matrix,
343
0
                 &tmp->base,
344
0
                 surface_is_unbounded,
345
0
                 replay_all);
346
0
  if (unlikely (status))
347
0
      goto cleanup3;
348
0
    }
349
350
548
    if (surface->target->backend->analyze_recording_surface) {
351
548
  status = surface->target->backend->analyze_recording_surface (
352
548
      surface->target,
353
548
      surface_pattern,
354
548
      surface->create_region_ids ? *regions_id : 0,
355
548
      source_type,
356
548
      FALSE);
357
548
        if (unlikely (status))
358
0
            goto cleanup3;
359
548
    }
360
361
    /* black background or mime data fills entire extents */
362
548
    if (!(source->content & CAIRO_CONTENT_ALPHA) || _cairo_surface_has_mime_image (source)) {
363
0
  cairo_rectangle_int_t rect;
364
365
0
  if (_cairo_surface_get_extents (source, &rect)) {
366
0
      cairo_box_t bbox;
367
368
0
      _cairo_box_from_rectangle (&bbox, &rect);
369
0
      _cairo_matrix_transform_bounding_box_fixed (&p2d, &bbox, NULL);
370
0
      _cairo_box_round_to_rectangle (&bbox, &rect);
371
0
      status = _add_operation (tmp, &rect, CAIRO_INT_STATUS_SUCCESS);
372
0
      if (status == CAIRO_INT_STATUS_IMAGE_FALLBACK)
373
0
    status = CAIRO_INT_STATUS_SUCCESS;
374
0
      if (unlikely (status))
375
0
    goto cleanup3;
376
0
  }
377
0
    }
378
379
548
    if (tmp->has_supported) {
380
548
  surface->has_supported = TRUE;
381
548
  unused = cairo_region_union (&surface->supported_region, &tmp->supported_region);
382
548
    }
383
384
548
    if (tmp->has_unsupported) {
385
0
  surface->has_unsupported = TRUE;
386
0
  unused = cairo_region_union (&surface->fallback_region, &tmp->fallback_region);
387
0
    }
388
389
548
    analysis_status = tmp->has_unsupported ? CAIRO_INT_STATUS_IMAGE_FALLBACK : CAIRO_INT_STATUS_SUCCESS;
390
548
    if (pattern->extend != CAIRO_EXTEND_NONE) {
391
518
  _cairo_unbounded_rectangle_init (extents);
392
518
    } else {
393
30
  status = cairo_matrix_invert (&tmp->ctm);
394
30
  _cairo_matrix_transform_bounding_box_fixed (&tmp->ctm,
395
30
                &tmp->page_bbox, NULL);
396
30
  _cairo_box_round_to_rectangle (&tmp->page_bbox, extents);
397
30
    }
398
399
548
  cleanup3:
400
548
    if (surface->create_region_ids && unlikely (status)) {
401
0
  _cairo_recording_surface_region_array_remove (source, *regions_id);
402
0
    }
403
548
  cleanup2:
404
548
    detach_proxy (proxy);
405
548
  cleanup1:
406
548
    cairo_surface_destroy (&tmp->base);
407
408
548
    if (unlikely (status))
409
0
  return status;
410
548
    else
411
548
  return analysis_status;
412
548
}
413
414
static cairo_status_t
415
_cairo_analysis_surface_finish (void *abstract_surface)
416
2.57k
{
417
2.57k
    cairo_analysis_surface_t  *surface = (cairo_analysis_surface_t *) abstract_surface;
418
419
2.57k
    _cairo_region_fini (&surface->supported_region);
420
2.57k
    _cairo_region_fini (&surface->fallback_region);
421
422
2.57k
    cairo_surface_destroy (surface->target);
423
424
2.57k
    return CAIRO_STATUS_SUCCESS;
425
2.57k
}
426
427
static cairo_bool_t
428
_cairo_analysis_surface_get_extents (void     *abstract_surface,
429
             cairo_rectangle_int_t  *rectangle)
430
499k
{
431
499k
    cairo_analysis_surface_t *surface = abstract_surface;
432
433
499k
    return _cairo_surface_get_extents (surface->target, rectangle);
434
499k
}
435
436
static void
437
_rectangle_intersect_clip (cairo_rectangle_int_t *extents, const cairo_clip_t *clip)
438
499k
{
439
499k
    if (clip != NULL)
440
498k
  _cairo_rectangle_intersect (extents, _cairo_clip_get_extents (clip));
441
499k
}
442
443
static void
444
_cairo_analysis_surface_operation_extents (cairo_analysis_surface_t *surface,
445
             cairo_operator_t op,
446
             const cairo_pattern_t *source,
447
             const cairo_clip_t *clip,
448
             cairo_rectangle_int_t *extents)
449
499k
{
450
499k
    cairo_bool_t is_empty;
451
452
499k
    is_empty = _cairo_surface_get_extents (&surface->base, extents);
453
454
499k
    if (_cairo_operator_bounded_by_source (op)) {
455
498k
  cairo_rectangle_int_t source_extents;
456
457
498k
  _cairo_pattern_get_extents (source, &source_extents, surface->target->is_vector);
458
498k
  _cairo_rectangle_intersect (extents, &source_extents);
459
498k
    }
460
461
499k
    _rectangle_intersect_clip (extents, clip);
462
499k
}
463
464
static cairo_int_status_t
465
_cairo_analysis_surface_paint (void     *abstract_surface,
466
             cairo_operator_t   op,
467
             const cairo_pattern_t  *source,
468
             const cairo_clip_t *clip)
469
333
{
470
333
    cairo_analysis_surface_t *surface = abstract_surface;
471
333
    cairo_int_status_t       backend_status;
472
333
    cairo_rectangle_int_t  extents;
473
474
333
    surface->source_region_id = 0;
475
333
    surface->mask_region_id = 0;
476
333
    if (surface->target->backend->paint == NULL) {
477
0
  backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
478
333
    } else {
479
333
  backend_status =
480
333
      surface->target->backend->paint (surface->target,
481
333
               op, source, clip);
482
333
  if (_cairo_int_status_is_error (backend_status))
483
0
      return backend_status;
484
333
    }
485
486
333
    _cairo_analysis_surface_operation_extents (surface,
487
333
                 op, source, clip,
488
333
                 &extents);
489
333
    if (backend_status == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN) {
490
7
  cairo_rectangle_int_t rec_extents;
491
7
  backend_status = _analyze_recording_surface_pattern (surface,
492
7
                   source,
493
7
                   &rec_extents,
494
7
                   &surface->source_region_id,
495
7
                   CAIRO_ANALYSIS_SOURCE_PAINT);
496
7
  _cairo_rectangle_intersect (&extents, &rec_extents);
497
7
    }
498
499
333
    return _add_operation (surface, &extents, backend_status);
500
333
}
501
502
static cairo_int_status_t
503
_cairo_analysis_surface_mask (void      *abstract_surface,
504
            cairo_operator_t     op,
505
            const cairo_pattern_t *source,
506
            const cairo_pattern_t *mask,
507
            const cairo_clip_t  *clip)
508
1.17k
{
509
1.17k
    cairo_analysis_surface_t *surface = abstract_surface;
510
1.17k
    cairo_int_status_t        backend_status;
511
1.17k
    cairo_rectangle_int_t   extents;
512
513
1.17k
    surface->source_region_id = 0;
514
1.17k
    surface->mask_region_id = 0;
515
1.17k
    if (surface->target->backend->mask == NULL) {
516
0
  backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
517
1.17k
    } else {
518
1.17k
  backend_status =
519
1.17k
      surface->target->backend->mask (surface->target,
520
1.17k
              op, source, mask, clip);
521
1.17k
  if (_cairo_int_status_is_error (backend_status))
522
0
      return backend_status;
523
1.17k
    }
524
525
1.17k
    _cairo_analysis_surface_operation_extents (surface,
526
1.17k
                 op, source, clip,
527
1.17k
                 &extents);
528
1.17k
    if (backend_status == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN) {
529
23
  cairo_int_status_t backend_source_status = CAIRO_STATUS_SUCCESS;
530
23
  cairo_int_status_t backend_mask_status = CAIRO_STATUS_SUCCESS;
531
23
  cairo_rectangle_int_t rec_extents;
532
533
23
  if (source->type == CAIRO_PATTERN_TYPE_SURFACE) {
534
23
      cairo_surface_t *src_surface = ((cairo_surface_pattern_t *)source)->surface;
535
23
      src_surface = _cairo_surface_get_source (src_surface, NULL);
536
23
      if (_cairo_surface_is_recording (src_surface)) {
537
23
    backend_source_status =
538
23
        _analyze_recording_surface_pattern (surface,
539
23
              source,
540
23
              &rec_extents,
541
23
              &surface->source_region_id,
542
23
              CAIRO_ANALYSIS_SOURCE_MASK);
543
23
    if (_cairo_int_status_is_error (backend_source_status))
544
0
        return backend_source_status;
545
546
23
    _cairo_rectangle_intersect (&extents, &rec_extents);
547
23
      }
548
23
  }
549
550
23
  if (mask->type == CAIRO_PATTERN_TYPE_SURFACE) {
551
0
      cairo_surface_t *mask_surface = ((cairo_surface_pattern_t *)mask)->surface;
552
0
      mask_surface = _cairo_surface_get_source (mask_surface, NULL);
553
0
      if (_cairo_surface_is_recording (mask_surface)) {
554
0
    backend_mask_status =
555
0
        _analyze_recording_surface_pattern (surface,
556
0
              mask,
557
0
              &rec_extents,
558
0
              &surface->mask_region_id,
559
0
              CAIRO_ANALYSIS_MASK_MASK);
560
0
    if (_cairo_int_status_is_error (backend_mask_status))
561
0
        return backend_mask_status;
562
563
0
    _cairo_rectangle_intersect (&extents, &rec_extents);
564
0
      }
565
0
  }
566
567
23
  backend_status =
568
23
      _cairo_analysis_surface_merge_status (backend_source_status,
569
23
              backend_mask_status);
570
23
    }
571
572
1.17k
    if (_cairo_operator_bounded_by_mask (op)) {
573
1.17k
  cairo_rectangle_int_t mask_extents;
574
575
1.17k
  _cairo_pattern_get_extents (mask, &mask_extents, surface->target->is_vector);
576
1.17k
  _cairo_rectangle_intersect (&extents, &mask_extents);
577
1.17k
    }
578
579
1.17k
    return _add_operation (surface, &extents, backend_status);
580
1.17k
}
581
582
static cairo_int_status_t
583
_cairo_analysis_surface_stroke (void         *abstract_surface,
584
        cairo_operator_t      op,
585
        const cairo_pattern_t    *source,
586
        const cairo_path_fixed_t   *path,
587
        const cairo_stroke_style_t *style,
588
        const cairo_matrix_t     *ctm,
589
        const cairo_matrix_t     *ctm_inverse,
590
        double          tolerance,
591
        cairo_antialias_t     antialias,
592
        const cairo_clip_t     *clip)
593
7.23k
{
594
7.23k
    cairo_analysis_surface_t *surface = abstract_surface;
595
7.23k
    cairo_int_status_t       backend_status;
596
7.23k
    cairo_rectangle_int_t    extents;
597
598
7.23k
    surface->source_region_id = 0;
599
7.23k
    surface->mask_region_id = 0;
600
7.23k
    if (surface->target->backend->stroke == NULL) {
601
0
  backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
602
7.23k
    } else {
603
7.23k
  backend_status =
604
7.23k
      surface->target->backend->stroke (surface->target, op,
605
7.23k
                source, path, style,
606
7.23k
                ctm, ctm_inverse,
607
7.23k
                tolerance, antialias,
608
7.23k
                clip);
609
7.23k
  if (_cairo_int_status_is_error (backend_status))
610
0
      return backend_status;
611
7.23k
    }
612
613
7.23k
    _cairo_analysis_surface_operation_extents (surface,
614
7.23k
                 op, source, clip,
615
7.23k
                 &extents);
616
7.23k
    if (backend_status == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN) {
617
0
  cairo_rectangle_int_t rec_extents;
618
0
  backend_status = _analyze_recording_surface_pattern (surface,
619
0
                   source,
620
0
                   &rec_extents,
621
0
                   &surface->source_region_id,
622
0
                   CAIRO_ANALYSIS_SOURCE_STROKE);
623
0
  _cairo_rectangle_intersect (&extents, &rec_extents);
624
0
    }
625
626
7.23k
    if (_cairo_operator_bounded_by_mask (op)) {
627
7.23k
  cairo_rectangle_int_t mask_extents;
628
7.23k
  cairo_int_status_t status;
629
630
7.23k
  status = _cairo_path_fixed_stroke_extents (path, style,
631
7.23k
               ctm, ctm_inverse,
632
7.23k
               tolerance,
633
7.23k
               &mask_extents);
634
7.23k
  if (unlikely (status))
635
0
      return status;
636
637
7.23k
  _cairo_rectangle_intersect (&extents, &mask_extents);
638
7.23k
    }
639
640
7.23k
    return _add_operation (surface, &extents, backend_status);
641
7.23k
}
642
643
static cairo_int_status_t
644
_cairo_analysis_surface_fill (void      *abstract_surface,
645
            cairo_operator_t     op,
646
            const cairo_pattern_t *source,
647
            const cairo_path_fixed_t  *path,
648
            cairo_fill_rule_t    fill_rule,
649
            double       tolerance,
650
            cairo_antialias_t    antialias,
651
            const cairo_clip_t  *clip)
652
5.82k
{
653
5.82k
    cairo_analysis_surface_t *surface = abstract_surface;
654
5.82k
    cairo_int_status_t       backend_status;
655
5.82k
    cairo_rectangle_int_t    extents;
656
657
5.82k
    if (surface->target->backend->fill == NULL) {
658
0
  backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
659
5.82k
    } else {
660
5.82k
  backend_status =
661
5.82k
      surface->target->backend->fill (surface->target, op,
662
5.82k
              source, path, fill_rule,
663
5.82k
              tolerance, antialias,
664
5.82k
              clip);
665
5.82k
  if (_cairo_int_status_is_error (backend_status))
666
0
      return backend_status;
667
5.82k
    }
668
669
5.82k
    _cairo_analysis_surface_operation_extents (surface,
670
5.82k
                 op, source, clip,
671
5.82k
                 &extents);
672
5.82k
    if (backend_status == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN) {
673
518
  cairo_rectangle_int_t rec_extents;
674
518
  backend_status = _analyze_recording_surface_pattern (surface,
675
518
                   source,
676
518
                   &rec_extents,
677
518
                   &surface->source_region_id,
678
518
                   CAIRO_ANALYSIS_SOURCE_FILL);
679
518
  _cairo_rectangle_intersect (&extents, &rec_extents);
680
518
    }
681
682
5.82k
    if (_cairo_operator_bounded_by_mask (op)) {
683
5.82k
  cairo_rectangle_int_t mask_extents;
684
685
5.82k
  _cairo_path_fixed_fill_extents (path, fill_rule, tolerance,
686
5.82k
          &mask_extents);
687
688
5.82k
  _cairo_rectangle_intersect (&extents, &mask_extents);
689
5.82k
    }
690
691
5.82k
    return _add_operation (surface, &extents, backend_status);
692
5.82k
}
693
694
static cairo_int_status_t
695
_cairo_analysis_surface_show_glyphs (void     *abstract_surface,
696
             cairo_operator_t    op,
697
             const cairo_pattern_t *source,
698
             cairo_glyph_t    *glyphs,
699
             int       num_glyphs,
700
             cairo_scaled_font_t  *scaled_font,
701
             const cairo_clip_t         *clip)
702
354k
{
703
354k
    cairo_analysis_surface_t *surface = abstract_surface;
704
354k
    cairo_int_status_t       status, backend_status;
705
354k
    cairo_rectangle_int_t    extents, glyph_extents;
706
707
354k
    surface->source_region_id = 0;
708
354k
    surface->mask_region_id = 0;
709
710
    /* Adapted from _cairo_surface_show_glyphs */
711
354k
    if (surface->target->backend->show_glyphs != NULL) {
712
0
  backend_status =
713
0
      surface->target->backend->show_glyphs (surface->target, op,
714
0
               source,
715
0
               glyphs, num_glyphs,
716
0
               scaled_font,
717
0
               clip);
718
0
  if (_cairo_int_status_is_error (backend_status))
719
0
      return backend_status;
720
0
    }
721
354k
    else if (surface->target->backend->show_text_glyphs != NULL)
722
354k
    {
723
354k
  backend_status =
724
354k
      surface->target->backend->show_text_glyphs (surface->target, op,
725
354k
              source,
726
354k
              NULL, 0,
727
354k
              glyphs, num_glyphs,
728
354k
              NULL, 0,
729
354k
              FALSE,
730
354k
              scaled_font,
731
354k
              clip);
732
354k
  if (_cairo_int_status_is_error (backend_status))
733
0
      return backend_status;
734
354k
    }
735
0
    else
736
0
    {
737
0
  backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
738
0
    }
739
740
354k
    _cairo_analysis_surface_operation_extents (surface,
741
354k
                 op, source, clip,
742
354k
                 &extents);
743
354k
    if (backend_status == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN) {
744
0
  cairo_rectangle_int_t rec_extents;
745
0
  backend_status = _analyze_recording_surface_pattern (surface,
746
0
                   source,
747
0
                   &rec_extents,
748
0
                   &surface->source_region_id,
749
0
                   CAIRO_ANALYSIS_SOURCE_SHOW_GLYPHS);
750
0
  _cairo_rectangle_intersect (&extents, &rec_extents);
751
0
    }
752
753
354k
    if (_cairo_operator_bounded_by_mask (op)) {
754
354k
  status = _cairo_scaled_font_glyph_device_extents (scaled_font,
755
354k
                glyphs,
756
354k
                num_glyphs,
757
354k
                &glyph_extents,
758
354k
                NULL);
759
354k
  if (unlikely (status))
760
0
      return status;
761
762
354k
  _cairo_rectangle_intersect (&extents, &glyph_extents);
763
354k
    }
764
765
354k
    return _add_operation (surface, &extents, backend_status);
766
354k
}
767
768
static cairo_bool_t
769
_cairo_analysis_surface_has_show_text_glyphs (void *abstract_surface)
770
0
{
771
0
    cairo_analysis_surface_t *surface = abstract_surface;
772
773
0
    return cairo_surface_has_show_text_glyphs (surface->target);
774
0
}
775
776
static cairo_int_status_t
777
_cairo_analysis_surface_show_text_glyphs (void          *abstract_surface,
778
            cairo_operator_t       op,
779
            const cairo_pattern_t     *source,
780
            const char        *utf8,
781
            int          utf8_len,
782
            cairo_glyph_t       *glyphs,
783
            int          num_glyphs,
784
            const cairo_text_cluster_t *clusters,
785
            int          num_clusters,
786
            cairo_text_cluster_flags_t cluster_flags,
787
            cairo_scaled_font_t     *scaled_font,
788
            const cairo_clip_t        *clip)
789
130k
{
790
130k
    cairo_analysis_surface_t *surface = abstract_surface;
791
130k
    cairo_int_status_t       status, backend_status;
792
130k
    cairo_rectangle_int_t    extents, glyph_extents;
793
794
130k
    surface->source_region_id = 0;
795
130k
    surface->mask_region_id = 0;
796
797
    /* Adapted from _cairo_surface_show_glyphs */
798
130k
    backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
799
130k
    if (surface->target->backend->show_text_glyphs != NULL) {
800
130k
  backend_status =
801
130k
      surface->target->backend->show_text_glyphs (surface->target, op,
802
130k
              source,
803
130k
              utf8, utf8_len,
804
130k
              glyphs, num_glyphs,
805
130k
              clusters, num_clusters,
806
130k
              cluster_flags,
807
130k
              scaled_font,
808
130k
              clip);
809
130k
  if (_cairo_int_status_is_error (backend_status))
810
0
      return backend_status;
811
130k
    }
812
130k
    if (backend_status == CAIRO_INT_STATUS_UNSUPPORTED &&
813
130k
  surface->target->backend->show_glyphs != NULL)
814
0
    {
815
0
  backend_status =
816
0
      surface->target->backend->show_glyphs (surface->target, op,
817
0
               source,
818
0
               glyphs, num_glyphs,
819
0
               scaled_font,
820
0
               clip);
821
0
  if (_cairo_int_status_is_error (backend_status))
822
0
      return backend_status;
823
0
    }
824
825
130k
    _cairo_analysis_surface_operation_extents (surface,
826
130k
                 op, source, clip,
827
130k
                 &extents);
828
130k
    if (backend_status == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN) {
829
0
  cairo_rectangle_int_t rec_extents;
830
0
  _analyze_recording_surface_pattern (surface,
831
0
              source,
832
0
              &rec_extents,
833
0
              &surface->source_region_id,
834
0
              CAIRO_ANALYSIS_SOURCE_SHOW_GLYPHS);
835
0
  _cairo_rectangle_intersect (&extents, &rec_extents);
836
0
    }
837
838
130k
    if (_cairo_operator_bounded_by_mask (op)) {
839
130k
  status = _cairo_scaled_font_glyph_device_extents (scaled_font,
840
130k
                glyphs,
841
130k
                num_glyphs,
842
130k
                &glyph_extents,
843
130k
                NULL);
844
130k
  if (unlikely (status))
845
0
      return status;
846
847
130k
  _cairo_rectangle_intersect (&extents, &glyph_extents);
848
130k
    }
849
850
130k
    return _add_operation (surface, &extents, backend_status);
851
130k
}
852
853
static cairo_int_status_t
854
_cairo_analysis_surface_tag (void                 *abstract_surface,
855
           cairo_bool_t                begin,
856
           const char                 *tag_name,
857
           const char                 *attributes)
858
0
{
859
0
    cairo_analysis_surface_t *surface = abstract_surface;
860
0
    cairo_int_status_t       backend_status;
861
862
0
    surface->source_region_id = 0;
863
0
    surface->mask_region_id = 0;
864
0
    backend_status = CAIRO_INT_STATUS_SUCCESS;
865
0
    if (surface->target->backend->tag != NULL) {
866
0
  backend_status =
867
0
      surface->target->backend->tag (surface->target,
868
0
             begin,
869
0
             tag_name,
870
0
             attributes);
871
0
        if (backend_status == CAIRO_INT_STATUS_SUCCESS)
872
0
            surface->has_supported = TRUE;
873
0
    }
874
875
0
    return backend_status;
876
0
}
877
878
static cairo_bool_t
879
_cairo_analysis_surface_supports_color_glyph (void                 *abstract_surface,
880
                                              cairo_scaled_font_t  *scaled_font,
881
                                              unsigned long         glyph_index)
882
0
{
883
0
    return TRUE;
884
0
}
885
886
static cairo_int_status_t
887
_cairo_analysis_surface_command_id (void                 *abstract_surface,
888
            unsigned int          recording_id,
889
            unsigned int          command_id)
890
499k
{
891
499k
    cairo_analysis_surface_t *surface = abstract_surface;
892
499k
    cairo_int_status_t backend_status;
893
894
499k
    backend_status = CAIRO_INT_STATUS_SUCCESS;
895
499k
    if (surface->target->backend->command_id != NULL) {
896
499k
  backend_status =
897
499k
      surface->target->backend->command_id (surface->target,
898
499k
              recording_id,
899
499k
              command_id);
900
499k
    }
901
902
499k
    return backend_status;
903
499k
}
904
905
static const cairo_surface_backend_t cairo_analysis_surface_backend = {
906
    CAIRO_INTERNAL_SURFACE_TYPE_ANALYSIS,
907
908
    _cairo_analysis_surface_finish,
909
    NULL,
910
911
    NULL, /* create_similar */
912
    NULL, /* create_similar_image */
913
    NULL, /* map_to_image */
914
    NULL, /* unmap */
915
916
    NULL, /* source */
917
    NULL, /* acquire_source_image */
918
    NULL, /* release_source_image */
919
    NULL, /* snapshot */
920
921
    NULL, /* copy_page */
922
    NULL, /* show_page */
923
924
    _cairo_analysis_surface_get_extents,
925
    NULL, /* get_font_options */
926
927
    NULL, /* flush */
928
    NULL, /* mark_dirty_rectangle */
929
930
    _cairo_analysis_surface_paint,
931
    _cairo_analysis_surface_mask,
932
    _cairo_analysis_surface_stroke,
933
    _cairo_analysis_surface_fill,
934
    NULL, /* fill_stroke */
935
    _cairo_analysis_surface_show_glyphs,
936
    _cairo_analysis_surface_has_show_text_glyphs,
937
    _cairo_analysis_surface_show_text_glyphs,
938
    NULL, /* get_supported_mime_types */
939
    _cairo_analysis_surface_tag,
940
    _cairo_analysis_surface_supports_color_glyph,
941
    NULL, /* analyze_recording_surface */
942
    _cairo_analysis_surface_command_id,
943
};
944
945
cairo_surface_t *
946
_cairo_analysis_surface_create (cairo_surface_t   *target,
947
        cairo_bool_t             create_region_ids)
948
2.57k
{
949
2.57k
    cairo_analysis_surface_t *surface;
950
2.57k
    cairo_status_t status;
951
952
2.57k
    status = target->status;
953
2.57k
    if (unlikely (status))
954
0
  return _cairo_surface_create_in_error (status);
955
956
2.57k
    surface = _cairo_calloc (sizeof (cairo_analysis_surface_t));
957
2.57k
    if (unlikely (surface == NULL))
958
0
  return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
959
960
    /* I believe the content type here is truly arbitrary. I'm quite
961
     * sure nothing will ever use this value. */
962
2.57k
    _cairo_surface_init (&surface->base,
963
2.57k
       &cairo_analysis_surface_backend,
964
2.57k
       NULL, /* device */
965
2.57k
       CAIRO_CONTENT_COLOR_ALPHA,
966
2.57k
       target->is_vector);
967
968
2.57k
    cairo_matrix_init_identity (&surface->ctm);
969
2.57k
    surface->has_ctm = FALSE;
970
971
2.57k
    surface->target = cairo_surface_reference (target);
972
2.57k
    surface->first_op  = TRUE;
973
2.57k
    surface->has_supported = FALSE;
974
2.57k
    surface->has_unsupported = FALSE;
975
976
2.57k
    surface->create_region_ids = create_region_ids;
977
2.57k
    surface->source_region_id = 0;
978
2.57k
    surface->mask_region_id = 0;
979
980
2.57k
    _cairo_region_init (&surface->supported_region);
981
2.57k
    _cairo_region_init (&surface->fallback_region);
982
983
2.57k
    surface->page_bbox.p1.x = 0;
984
2.57k
    surface->page_bbox.p1.y = 0;
985
2.57k
    surface->page_bbox.p2.x = 0;
986
2.57k
    surface->page_bbox.p2.y = 0;
987
988
2.57k
    return &surface->base;
989
2.57k
}
990
991
void
992
_cairo_analysis_surface_set_ctm (cairo_surface_t *abstract_surface,
993
         const cairo_matrix_t  *ctm)
994
571
{
995
571
    cairo_analysis_surface_t  *surface;
996
997
571
    if (abstract_surface->status)
998
0
  return;
999
1000
571
    surface = (cairo_analysis_surface_t *) abstract_surface;
1001
1002
571
    surface->ctm = *ctm;
1003
571
    surface->has_ctm = ! _cairo_matrix_is_identity (&surface->ctm);
1004
571
}
1005
1006
void
1007
_cairo_analysis_surface_get_ctm (cairo_surface_t *abstract_surface,
1008
         cairo_matrix_t  *ctm)
1009
0
{
1010
0
    cairo_analysis_surface_t  *surface = (cairo_analysis_surface_t *) abstract_surface;
1011
1012
0
    *ctm = surface->ctm;
1013
0
}
1014
1015
1016
cairo_region_t *
1017
_cairo_analysis_surface_get_supported (cairo_surface_t *abstract_surface)
1018
0
{
1019
0
    cairo_analysis_surface_t  *surface = (cairo_analysis_surface_t *) abstract_surface;
1020
1021
0
    return &surface->supported_region;
1022
0
}
1023
1024
cairo_region_t *
1025
_cairo_analysis_surface_get_unsupported (cairo_surface_t *abstract_surface)
1026
0
{
1027
0
    cairo_analysis_surface_t  *surface = (cairo_analysis_surface_t *) abstract_surface;
1028
1029
0
    return &surface->fallback_region;
1030
0
}
1031
1032
cairo_bool_t
1033
_cairo_analysis_surface_has_supported (cairo_surface_t *abstract_surface)
1034
2.00k
{
1035
2.00k
    cairo_analysis_surface_t  *surface = (cairo_analysis_surface_t *) abstract_surface;
1036
1037
2.00k
    return surface->has_supported;
1038
2.00k
}
1039
1040
cairo_bool_t
1041
_cairo_analysis_surface_has_unsupported (cairo_surface_t *abstract_surface)
1042
4.00k
{
1043
4.00k
    cairo_analysis_surface_t  *surface = (cairo_analysis_surface_t *) abstract_surface;
1044
1045
4.00k
    return surface->has_unsupported;
1046
4.00k
}
1047
1048
void
1049
_cairo_analysis_surface_get_bounding_box (cairo_surface_t *abstract_surface,
1050
            cairo_box_t     *bbox)
1051
23
{
1052
23
    cairo_analysis_surface_t  *surface = (cairo_analysis_surface_t *) abstract_surface;
1053
1054
23
    *bbox = surface->page_bbox;
1055
23
}
1056
1057
unsigned int
1058
_cairo_analysis_surface_get_source_region_id (cairo_surface_t *abstract_surface)
1059
499k
{
1060
499k
    cairo_analysis_surface_t  *surface = (cairo_analysis_surface_t *) abstract_surface;
1061
1062
499k
    return surface->source_region_id;
1063
499k
}
1064
1065
unsigned int
1066
_cairo_analysis_surface_get_mask_region_id (cairo_surface_t *abstract_surface)
1067
1.17k
{
1068
1.17k
    cairo_analysis_surface_t  *surface = (cairo_analysis_surface_t *) abstract_surface;
1069
1070
1.17k
    return surface->mask_region_id;
1071
1.17k
}
1072
1073
1074
/* null surface type: a surface that does nothing (has no side effects, yay!) */
1075
1076
static cairo_int_status_t
1077
_paint_return_success (void     *surface,
1078
           cairo_operator_t    op,
1079
           const cairo_pattern_t  *source,
1080
           const cairo_clip_t *clip)
1081
0
{
1082
0
    if (source->type == CAIRO_PATTERN_TYPE_SURFACE) {
1083
0
        cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) source;
1084
0
        if (surface_pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING)
1085
0
            return CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN;
1086
0
    }
1087
1088
0
    return CAIRO_INT_STATUS_SUCCESS;
1089
0
}
1090
1091
static cairo_int_status_t
1092
_mask_return_success (void      *surface,
1093
          cairo_operator_t     op,
1094
          const cairo_pattern_t *source,
1095
          const cairo_pattern_t *mask,
1096
          const cairo_clip_t  *clip)
1097
2
{
1098
2
    if (source->type == CAIRO_PATTERN_TYPE_SURFACE) {
1099
0
        cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) source;
1100
0
        if (surface_pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING)
1101
0
            return CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN;
1102
0
    }
1103
1104
2
    if (mask->type == CAIRO_PATTERN_TYPE_SURFACE) {
1105
2
        cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) mask;
1106
2
        if (surface_pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING)
1107
0
            return CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN;
1108
2
    }
1109
1110
2
    return CAIRO_INT_STATUS_SUCCESS;
1111
2
}
1112
1113
static cairo_int_status_t
1114
_stroke_return_success (void        *surface,
1115
      cairo_operator_t     op,
1116
      const cairo_pattern_t   *source,
1117
      const cairo_path_fixed_t  *path,
1118
      const cairo_stroke_style_t  *style,
1119
      const cairo_matrix_t    *ctm,
1120
      const cairo_matrix_t    *ctm_inverse,
1121
      double         tolerance,
1122
      cairo_antialias_t    antialias,
1123
      const cairo_clip_t    *clip)
1124
2
{
1125
2
    if (source->type == CAIRO_PATTERN_TYPE_SURFACE) {
1126
0
        cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) source;
1127
0
        if (surface_pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING)
1128
0
            return CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN;
1129
0
    }
1130
1131
2
    return CAIRO_INT_STATUS_SUCCESS;
1132
2
}
1133
1134
static cairo_int_status_t
1135
_fill_return_success (void      *surface,
1136
          cairo_operator_t     op,
1137
          const cairo_pattern_t *source,
1138
          const cairo_path_fixed_t  *path,
1139
          cairo_fill_rule_t    fill_rule,
1140
          double       tolerance,
1141
          cairo_antialias_t    antialias,
1142
          const cairo_clip_t  *clip)
1143
340
{
1144
340
    if (source->type == CAIRO_PATTERN_TYPE_SURFACE) {
1145
0
        cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) source;
1146
0
        if (surface_pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING)
1147
0
            return CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN;
1148
0
    }
1149
1150
340
    return CAIRO_INT_STATUS_SUCCESS;
1151
340
}
1152
1153
static cairo_int_status_t
1154
_show_glyphs_return_success (void     *surface,
1155
           cairo_operator_t    op,
1156
           const cairo_pattern_t  *source,
1157
           cairo_glyph_t    *glyphs,
1158
           int       num_glyphs,
1159
           cairo_scaled_font_t  *scaled_font,
1160
           const cairo_clip_t   *clip)
1161
0
{
1162
0
    if (source->type == CAIRO_PATTERN_TYPE_SURFACE) {
1163
0
        cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) source;
1164
0
        if (surface_pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING)
1165
0
            return CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN;
1166
0
    }
1167
1168
0
    return CAIRO_INT_STATUS_SUCCESS;
1169
0
}
1170
1171
static const cairo_surface_backend_t cairo_null_surface_backend = {
1172
    CAIRO_INTERNAL_SURFACE_TYPE_NULL,
1173
    NULL, /* finish */
1174
1175
    NULL, /* only accessed through the surface functions */
1176
1177
    NULL, /* create_similar */
1178
    NULL, /* create similar image */
1179
    NULL, /* map to image */
1180
    NULL, /* unmap image*/
1181
1182
    NULL, /* source */
1183
    NULL, /* acquire_source_image */
1184
    NULL, /* release_source_image */
1185
    NULL, /* snapshot */
1186
1187
    NULL, /* copy_page */
1188
    NULL, /* show_page */
1189
1190
    NULL, /* get_extents */
1191
    NULL, /* get_font_options */
1192
1193
    NULL, /* flush */
1194
    NULL, /* mark_dirty_rectangle */
1195
1196
    _paint_return_success,      /* paint */
1197
    _mask_return_success,     /* mask */
1198
    _stroke_return_success,     /* stroke */
1199
    _fill_return_success,     /* fill */
1200
    NULL, /* fill_stroke */
1201
    _show_glyphs_return_success,    /* show_glyphs */
1202
    NULL, /* has_show_text_glyphs */
1203
    NULL, /* show_text_glyphs */
1204
    NULL, /* get_supported_mime_types */
1205
    NULL, /* tag */
1206
    NULL, /* supports_color_glyph */
1207
    NULL, /* analyze_recording_surface */
1208
    NULL, /* command_id*/
1209
};
1210
1211
cairo_surface_t *
1212
_cairo_null_surface_create (cairo_content_t content)
1213
23
{
1214
23
    cairo_surface_t *surface;
1215
1216
23
    surface = _cairo_calloc (sizeof (cairo_surface_t));
1217
23
    if (unlikely (surface == NULL)) {
1218
0
  return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
1219
0
    }
1220
1221
23
    _cairo_surface_init (surface,
1222
23
       &cairo_null_surface_backend,
1223
23
       NULL, /* device */
1224
23
       content,
1225
23
       TRUE); /* is_vector */
1226
1227
23
    return surface;
1228
23
}