Coverage Report

Created: 2025-07-07 10:01

/work/workdir/UnpackedTarball/cairo/src/cairo-paginated-surface.c
Line
Count
Source (jump to first uncovered line)
1
/* cairo - a vector graphics library with display and print output
2
 *
3
 * Copyright © 2005 Red Hat, Inc
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 Red Hat, Inc.
32
 *
33
 * Contributor(s):
34
 *  Carl Worth <cworth@cworth.org>
35
 *  Keith Packard <keithp@keithp.com>
36
 *  Adrian Johnson <ajohnson@redneon.com>
37
 */
38
39
/* The paginated surface layer exists to provide as much code sharing
40
 * as possible for the various paginated surface backends in cairo
41
 * (PostScript, PDF, etc.). See cairo-paginated-private.h for
42
 * more details on how it works and how to use it.
43
 */
44
45
#include "cairoint.h"
46
47
#include "cairo-paginated-private.h"
48
#include "cairo-paginated-surface-private.h"
49
#include "cairo-recording-surface-private.h"
50
#include "cairo-analysis-surface-private.h"
51
#include "cairo-error-private.h"
52
#include "cairo-image-surface-private.h"
53
#include "cairo-surface-subsurface-inline.h"
54
55
static const cairo_surface_backend_t cairo_paginated_surface_backend;
56
57
static cairo_int_status_t
58
_cairo_paginated_surface_show_page (void *abstract_surface);
59
60
static cairo_surface_t *
61
_cairo_paginated_surface_create_similar (void     *abstract_surface,
62
           cairo_content_t   content,
63
           int       width,
64
           int       height)
65
0
{
66
0
    cairo_rectangle_t rect;
67
0
    rect.x = rect.y = 0.;
68
0
    rect.width = width;
69
0
    rect.height = height;
70
0
    return cairo_recording_surface_create (content, &rect);
71
0
}
72
73
static cairo_surface_t *
74
_create_recording_surface_for_target (cairo_surface_t *target,
75
              cairo_content_t content)
76
4
{
77
4
    cairo_rectangle_int_t rect;
78
79
4
    if (_cairo_surface_get_extents (target, &rect)) {
80
4
  cairo_rectangle_t recording_extents;
81
82
4
  recording_extents.x = rect.x;
83
4
  recording_extents.y = rect.y;
84
4
  recording_extents.width = rect.width;
85
4
  recording_extents.height = rect.height;
86
87
4
  return cairo_recording_surface_create (content, &recording_extents);
88
4
    } else {
89
0
  return cairo_recording_surface_create (content, NULL);
90
0
    }
91
4
}
92
93
cairo_surface_t *
94
_cairo_paginated_surface_create (cairo_surface_t        *target,
95
         cairo_content_t         content,
96
         const cairo_paginated_surface_backend_t  *backend)
97
2
{
98
2
    cairo_paginated_surface_t *surface;
99
2
    cairo_status_t status;
100
101
2
    surface = _cairo_malloc (sizeof (cairo_paginated_surface_t));
102
2
    if (unlikely (surface == NULL)) {
103
0
  status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
104
0
  goto FAIL;
105
0
    }
106
107
2
    _cairo_surface_init (&surface->base,
108
2
       &cairo_paginated_surface_backend,
109
2
       NULL, /* device */
110
2
       content,
111
2
       target->is_vector);
112
113
    /* Override surface->base.type with target's type so we don't leak
114
     * evidence of the paginated wrapper out to the user. */
115
2
    surface->base.type = target->type;
116
117
2
    surface->target = cairo_surface_reference (target);
118
119
2
    surface->content = content;
120
2
    surface->backend = backend;
121
122
2
    surface->recording_surface = _create_recording_surface_for_target (target, content);
123
2
    status = surface->recording_surface->status;
124
2
    if (unlikely (status))
125
0
  goto FAIL_CLEANUP_SURFACE;
126
127
2
    surface->page_num = 1;
128
2
    surface->base.is_clear = TRUE;
129
130
2
    return &surface->base;
131
132
0
  FAIL_CLEANUP_SURFACE:
133
0
    cairo_surface_destroy (target);
134
0
    free (surface);
135
0
  FAIL:
136
0
    return _cairo_surface_create_in_error (status);
137
0
}
138
139
cairo_bool_t
140
_cairo_surface_is_paginated (cairo_surface_t *surface)
141
0
{
142
0
    return surface->backend == &cairo_paginated_surface_backend;
143
0
}
144
145
cairo_surface_t *
146
_cairo_paginated_surface_get_target (cairo_surface_t *surface)
147
0
{
148
0
    cairo_paginated_surface_t *paginated_surface;
149
150
0
    assert (_cairo_surface_is_paginated (surface));
151
152
0
    paginated_surface = (cairo_paginated_surface_t *) surface;
153
0
    return paginated_surface->target;
154
0
}
155
156
cairo_surface_t *
157
_cairo_paginated_surface_get_recording (cairo_surface_t *surface)
158
0
{
159
0
    cairo_paginated_surface_t *paginated_surface;
160
161
0
    assert (_cairo_surface_is_paginated (surface));
162
163
0
    paginated_surface = (cairo_paginated_surface_t *) surface;
164
0
    return paginated_surface->recording_surface;
165
0
}
166
167
cairo_status_t
168
_cairo_paginated_surface_set_size (cairo_surface_t  *surface,
169
           int       width,
170
           int       height)
171
0
{
172
0
    cairo_paginated_surface_t *paginated_surface;
173
0
    cairo_status_t status;
174
0
    cairo_rectangle_t recording_extents;
175
176
0
    assert (_cairo_surface_is_paginated (surface));
177
178
0
    paginated_surface = (cairo_paginated_surface_t *) surface;
179
180
0
    recording_extents.x = 0;
181
0
    recording_extents.y = 0;
182
0
    recording_extents.width = width;
183
0
    recording_extents.height = height;
184
185
0
    cairo_surface_destroy (paginated_surface->recording_surface);
186
0
    paginated_surface->recording_surface = cairo_recording_surface_create (paginated_surface->content,
187
0
                     &recording_extents);
188
0
    status = paginated_surface->recording_surface->status;
189
0
    if (unlikely (status))
190
0
  return _cairo_surface_set_error (surface, status);
191
192
0
    return CAIRO_STATUS_SUCCESS;
193
0
}
194
195
static cairo_status_t
196
_cairo_paginated_surface_finish (void *abstract_surface)
197
2
{
198
2
    cairo_paginated_surface_t *surface = abstract_surface;
199
2
    cairo_status_t status = CAIRO_STATUS_SUCCESS;
200
201
2
    if (! surface->base.is_clear || surface->page_num == 1) {
202
  /* Bypass some of the sanity checking in cairo-surface.c, as we
203
   * know that the surface is finished...
204
   */
205
2
  status = _cairo_paginated_surface_show_page (surface);
206
2
    }
207
208
     /* XXX We want to propagate any errors from destroy(), but those are not
209
      * returned via the api. So we need to explicitly finish the target,
210
      * and check the status afterwards. However, we can only call finish()
211
      * on the target, if we own it.
212
      */
213
2
    if (CAIRO_REFERENCE_COUNT_GET_VALUE (&surface->target->ref_count) == 1)
214
2
  cairo_surface_finish (surface->target);
215
2
    if (status == CAIRO_STATUS_SUCCESS)
216
2
  status = cairo_surface_status (surface->target);
217
2
    cairo_surface_destroy (surface->target);
218
219
2
    cairo_surface_finish (surface->recording_surface);
220
2
    if (status == CAIRO_STATUS_SUCCESS)
221
2
  status = cairo_surface_status (surface->recording_surface);
222
2
    cairo_surface_destroy (surface->recording_surface);
223
224
2
    return status;
225
2
}
226
227
static cairo_surface_t *
228
_cairo_paginated_surface_create_image_surface (void        *abstract_surface,
229
                 int    width,
230
                 int    height)
231
0
{
232
0
    cairo_paginated_surface_t *surface = abstract_surface;
233
0
    cairo_surface_t *image;
234
0
    cairo_font_options_t options;
235
236
0
    image = _cairo_image_surface_create_with_content (surface->content,
237
0
                  width,
238
0
                  height);
239
240
0
    cairo_surface_get_font_options (&surface->base, &options);
241
0
    _cairo_surface_set_font_options (image, &options);
242
243
0
    return image;
244
0
}
245
246
static cairo_surface_t *
247
_cairo_paginated_surface_source (void        *abstract_surface,
248
         cairo_rectangle_int_t *extents)
249
0
{
250
0
    cairo_paginated_surface_t *surface = abstract_surface;
251
0
    return _cairo_surface_get_source (surface->target, extents);
252
0
}
253
254
static cairo_status_t
255
_cairo_paginated_surface_acquire_source_image (void        *abstract_surface,
256
                 cairo_image_surface_t **image_out,
257
                 void      **image_extra)
258
0
{
259
0
    cairo_paginated_surface_t *surface = abstract_surface;
260
0
    cairo_bool_t is_bounded;
261
0
    cairo_surface_t *image;
262
0
    cairo_status_t status;
263
0
    cairo_rectangle_int_t extents;
264
265
0
    is_bounded = _cairo_surface_get_extents (surface->target, &extents);
266
0
    if (! is_bounded)
267
0
  return CAIRO_INT_STATUS_UNSUPPORTED;
268
269
0
    image = _cairo_paginated_surface_create_image_surface (surface,
270
0
                 extents.width,
271
0
                 extents.height);
272
273
0
    status = _cairo_recording_surface_replay (surface->recording_surface, image);
274
0
    if (unlikely (status)) {
275
0
  cairo_surface_destroy (image);
276
0
  return status;
277
0
    }
278
279
0
    *image_out = (cairo_image_surface_t*) image;
280
0
    *image_extra = NULL;
281
282
0
    return CAIRO_STATUS_SUCCESS;
283
0
}
284
285
static void
286
_cairo_paginated_surface_release_source_image (void   *abstract_surface,
287
                 cairo_image_surface_t *image,
288
                 void        *image_extra)
289
0
{
290
0
    cairo_surface_destroy (&image->base);
291
0
}
292
293
static cairo_int_status_t
294
_paint_thumbnail_image (cairo_paginated_surface_t *surface,
295
      int                        width,
296
      int                        height)
297
0
{
298
0
    cairo_surface_pattern_t pattern;
299
0
    cairo_rectangle_int_t extents;
300
0
    double x_scale;
301
0
    double y_scale;
302
0
    cairo_surface_t *image = NULL;
303
0
    cairo_surface_t *opaque = NULL;
304
0
    cairo_status_t status = CAIRO_STATUS_SUCCESS;
305
306
0
    _cairo_surface_get_extents (surface->target, &extents);
307
0
    x_scale = (double)width / extents.width;
308
0
    y_scale = (double)height / extents.height;
309
310
0
    image = _cairo_paginated_surface_create_image_surface (surface, width, height);
311
0
    cairo_surface_set_device_scale (image, x_scale, y_scale);
312
0
    cairo_surface_set_device_offset (image, -extents.x*x_scale, -extents.y*y_scale);
313
0
    status = _cairo_recording_surface_replay (surface->recording_surface, image);
314
0
    if (unlikely (status))
315
0
  goto cleanup;
316
317
    /* flatten transparency */
318
319
0
    opaque = cairo_image_surface_create (CAIRO_FORMAT_RGB24, width, height);
320
0
    if (unlikely (opaque->status)) {
321
0
  status = opaque->status;
322
0
  goto cleanup;
323
0
    }
324
325
0
    status = _cairo_surface_paint (opaque,
326
0
           CAIRO_OPERATOR_SOURCE,
327
0
           &_cairo_pattern_white.base,
328
0
           NULL);
329
0
    if (unlikely (status))
330
0
  goto cleanup;
331
332
0
    _cairo_pattern_init_for_surface (&pattern, image);
333
0
    pattern.base.filter = CAIRO_FILTER_NEAREST;
334
0
    status = _cairo_surface_paint (opaque, CAIRO_OPERATOR_OVER, &pattern.base, NULL);
335
0
    _cairo_pattern_fini (&pattern.base);
336
0
    if (unlikely (status))
337
0
  goto cleanup;
338
339
0
    status = surface->backend->set_thumbnail_image (surface->target, (cairo_image_surface_t *)opaque);
340
341
0
  cleanup:
342
0
    if (image)
343
0
  cairo_surface_destroy (image);
344
0
    if (opaque)
345
0
  cairo_surface_destroy (opaque);
346
347
0
    return status;
348
0
}
349
350
static cairo_int_status_t
351
_paint_fallback_image (cairo_paginated_surface_t *surface,
352
           cairo_rectangle_int_t     *rect)
353
0
{
354
0
    double x_scale = surface->base.x_fallback_resolution / surface->target->x_resolution;
355
0
    double y_scale = surface->base.y_fallback_resolution / surface->target->y_resolution;
356
0
    int x, y, width, height;
357
0
    cairo_status_t status;
358
0
    cairo_surface_t *image;
359
0
    cairo_surface_pattern_t pattern;
360
0
    cairo_clip_t *clip;
361
362
0
    x = rect->x;
363
0
    y = rect->y;
364
0
    width = rect->width;
365
0
    height = rect->height;
366
0
    image = _cairo_paginated_surface_create_image_surface (surface,
367
0
                 ceil (width  * x_scale),
368
0
                 ceil (height * y_scale));
369
0
    cairo_surface_set_device_scale (image, x_scale, y_scale);
370
    /* set_device_offset just sets the x0/y0 components of the matrix;
371
     * so we have to do the scaling manually. */
372
0
    cairo_surface_set_device_offset (image, -x*x_scale, -y*y_scale);
373
374
0
    status = _cairo_recording_surface_replay (surface->recording_surface, image);
375
0
    if (unlikely (status))
376
0
  goto CLEANUP_IMAGE;
377
378
0
    _cairo_pattern_init_for_surface (&pattern, image);
379
0
    cairo_matrix_init (&pattern.base.matrix,
380
0
           x_scale, 0, 0, y_scale, -x*x_scale, -y*y_scale);
381
    /* the fallback should be rendered at native resolution, so disable
382
     * filtering (if possible) to avoid introducing potential artifacts. */
383
0
    pattern.base.filter = CAIRO_FILTER_NEAREST;
384
385
0
    clip = _cairo_clip_intersect_rectangle (NULL, rect);
386
0
    status = _cairo_surface_paint (surface->target,
387
0
           CAIRO_OPERATOR_SOURCE,
388
0
           &pattern.base, clip);
389
0
    _cairo_clip_destroy (clip);
390
0
    _cairo_pattern_fini (&pattern.base);
391
392
0
CLEANUP_IMAGE:
393
0
    cairo_surface_destroy (image);
394
395
0
    return status;
396
0
}
397
398
static cairo_int_status_t
399
_paint_page (cairo_paginated_surface_t *surface)
400
2
{
401
2
    cairo_surface_t *analysis;
402
2
    cairo_int_status_t status;
403
2
    cairo_bool_t has_supported, has_page_fallback, has_finegrained_fallback;
404
405
2
    if (unlikely (surface->target->status))
406
0
  return surface->target->status;
407
408
2
    analysis = _cairo_analysis_surface_create (surface->target);
409
2
    if (unlikely (analysis->status))
410
0
  return _cairo_surface_set_error (surface->target, analysis->status);
411
412
2
    status = surface->backend->set_paginated_mode (surface->target,
413
2
                                    CAIRO_PAGINATED_MODE_ANALYZE);
414
2
    if (unlikely (status))
415
0
  goto FAIL;
416
417
2
    status = _cairo_recording_surface_replay_and_create_regions (surface->recording_surface,
418
2
                 NULL, analysis, FALSE);
419
2
    if (status)
420
0
  goto FAIL;
421
422
2
    assert (analysis->status == CAIRO_STATUS_SUCCESS);
423
424
2
     if (surface->backend->set_bounding_box) {
425
0
   cairo_box_t bbox;
426
427
0
   _cairo_analysis_surface_get_bounding_box (analysis, &bbox);
428
0
   status = surface->backend->set_bounding_box (surface->target, &bbox);
429
0
   if (unlikely (status))
430
0
       goto FAIL;
431
0
     }
432
433
2
    if (surface->backend->set_fallback_images_required) {
434
2
  cairo_bool_t has_fallbacks = _cairo_analysis_surface_has_unsupported (analysis);
435
436
2
  status = surface->backend->set_fallback_images_required (surface->target,
437
2
                 has_fallbacks);
438
2
  if (unlikely (status))
439
0
      goto FAIL;
440
2
    }
441
442
    /* Finer grained fallbacks are currently only supported for some
443
     * surface types */
444
2
    if (surface->backend->supports_fine_grained_fallbacks != NULL &&
445
2
  surface->backend->supports_fine_grained_fallbacks (surface->target))
446
2
    {
447
2
  has_supported = _cairo_analysis_surface_has_supported (analysis);
448
2
  has_page_fallback = FALSE;
449
2
  has_finegrained_fallback = _cairo_analysis_surface_has_unsupported (analysis);
450
2
    }
451
0
    else
452
0
    {
453
0
  if (_cairo_analysis_surface_has_unsupported (analysis)) {
454
0
      has_supported = FALSE;
455
0
      has_page_fallback = TRUE;
456
0
  } else {
457
0
      has_supported = TRUE;
458
0
      has_page_fallback = FALSE;
459
0
  }
460
0
  has_finegrained_fallback = FALSE;
461
0
    }
462
463
2
    if (has_supported) {
464
0
  status = surface->backend->set_paginated_mode (surface->target,
465
0
                   CAIRO_PAGINATED_MODE_RENDER);
466
0
  if (unlikely (status))
467
0
      goto FAIL;
468
469
0
  status = _cairo_recording_surface_replay_region (surface->recording_surface,
470
0
               NULL,
471
0
               surface->target,
472
0
               CAIRO_RECORDING_REGION_NATIVE);
473
0
  assert (status != CAIRO_INT_STATUS_UNSUPPORTED);
474
0
  if (unlikely (status))
475
0
      goto FAIL;
476
0
    }
477
478
2
    if (has_page_fallback) {
479
0
  cairo_rectangle_int_t extents;
480
0
  cairo_bool_t is_bounded;
481
482
0
  status = surface->backend->set_paginated_mode (surface->target,
483
0
                   CAIRO_PAGINATED_MODE_FALLBACK);
484
0
  if (unlikely (status))
485
0
      goto FAIL;
486
487
0
  is_bounded = _cairo_surface_get_extents (surface->target, &extents);
488
0
  if (! is_bounded) {
489
0
      status = CAIRO_INT_STATUS_UNSUPPORTED;
490
0
      goto FAIL;
491
0
  }
492
493
0
  status = _paint_fallback_image (surface, &extents);
494
0
  if (unlikely (status))
495
0
      goto FAIL;
496
0
    }
497
498
2
    if (has_finegrained_fallback) {
499
0
        cairo_region_t *region;
500
0
        int num_rects, i;
501
502
0
  status = surface->backend->set_paginated_mode (surface->target,
503
0
                                  CAIRO_PAGINATED_MODE_FALLBACK);
504
0
  if (unlikely (status))
505
0
      goto FAIL;
506
507
0
  region = _cairo_analysis_surface_get_unsupported (analysis);
508
509
0
  num_rects = cairo_region_num_rectangles (region);
510
0
  for (i = 0; i < num_rects; i++) {
511
0
      cairo_rectangle_int_t rect;
512
513
0
      cairo_region_get_rectangle (region, i, &rect);
514
0
      status = _paint_fallback_image (surface, &rect);
515
0
      if (unlikely (status))
516
0
    goto FAIL;
517
0
  }
518
0
    }
519
520
2
    if (surface->backend->requires_thumbnail_image) {
521
2
  int width, height;
522
523
2
  if (surface->backend->requires_thumbnail_image (surface->target, &width, &height))
524
0
      _paint_thumbnail_image (surface, width, height);
525
2
    }
526
527
2
  FAIL:
528
2
    cairo_surface_destroy (analysis);
529
530
2
    return _cairo_surface_set_error (surface->target, status);
531
2
}
532
533
static cairo_status_t
534
_start_page (cairo_paginated_surface_t *surface)
535
2
{
536
2
    if (surface->target->status)
537
0
  return surface->target->status;
538
539
2
    if (! surface->backend->start_page)
540
0
  return CAIRO_STATUS_SUCCESS;
541
542
2
    return _cairo_surface_set_error (surface->target,
543
2
                          surface->backend->start_page (surface->target));
544
2
}
545
546
static cairo_int_status_t
547
_cairo_paginated_surface_copy_page (void *abstract_surface)
548
0
{
549
0
    cairo_status_t status;
550
0
    cairo_paginated_surface_t *surface = abstract_surface;
551
552
0
    status = _start_page (surface);
553
0
    if (unlikely (status))
554
0
  return status;
555
556
0
    status = _paint_page (surface);
557
0
    if (unlikely (status))
558
0
  return status;
559
560
0
    surface->page_num++;
561
562
    /* XXX: It might make sense to add some support here for calling
563
     * cairo_surface_copy_page on the target surface. It would be an
564
     * optimization for the output, but the interaction with image
565
     * fallbacks gets tricky. For now, we just let the target see a
566
     * show_page and we implement the copying by simply not destroying
567
     * the recording-surface. */
568
569
0
    cairo_surface_show_page (surface->target);
570
0
    return cairo_surface_status (surface->target);
571
0
}
572
573
static cairo_int_status_t
574
_cairo_paginated_surface_show_page (void *abstract_surface)
575
2
{
576
2
    cairo_status_t status;
577
2
    cairo_paginated_surface_t *surface = abstract_surface;
578
579
2
    status = _start_page (surface);
580
2
    if (unlikely (status))
581
0
  return status;
582
583
2
    status = _paint_page (surface);
584
2
    if (unlikely (status))
585
0
  return status;
586
587
2
    cairo_surface_show_page (surface->target);
588
2
    status = surface->target->status;
589
2
    if (unlikely (status))
590
0
  return status;
591
592
2
    status = surface->recording_surface->status;
593
2
    if (unlikely (status))
594
0
  return status;
595
596
2
    if (! surface->base.finished) {
597
2
  cairo_surface_destroy (surface->recording_surface);
598
599
2
  surface->recording_surface = _create_recording_surface_for_target (surface->target,
600
2
                     surface->content);
601
2
  status = surface->recording_surface->status;
602
2
  if (unlikely (status))
603
0
      return status;
604
605
2
  surface->page_num++;
606
2
  surface->base.is_clear = TRUE;
607
2
    }
608
609
2
    return CAIRO_STATUS_SUCCESS;
610
2
}
611
612
static cairo_bool_t
613
_cairo_paginated_surface_get_extents (void                *abstract_surface,
614
              cairo_rectangle_int_t   *rectangle)
615
0
{
616
0
    cairo_paginated_surface_t *surface = abstract_surface;
617
618
0
    return _cairo_surface_get_extents (surface->target, rectangle);
619
0
}
620
621
static void
622
_cairo_paginated_surface_get_font_options (void                  *abstract_surface,
623
             cairo_font_options_t  *options)
624
2
{
625
2
    cairo_paginated_surface_t *surface = abstract_surface;
626
627
2
    cairo_surface_get_font_options (surface->target, options);
628
2
}
629
630
static cairo_int_status_t
631
_cairo_paginated_surface_paint (void      *abstract_surface,
632
        cairo_operator_t   op,
633
        const cairo_pattern_t *source,
634
        const cairo_clip_t  *clip)
635
0
{
636
0
    cairo_paginated_surface_t *surface = abstract_surface;
637
638
0
    return _cairo_surface_paint (surface->recording_surface, op, source, clip);
639
0
}
640
641
static cairo_int_status_t
642
_cairo_paginated_surface_mask (void   *abstract_surface,
643
             cairo_operator_t  op,
644
             const cairo_pattern_t  *source,
645
             const cairo_pattern_t  *mask,
646
             const cairo_clip_t   *clip)
647
0
{
648
0
    cairo_paginated_surface_t *surface = abstract_surface;
649
650
0
    return _cairo_surface_mask (surface->recording_surface, op, source, mask, clip);
651
0
}
652
653
static cairo_int_status_t
654
_cairo_paginated_surface_stroke (void     *abstract_surface,
655
         cairo_operator_t  op,
656
         const cairo_pattern_t  *source,
657
         const cairo_path_fixed_t *path,
658
         const cairo_stroke_style_t *style,
659
         const cairo_matrix_t   *ctm,
660
         const cairo_matrix_t   *ctm_inverse,
661
         double      tolerance,
662
         cairo_antialias_t   antialias,
663
         const cairo_clip_t   *clip)
664
0
{
665
0
    cairo_paginated_surface_t *surface = abstract_surface;
666
667
0
    return _cairo_surface_stroke (surface->recording_surface, op, source,
668
0
          path, style,
669
0
          ctm, ctm_inverse,
670
0
          tolerance, antialias,
671
0
          clip);
672
0
}
673
674
static cairo_int_status_t
675
_cairo_paginated_surface_fill (void     *abstract_surface,
676
             cairo_operator_t    op,
677
             const cairo_pattern_t  *source,
678
             const cairo_path_fixed_t *path,
679
             cairo_fill_rule_t   fill_rule,
680
             double      tolerance,
681
             cairo_antialias_t   antialias,
682
             const cairo_clip_t   *clip)
683
0
{
684
0
    cairo_paginated_surface_t *surface = abstract_surface;
685
686
0
    return _cairo_surface_fill (surface->recording_surface, op, source,
687
0
        path, fill_rule,
688
0
        tolerance, antialias,
689
0
        clip);
690
0
}
691
692
static cairo_bool_t
693
_cairo_paginated_surface_has_show_text_glyphs (void *abstract_surface)
694
0
{
695
0
    cairo_paginated_surface_t *surface = abstract_surface;
696
697
0
    return cairo_surface_has_show_text_glyphs (surface->target);
698
0
}
699
700
static cairo_int_status_t
701
_cairo_paginated_surface_show_text_glyphs (void           *abstract_surface,
702
             cairo_operator_t        op,
703
             const cairo_pattern_t      *source,
704
             const char         *utf8,
705
             int             utf8_len,
706
             cairo_glyph_t        *glyphs,
707
             int             num_glyphs,
708
             const cairo_text_cluster_t *clusters,
709
             int             num_clusters,
710
             cairo_text_cluster_flags_t  cluster_flags,
711
             cairo_scaled_font_t        *scaled_font,
712
             const cairo_clip_t         *clip)
713
0
{
714
0
    cairo_paginated_surface_t *surface = abstract_surface;
715
716
0
    return _cairo_surface_show_text_glyphs (surface->recording_surface, op, source,
717
0
              utf8, utf8_len,
718
0
              glyphs, num_glyphs,
719
0
              clusters, num_clusters,
720
0
              cluster_flags,
721
0
              scaled_font,
722
0
              clip);
723
0
}
724
725
static const char **
726
_cairo_paginated_surface_get_supported_mime_types (void *abstract_surface)
727
0
{
728
0
    cairo_paginated_surface_t *surface = abstract_surface;
729
730
0
    if (surface->target->backend->get_supported_mime_types)
731
0
  return surface->target->backend->get_supported_mime_types (surface->target);
732
733
0
    return NULL;
734
0
}
735
736
static cairo_int_status_t
737
_cairo_paginated_surface_tag (void       *abstract_surface,
738
            cairo_bool_t                begin,
739
            const char                 *tag_name,
740
            const char                 *attributes)
741
0
{
742
0
    cairo_paginated_surface_t *surface = abstract_surface;
743
744
0
    return _cairo_surface_tag (surface->recording_surface,
745
0
             begin, tag_name, attributes);
746
0
}
747
748
static cairo_surface_t *
749
_cairo_paginated_surface_snapshot (void *abstract_other)
750
0
{
751
0
    cairo_paginated_surface_t *other = abstract_other;
752
753
0
    return other->recording_surface->backend->snapshot (other->recording_surface);
754
0
}
755
756
static cairo_t *
757
_cairo_paginated_context_create (void *target)
758
0
{
759
0
    cairo_paginated_surface_t *surface = target;
760
761
0
    if (_cairo_surface_is_subsurface (&surface->base))
762
0
  surface = (cairo_paginated_surface_t *)
763
0
      _cairo_surface_subsurface_get_target (&surface->base);
764
765
0
    return surface->recording_surface->backend->create_context (target);
766
0
}
767
768
static const cairo_surface_backend_t cairo_paginated_surface_backend = {
769
    CAIRO_INTERNAL_SURFACE_TYPE_PAGINATED,
770
    _cairo_paginated_surface_finish,
771
772
    _cairo_paginated_context_create,
773
774
    _cairo_paginated_surface_create_similar,
775
    NULL, /* create similar image */
776
    NULL, /* map to image */
777
    NULL, /* unmap image */
778
779
    _cairo_paginated_surface_source,
780
    _cairo_paginated_surface_acquire_source_image,
781
    _cairo_paginated_surface_release_source_image,
782
    _cairo_paginated_surface_snapshot,
783
784
    _cairo_paginated_surface_copy_page,
785
    _cairo_paginated_surface_show_page,
786
787
    _cairo_paginated_surface_get_extents,
788
    _cairo_paginated_surface_get_font_options,
789
790
    NULL, /* flush */
791
    NULL, /* mark_dirty_rectangle */
792
793
    _cairo_paginated_surface_paint,
794
    _cairo_paginated_surface_mask,
795
    _cairo_paginated_surface_stroke,
796
    _cairo_paginated_surface_fill,
797
    NULL, /* fill_stroke */
798
    NULL, /* show_glyphs */
799
    _cairo_paginated_surface_has_show_text_glyphs,
800
    _cairo_paginated_surface_show_text_glyphs,
801
    _cairo_paginated_surface_get_supported_mime_types,
802
    _cairo_paginated_surface_tag,
803
};