Coverage Report

Created: 2025-11-16 09:57

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