2 * Copyright © 2012 SCore Corporation
4 * This library is free software; you can redistribute it and/or
5 * modify it either under the terms of the GNU Lesser General Public
6 * License version 2.1 as published by the Free Software Foundation
7 * (the "LGPL") or, at your option, under the terms of the Mozilla
8 * Public License Version 1.1 (the "MPL"). If you do not alter this
9 * notice, a recipient may use your version of this file under either
10 * the MPL or the LGPL.
12 * You should have received a copy of the LGPL along with this library
13 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
15 * You should have received a copy of the MPL along with this library
16 * in the file COPYING-MPL-1.1
18 * The contents of this file are subject to the Mozilla Public License
19 * Version 1.1 (the "License"); you may not use this file except in
20 * compliance with the License. You may obtain a copy of the License at
21 * http://www.mozilla.org/MPL/
23 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
24 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
25 * the specific language governing rights and limitations.
27 * Author: Taekyun Kim (podain77@gmail.com)
31 #include "cairo-surface-fallback-private.h"
33 #include "cairo-tg-private.h"
34 #include "cairo-image-surface-inline.h"
35 #include "cairo-surface-subsurface-inline.h"
36 #include "cairo-compositor-private.h"
37 #include "cairo-clip-inline.h"
38 #include "cairo-recording-surface-inline.h"
44 #define CAIRO_TG_THREAD_POOL_BUSY_WAIT
45 #define CAIRO_TG_NUM_MIN_ENTRIES_FOR_PARALLEL_FLUSH 2
48 get_num_cpu_cores (void)
50 static int num_cpu_cores = 0;
52 if (num_cpu_cores == 0)
55 num_cpu_cores = omp_get_num_procs ();
56 #elif defined (__WIN32)
59 GetSystemInfo (&sysinfo);
60 num_cpu_cores = sysinfo.dwNumberOfProcessors;
61 #elif defined (__linux__)
67 if (sched_getaffinity (0, sizeof (cs), &cs) != 0)
70 for (i = 0; i < 8; i++)
72 if (CPU_ISSET (i, &cs))
84 get_bpp_for_format (cairo_format_t format)
88 case CAIRO_FORMAT_ARGB32:
89 case CAIRO_FORMAT_RGB24:
90 case CAIRO_FORMAT_RGB30:
92 case CAIRO_FORMAT_RGB16_565:
98 case CAIRO_FORMAT_INVALID:
105 static inline cairo_bool_t
106 _cairo_surface_is_tg(const cairo_surface_t *surface)
108 return surface->backend && surface->backend->type == CAIRO_SURFACE_TYPE_TG;
111 static inline cairo_bool_t
112 _cairo_tg_surface_is_size_valid (int width, int height)
114 if (width < 0 || height < 0)
117 /* TODO: Check for upper limit of surface size. */
122 static inline cairo_bool_t
123 _cairo_pattern_is_self_copy (cairo_surface_t *surface,
124 const cairo_pattern_t *pattern)
126 if (unlikely (surface == NULL))
129 if (unlikely (pattern == NULL))
132 if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE )
134 cairo_surface_t *pattern_surface =
135 ((cairo_surface_pattern_t *) pattern)->surface;
137 while (_cairo_surface_is_subsurface (pattern_surface))
140 _cairo_surface_subsurface_get_target (pattern_surface);
143 return pattern_surface == surface;
149 static inline cairo_bool_t
150 _cairo_pattern_is_recording (const cairo_pattern_t *pattern)
152 cairo_surface_t *surface;
154 if (pattern->type != CAIRO_PATTERN_TYPE_SURFACE)
157 surface = ((const cairo_surface_pattern_t *) pattern)->surface;
158 return _cairo_surface_is_recording (surface);
161 static inline cairo_bool_t
162 _cairo_tg_surface_owns_data (cairo_tg_surface_t *surface)
164 return ((cairo_image_surface_t *) surface->image_surface)->owns_data;
167 static inline cairo_int_status_t
168 _cairo_tg_image_surface_paint (void *closure,
170 const cairo_pattern_t *source,
171 const cairo_clip_t *clip)
173 cairo_image_surface_t *surface = (cairo_image_surface_t *) closure;
174 cairo_int_status_t status;
176 status = _cairo_surface_begin_modification (&surface->base);
178 if (unlikely (status))
181 status = _cairo_compositor_paint (surface->compositor, &surface->base,
184 if (status != CAIRO_INT_STATUS_NOTHING_TO_DO)
186 surface->base.is_clear = op == CAIRO_OPERATOR_CLEAR && clip == NULL;
187 surface->base.serial++;
193 static inline cairo_int_status_t
194 _cairo_tg_image_surface_mask (void *closure,
196 const cairo_pattern_t *source,
197 const cairo_pattern_t *mask,
198 const cairo_clip_t *clip)
200 cairo_image_surface_t *surface = (cairo_image_surface_t *) closure;
201 cairo_int_status_t status;
203 status = _cairo_surface_begin_modification (&surface->base);
205 if (unlikely (status))
208 status = _cairo_compositor_mask (surface->compositor, &surface->base,
209 op, source, mask, clip);
211 if (status != CAIRO_INT_STATUS_NOTHING_TO_DO)
213 surface->base.is_clear = FALSE;
214 surface->base.serial++;
220 static inline cairo_int_status_t
221 _cairo_tg_image_surface_stroke (void *closure,
223 const cairo_pattern_t *source,
224 const cairo_path_fixed_t *path,
225 const cairo_stroke_style_t *style,
226 const cairo_matrix_t *ctm,
227 const cairo_matrix_t *ctm_inverse,
229 cairo_antialias_t antialias,
230 const cairo_clip_t *clip)
232 cairo_image_surface_t *surface = (cairo_image_surface_t *) closure;
233 cairo_int_status_t status;
235 status = _cairo_surface_begin_modification (&surface->base);
237 if (unlikely (status))
240 status = _cairo_compositor_stroke (surface->compositor, &surface->base,
242 style, ctm, ctm_inverse,
243 tolerance, antialias, clip);
245 if (status != CAIRO_INT_STATUS_NOTHING_TO_DO)
247 surface->base.is_clear = FALSE;
248 surface->base.serial++;
255 static inline cairo_int_status_t
256 _cairo_tg_image_surface_fill (void *closure,
258 const cairo_pattern_t *source,
259 const cairo_path_fixed_t *path,
260 cairo_fill_rule_t fill_rule,
262 cairo_antialias_t antialias,
263 const cairo_clip_t *clip)
265 cairo_image_surface_t *surface = (cairo_image_surface_t *) closure;
266 cairo_int_status_t status;
268 status = _cairo_surface_begin_modification (&surface->base);
270 if (unlikely (status))
273 status = _cairo_compositor_fill (surface->compositor, &surface->base,
275 fill_rule, tolerance, antialias, clip);
277 if (status != CAIRO_INT_STATUS_NOTHING_TO_DO)
279 surface->base.is_clear = FALSE;
280 surface->base.serial++;
286 static inline cairo_int_status_t
287 _cairo_tg_image_surface_glyphs (void *closure,
289 const cairo_pattern_t *source,
290 cairo_glyph_t *glyphs,
292 cairo_scaled_font_t *scaled_font,
293 const cairo_clip_t *clip)
295 cairo_image_surface_t *surface = (cairo_image_surface_t *) closure;
296 cairo_int_status_t status;
298 status = _cairo_surface_begin_modification (&surface->base);
300 if (unlikely (status))
303 status = _cairo_compositor_glyphs (surface->compositor, &surface->base,
305 glyphs, num_glyphs, scaled_font,
308 if (status != CAIRO_INT_STATUS_NOTHING_TO_DO)
310 surface->base.is_clear = FALSE;
311 surface->base.serial++;
317 const cairo_tg_journal_replay_funcs_t replay_funcs_image_fallback =
319 _cairo_tg_image_surface_paint,
320 _cairo_tg_image_surface_mask,
321 _cairo_tg_image_surface_stroke,
322 _cairo_tg_image_surface_fill,
323 _cairo_tg_image_surface_glyphs,
326 typedef struct _cairo_tg_surface_tile
328 cairo_surface_t *surface;
329 cairo_rectangle_int_t tile_rect;
330 } cairo_tg_surface_tile_t;
333 _cairo_tg_surface_tiles_init (cairo_tg_surface_t *surface,
334 const cairo_rectangle_int_t *extents,
336 cairo_tg_surface_tile_t *tiles)
341 if (extents->height <= 0)
344 if (extents->height <= num_tiles)
345 num_tiles = extents->height;
347 tile_height = extents->height / num_tiles;
349 for (i = 0; i < num_tiles; i++)
351 tiles[i].surface = surface->tile_surfaces[i];
352 tiles[i].tile_rect.x = extents->x;
353 tiles[i].tile_rect.y = extents->y + i * tile_height;
354 tiles[i].tile_rect.width = extents->width;
355 tiles[i].tile_rect.height = tile_height;
358 tiles[num_tiles - 1].tile_rect.height = extents->height - i * (num_tiles - 1);
363 static cairo_int_status_t
364 _cairo_tg_surface_tile_paint (void *closure,
366 const cairo_pattern_t *source,
367 const cairo_clip_t *clip)
369 cairo_tg_surface_tile_t *tile = (cairo_tg_surface_tile_t *) closure;
370 cairo_clip_t *tile_clip;
371 cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS;
373 tile_clip = _cairo_clip_copy_intersect_rectangle (clip, &tile->tile_rect);
375 if (! _cairo_clip_is_all_clipped (tile_clip))
376 status = _cairo_tg_image_surface_paint (tile->surface, op, source, tile_clip);
378 _cairo_clip_destroy (tile_clip);
383 static cairo_int_status_t
384 _cairo_tg_surface_tile_mask (void *closure,
386 const cairo_pattern_t *source,
387 const cairo_pattern_t *mask,
388 const cairo_clip_t *clip)
390 cairo_tg_surface_tile_t *tile = (cairo_tg_surface_tile_t *) closure;
391 cairo_clip_t *tile_clip;
392 cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS;
394 tile_clip = _cairo_clip_copy_intersect_rectangle (clip, &tile->tile_rect);
396 if (! _cairo_clip_is_all_clipped (tile_clip))
398 status = _cairo_tg_image_surface_mask (tile->surface, op, source,
402 _cairo_clip_destroy (tile_clip);
407 static cairo_int_status_t
408 _cairo_tg_surface_tile_stroke (void *closure,
410 const cairo_pattern_t *source,
411 const cairo_path_fixed_t *path,
412 const cairo_stroke_style_t *style,
413 const cairo_matrix_t *ctm,
414 const cairo_matrix_t *ctm_inverse,
416 cairo_antialias_t antialias,
417 const cairo_clip_t *clip)
419 cairo_tg_surface_tile_t *tile = (cairo_tg_surface_tile_t *) closure;
420 cairo_clip_t *tile_clip;
421 cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS;
423 tile_clip = _cairo_clip_copy_intersect_rectangle (clip, &tile->tile_rect);
425 if (! _cairo_clip_is_all_clipped (tile_clip))
427 status = _cairo_tg_image_surface_stroke (tile->surface, op, source,
428 path, style, ctm, ctm_inverse,
429 tolerance, antialias, tile_clip);
432 _cairo_clip_destroy (tile_clip);
437 static cairo_int_status_t
438 _cairo_tg_surface_tile_fill (void *closure,
440 const cairo_pattern_t *source,
441 const cairo_path_fixed_t *path,
442 cairo_fill_rule_t fill_rule,
444 cairo_antialias_t antialias,
445 const cairo_clip_t *clip)
447 cairo_tg_surface_tile_t *tile = (cairo_tg_surface_tile_t *) closure;
448 cairo_clip_t *tile_clip;
449 cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS;
451 tile_clip = _cairo_clip_copy_intersect_rectangle (clip, &tile->tile_rect);
453 if (! _cairo_clip_is_all_clipped (tile_clip))
455 status = _cairo_tg_image_surface_fill (tile->surface, op, source,
456 path, fill_rule, tolerance,
457 antialias, tile_clip);
460 _cairo_clip_destroy (tile_clip);
465 static cairo_int_status_t
466 _cairo_tg_surface_tile_glyphs (void *closure,
468 const cairo_pattern_t *source,
469 cairo_glyph_t *glyphs,
471 cairo_scaled_font_t *scaled_font,
472 const cairo_clip_t *clip)
474 cairo_tg_surface_tile_t *tile = (cairo_tg_surface_tile_t *) closure;
475 cairo_clip_t *tile_clip;
476 cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS;
478 tile_clip = _cairo_clip_copy_intersect_rectangle (clip, &tile->tile_rect);
480 if (! _cairo_clip_is_all_clipped (tile_clip))
482 status = _cairo_tg_image_surface_glyphs (tile->surface, op, source,
483 glyphs, num_glyphs, scaled_font,
487 _cairo_clip_destroy (tile_clip);
492 const cairo_tg_journal_replay_funcs_t replay_funcs_tile =
494 _cairo_tg_surface_tile_paint,
495 _cairo_tg_surface_tile_mask,
496 _cairo_tg_surface_tile_stroke,
497 _cairo_tg_surface_tile_fill,
498 _cairo_tg_surface_tile_glyphs,
501 #if ! CAIRO_HAS_OPENMP
502 #define CAIRO_TG_NUM_MAX_WORKERS CAIRO_TG_NUM_MAX_TILES
504 typedef enum _cairo_tg_worker_status
506 CAIRO_TG_WORKER_STATUS_IDLE, /* can transit to either OCCUPIED or KILLED */
507 CAIRO_TG_WORKER_STATUS_TO_DO, /* only can transit to IDLE state */
508 CAIRO_TG_WORKER_STATUS_KILLED, /* worker will be no longer valid */
509 } cairo_tg_worker_status_t;
511 typedef struct _cairo_tg_worker
513 cairo_tg_journal_t *journal;
514 cairo_tg_surface_tile_t *tile;
517 pthread_mutex_t lock;
518 pthread_cond_t cond_wake_up;
519 cairo_tg_worker_status_t status;
521 #ifdef CAIRO_TG_THREAD_POOL_BUSY_WAIT
522 pthread_spinlock_t spinlock;
524 pthread_cond_t cond_done;
528 cairo_tg_worker_t workers[CAIRO_TG_NUM_MAX_WORKERS];
530 pthread_mutex_t workers_lock;
531 cairo_bool_t workers_occupied;
534 _cairo_tg_worker_mainloop (void *arg)
536 cairo_tg_worker_t *worker = (cairo_tg_worker_t *) arg;
540 pthread_mutex_lock (&worker->lock);
542 while (worker->status == CAIRO_TG_WORKER_STATUS_IDLE)
543 pthread_cond_wait (&worker->cond_wake_up, &worker->lock);
545 /* Here, worker is kicked off to do some action. */
547 if (worker->status == CAIRO_TG_WORKER_STATUS_KILLED)
549 /* Worker is killed, so release mutex and exit. */
550 pthread_mutex_unlock (&worker->lock);
554 assert (worker->status == CAIRO_TG_WORKER_STATUS_TO_DO);
556 _cairo_tg_journal_replay (worker->journal, (void *)worker->tile,
557 &worker->tile->tile_rect, &replay_funcs_tile);
559 worker->status = CAIRO_TG_WORKER_STATUS_IDLE;
561 #ifndef CAIRO_TG_THREAD_POOL_BUSY_WAIT
562 pthread_cond_signal (&worker->cond_done);
565 pthread_mutex_unlock (&worker->lock);
572 _cairo_tg_workers_init (void)
576 for (i = 0; i < CAIRO_TG_NUM_MAX_WORKERS; i++)
578 workers[i].status = CAIRO_TG_WORKER_STATUS_IDLE;
580 pthread_mutex_init (&workers[i].lock, NULL);
581 pthread_cond_init (&workers[i].cond_wake_up, NULL);
583 #ifdef CAIRO_TG_THREAD_POOL_BUSY_WAIT
584 pthread_spin_init (&workers[i].spinlock, 0);
586 pthread_cond_init (&workers[i].cond_done, NULL);
589 pthread_create (&workers[i].thread, NULL, _cairo_tg_worker_mainloop, (void *) &workers[i]);
592 pthread_mutex_init (&workers_lock, NULL);
593 workers_occupied = FALSE;
597 _cairo_tg_workers_fini (void)
601 for (i = 0; i < CAIRO_TG_NUM_MAX_WORKERS; i++)
603 pthread_mutex_lock (&workers[i].lock);
605 workers[i].status = CAIRO_TG_WORKER_STATUS_KILLED;
606 pthread_cond_signal (&workers[i].cond_wake_up);
607 pthread_mutex_unlock (&workers[i].lock);
610 for (i = 0; i < CAIRO_TG_NUM_MAX_WORKERS; i++)
611 pthread_join (workers[i].thread, NULL);
613 for (i = 0; i < CAIRO_TG_NUM_MAX_WORKERS; i++)
615 pthread_mutex_destroy (&workers[i].lock);
616 pthread_cond_destroy (&workers[i].cond_wake_up);
618 #ifdef CAIRO_TG_THREAD_POOL_BUSY_WAIT
619 pthread_spin_destroy (&workers[i].spinlock);
621 pthread_cond_destroy (&workers[i].cond_done);
626 static void __attribute__((constructor))
627 _cairo_tg_constructor (void)
629 pthread_atfork (NULL, NULL, _cairo_tg_workers_init);
630 _cairo_tg_workers_init ();
633 static void __attribute__((destructor))
634 _cairo_tg_destructor (void)
636 _cairo_tg_workers_fini ();
639 #endif /* ! CAIRO_HAS_OPENMP */
642 _cairo_tg_surface_prepare_flush_parallel (cairo_tg_surface_t *surface)
644 const cairo_tg_journal_entry_t *entry;
645 const cairo_tg_journal_entry_t *next;
647 cairo_list_foreach_entry_safe (entry, next, cairo_tg_journal_entry_t,
648 &surface->journal.entry_list, link)
650 if (entry->source.base.type == CAIRO_PATTERN_TYPE_SURFACE)
652 cairo_surface_pattern_t *pattern = (cairo_surface_pattern_t *) (&entry->source.base);
653 cairo_surface_flush (pattern->surface);
656 if (entry->type == CAIRO_TG_JOURNAL_ENTRY_MASK)
658 cairo_tg_journal_entry_mask_t *e =
659 (cairo_tg_journal_entry_mask_t *) entry;
661 if (e->mask.base.type == CAIRO_PATTERN_TYPE_SURFACE)
663 cairo_surface_pattern_t *pattern = (cairo_surface_pattern_t *) (&e->mask.base);
664 cairo_surface_flush (pattern->surface);
670 static cairo_int_status_t
671 _cairo_tg_surface_flush_parallel (cairo_tg_surface_t *surface)
674 cairo_tg_surface_tile_t tiles[CAIRO_TG_NUM_MAX_TILES];
675 cairo_rectangle_int_t extents;
677 if (surface->journal.num_entries < CAIRO_TG_NUM_MIN_ENTRIES_FOR_PARALLEL_FLUSH)
678 return CAIRO_INT_STATUS_UNSUPPORTED;
680 _cairo_tg_surface_prepare_flush_parallel (surface);
684 extents.width = surface->width;
685 extents.height = surface->height;
687 _cairo_rectangle_intersect (&extents, &surface->journal.extents);
689 num_tiles = get_num_cpu_cores ();
691 #if ! CAIRO_HAS_OPENMP
692 if (num_tiles > CAIRO_TG_NUM_MAX_WORKERS)
693 num_tiles = CAIRO_TG_NUM_MAX_WORKERS;
696 num_tiles = _cairo_tg_surface_tiles_init (surface, &extents, num_tiles, &tiles[0]);
699 #pragma omp parallel for
700 for (i = 0; i < num_tiles; i++)
702 _cairo_tg_journal_replay (&surface->journal, (void *) &tiles[i],
703 &tiles[i].tile_rect, &replay_funcs_tile);
706 pthread_mutex_lock (&workers_lock);
708 if (workers_occupied)
710 pthread_mutex_unlock (&workers_lock);
711 return CAIRO_INT_STATUS_UNSUPPORTED;
714 workers_occupied = TRUE;
715 pthread_mutex_unlock (&workers_lock);
717 /* Kick workers to start. */
718 for (i = 0; i < num_tiles - 1; i++)
720 pthread_mutex_lock (&workers[i].lock);
722 workers[i].status = CAIRO_TG_WORKER_STATUS_TO_DO;
723 workers[i].journal = &surface->journal;
724 workers[i].tile = &tiles[i];
726 pthread_cond_signal (&workers[i].cond_wake_up);
727 pthread_mutex_unlock (&workers[i].lock);
730 _cairo_tg_journal_replay (&surface->journal, &tiles[num_tiles - 1],
731 &tiles[num_tiles - 1].tile_rect, &replay_funcs_tile);
733 /* Wait for workers to finish. */
734 for (i = 0; i < num_tiles - 1; i++)
736 #ifdef CAIRO_TG_THREAD_POOL_BUSY_WAIT
737 pthread_spin_lock (&workers[i].spinlock);
739 while (workers[i].status == CAIRO_TG_WORKER_STATUS_TO_DO)
741 pthread_spin_unlock (&workers[i].spinlock);
742 pthread_spin_lock (&workers[i].spinlock);
745 pthread_spin_unlock (&workers[i].spinlock);
747 pthread_mutex_lock (&workers[i].lock);
749 while (workers[i].status == CAIRO_TG_WORKER_STATUS_TO_DO)
750 pthread_cond_wait (&workers[i].cond_done, &workers[i].lock);
752 pthread_mutex_unlock (&workers[i].lock);
756 /* Release thread pool. */
757 pthread_mutex_lock (&workers_lock);
758 workers_occupied = FALSE;
759 pthread_mutex_unlock (&workers_lock);
762 return CAIRO_INT_STATUS_SUCCESS;
765 static cairo_status_t
766 _cairo_tg_surface_flush (void *abstract_surface,
769 cairo_tg_surface_t *surface = abstract_surface;
770 cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS;
773 return CAIRO_STATUS_SUCCESS;
775 _cairo_tg_journal_lock (&surface->journal);
777 if (surface->journal.num_entries)
779 status = _cairo_tg_surface_flush_parallel (surface);
783 status = _cairo_tg_journal_replay (&surface->journal,
784 (void *) surface->image_surface,
785 NULL, &replay_funcs_image_fallback);
788 _cairo_tg_journal_clear (&surface->journal);
791 _cairo_tg_journal_unlock (&surface->journal);
796 static cairo_image_surface_t *
797 _cairo_tg_surface_map_to_image (void *abstract_surface,
798 const cairo_rectangle_int_t *extents)
800 cairo_tg_surface_t *other = abstract_surface;
801 cairo_surface_t *surface;
804 _cairo_tg_surface_flush (other, 0);
806 buffer = other->data;
807 buffer += extents->y * other->stride;
808 buffer += extents->x * other->bpp / 8;
811 _cairo_image_surface_create_with_pixman_format (buffer,
812 other->pixman_format,
817 if (unlikely (surface == NULL))
820 cairo_surface_set_device_offset (surface, -extents->x, extents->y);
822 return (cairo_image_surface_t *) surface;
825 static cairo_int_status_t
826 _cairo_tg_surface_unmap_image (void *abstract_surface,
827 cairo_image_surface_t *image)
829 cairo_surface_finish (&image->base);
830 cairo_surface_destroy (&image->base);
832 return CAIRO_INT_STATUS_SUCCESS;
836 _cairo_tg_surface_get_extents (void *abstract_surface,
837 cairo_rectangle_int_t *extents)
839 cairo_tg_surface_t *surface = abstract_surface;
843 extents->width = surface->width;
844 extents->height = surface->height;
849 static cairo_int_status_t
850 _cairo_tg_surface_paint (void *abstract_surface,
852 const cairo_pattern_t *source,
853 const cairo_clip_t *clip)
855 cairo_tg_surface_t *surface = abstract_surface;
856 cairo_int_status_t status = CAIRO_INT_STATUS_UNSUPPORTED;
858 if (! _cairo_pattern_is_self_copy (&surface->base, source) &&
859 ! _cairo_pattern_is_recording (source))
860 status = _cairo_tg_journal_log_paint (&surface->journal, op, source, clip);
864 status = _cairo_tg_surface_flush (surface, 0);
866 if (unlikely (status))
869 status = _cairo_tg_image_surface_paint (surface->image_surface, op, source, clip);
875 static cairo_int_status_t
876 _cairo_tg_surface_mask (void *abstract_surface,
878 const cairo_pattern_t *source,
879 const cairo_pattern_t *mask,
880 const cairo_clip_t *clip)
882 cairo_tg_surface_t *surface = abstract_surface;
883 cairo_int_status_t status = CAIRO_INT_STATUS_UNSUPPORTED;
885 if (! _cairo_pattern_is_self_copy (&surface->base, source) &&
886 ! _cairo_pattern_is_self_copy (&surface->base, mask) &&
887 ! _cairo_pattern_is_recording (source))
888 status = _cairo_tg_journal_log_mask (&surface->journal, op, source, mask, clip);
892 status = _cairo_tg_surface_flush (surface, 0);
894 if (unlikely (status))
897 status = _cairo_tg_image_surface_mask (surface->image_surface, op, source,
904 static cairo_int_status_t
905 _cairo_tg_surface_stroke (void *abstract_surface,
907 const cairo_pattern_t *source,
908 const cairo_path_fixed_t *path,
909 const cairo_stroke_style_t *style,
910 const cairo_matrix_t *ctm,
911 const cairo_matrix_t *ctm_inverse,
913 cairo_antialias_t antialias,
914 const cairo_clip_t *clip)
916 cairo_tg_surface_t *surface = abstract_surface;
917 cairo_int_status_t status = CAIRO_INT_STATUS_UNSUPPORTED;
919 if (! _cairo_pattern_is_self_copy (&surface->base, source) &&
920 ! _cairo_pattern_is_recording (source))
922 status = _cairo_tg_journal_log_stroke (&surface->journal, op, source,
923 path, style, ctm, ctm_inverse,
924 tolerance, antialias, clip);
929 status = _cairo_tg_surface_flush (surface, 0);
931 if (unlikely (status))
934 status = _cairo_tg_image_surface_stroke (surface->image_surface, op, source,
935 path, style, ctm, ctm_inverse,
936 tolerance, antialias, clip);
942 static cairo_int_status_t
943 _cairo_tg_surface_fill (void *abstract_surface,
945 const cairo_pattern_t *source,
946 const cairo_path_fixed_t *path,
947 cairo_fill_rule_t fill_rule,
949 cairo_antialias_t antialias,
950 const cairo_clip_t *clip)
952 cairo_tg_surface_t *surface = abstract_surface;
953 cairo_int_status_t status = CAIRO_INT_STATUS_UNSUPPORTED;
955 if (! _cairo_pattern_is_self_copy (&surface->base, source) &&
956 ! _cairo_pattern_is_recording (source))
958 status = _cairo_tg_journal_log_fill (&surface->journal, op, source,
959 path, fill_rule, tolerance, antialias, clip);
964 status = _cairo_tg_surface_flush (surface, 0);
966 if (unlikely (status))
969 status = _cairo_tg_image_surface_fill (surface->image_surface, op, source,
970 path, fill_rule, tolerance, antialias, clip);
976 static cairo_int_status_t
977 _cairo_tg_surface_glyphs (void *abstract_surface,
979 const cairo_pattern_t *source,
980 cairo_glyph_t *glyphs,
982 cairo_scaled_font_t *scaled_font,
983 const cairo_clip_t *clip)
985 cairo_tg_surface_t *surface = abstract_surface;
986 cairo_int_status_t status = CAIRO_INT_STATUS_UNSUPPORTED;
988 if (! _cairo_pattern_is_self_copy (&surface->base, source) &&
989 ! _cairo_pattern_is_recording (source))
991 status = _cairo_tg_journal_log_glyphs (&surface->journal, op, source,
992 glyphs, num_glyphs, scaled_font, clip);
997 status = _cairo_tg_surface_flush (surface, 0);
999 if (unlikely (status))
1002 status = _cairo_tg_image_surface_glyphs (surface->image_surface, op, source,
1003 glyphs, num_glyphs, scaled_font, clip);
1009 static cairo_surface_t *
1010 _cairo_tg_surface_create_similar (void *abstract_other,
1011 cairo_content_t content,
1015 cairo_tg_surface_t *other = abstract_other;
1017 if (! _cairo_tg_surface_is_size_valid (width, height))
1018 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE));
1020 if (content == other->base.content)
1021 return cairo_tg_surface_create (other->format, width, height);
1023 return cairo_tg_surface_create (_cairo_format_from_content (content), width, height);
1026 static cairo_surface_t *
1027 _cairo_tg_surface_source (void *abstract_surface,
1028 cairo_rectangle_int_t *extents)
1030 cairo_tg_surface_t *surface = abstract_surface;
1034 extents->x = extents->y = 0;
1035 extents->width = surface->width;
1036 extents->height = surface->height;
1039 return &surface->base;
1042 static cairo_status_t
1043 _cairo_tg_surface_acquire_source_image (void *abstract_surface,
1044 cairo_image_surface_t **image_out,
1047 cairo_tg_surface_t *surface = abstract_surface;
1049 _cairo_tg_surface_flush (surface, 0);
1051 *image_out = (cairo_image_surface_t *) surface->image_surface;
1052 *image_extra = NULL;
1054 return CAIRO_STATUS_SUCCESS;
1058 _cairo_tg_surface_release_source_image (void *abstract_surface,
1059 cairo_image_surface_t *image,
1065 static cairo_surface_t *
1066 _cairo_tg_surface_snapshot (void *abstract_surface)
1068 cairo_tg_surface_t *surface = abstract_surface;
1069 cairo_tg_surface_t *clone;
1071 _cairo_tg_surface_flush (surface, 0);
1073 if (_cairo_tg_surface_owns_data (surface) && surface->base._finishing)
1075 return cairo_tg_surface_create_for_data (surface->data, surface->format,
1076 surface->width, surface->height,
1080 clone = (cairo_tg_surface_t *)
1081 cairo_tg_surface_create (surface->format, surface->width, surface->height);
1083 if (unlikely (clone->base.status))
1084 return &clone->base;
1086 if (surface->stride == clone->stride)
1088 memcpy (clone->data, surface->data, clone->stride * clone->height);
1092 unsigned char *dst = clone->data;
1093 unsigned char *src = surface->data;
1095 int stride = clone->stride < surface->stride ? clone->stride : surface->stride;
1097 for (i = 0; i < clone->height; i++)
1099 memcpy (dst, src, stride);
1100 dst += clone->stride;
1101 src += surface->stride;
1105 clone->base.is_clear = FALSE;
1107 return &clone->base;
1110 static cairo_int_status_t
1111 _cairo_tg_surface_init_tile_surfaces (cairo_tg_surface_t *surface)
1114 cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS;
1116 memset (&surface->tile_surfaces[0], 0x00,
1117 sizeof (cairo_surface_t *) * CAIRO_TG_NUM_MAX_TILES);
1119 for (i = 0; i < CAIRO_TG_NUM_MAX_TILES; i++)
1121 surface->tile_surfaces[i] = cairo_image_surface_create_for_data (surface->data,
1127 if (surface->tile_surfaces[i] == NULL)
1129 status = CAIRO_INT_STATUS_NO_MEMORY;
1134 if (unlikely (status))
1136 for (i = 0; i < CAIRO_TG_NUM_MAX_TILES; i++)
1138 if (surface->tile_surfaces[i])
1139 cairo_surface_destroy (surface->tile_surfaces[i]);
1149 _cairo_tg_surface_fini_tile_surfaces (cairo_tg_surface_t *surface)
1153 for (i = 0; i < CAIRO_TG_NUM_MAX_TILES; i++)
1155 if (surface->tile_surfaces[i])
1156 cairo_surface_destroy (surface->tile_surfaces[i]);
1162 static cairo_status_t
1163 _cairo_tg_surface_finish (void *abstract_surface)
1165 cairo_tg_surface_t *surface = abstract_surface;
1167 _cairo_tg_surface_flush (surface, 0);
1168 _cairo_tg_journal_fini (&surface->journal);
1169 _cairo_tg_surface_fini_tile_surfaces (surface);
1170 cairo_surface_destroy (surface->image_surface);
1172 return CAIRO_STATUS_SUCCESS;
1175 static const cairo_surface_backend_t _cairo_tg_surface_backend =
1177 CAIRO_SURFACE_TYPE_TG,
1178 _cairo_tg_surface_finish,
1180 _cairo_default_context_create,
1182 _cairo_tg_surface_create_similar,
1183 NULL, /* create_similar image */
1184 _cairo_tg_surface_map_to_image,
1185 _cairo_tg_surface_unmap_image,
1187 _cairo_tg_surface_source,
1188 _cairo_tg_surface_acquire_source_image,
1189 _cairo_tg_surface_release_source_image,
1190 _cairo_tg_surface_snapshot,
1192 NULL, /* copy_page */
1193 NULL, /* show_page */
1195 _cairo_tg_surface_get_extents,
1196 NULL, /* get_font_options */
1198 _cairo_tg_surface_flush,
1199 NULL, /* mark_dirty_rectangle */
1201 _cairo_tg_surface_paint,
1202 _cairo_tg_surface_mask,
1203 _cairo_tg_surface_stroke,
1204 _cairo_tg_surface_fill,
1205 NULL, /* fill_stroke */
1206 _cairo_tg_surface_glyphs,
1210 cairo_tg_surface_create (cairo_format_t format,
1214 cairo_tg_surface_t *surface;
1215 cairo_surface_t *image_surface;
1217 image_surface = cairo_image_surface_create (format, width, height);
1219 if (unlikely (image_surface == NULL))
1220 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
1222 surface = malloc (sizeof (cairo_tg_surface_t));
1224 if (unlikely (surface == NULL))
1226 cairo_surface_destroy (image_surface);
1228 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
1231 _cairo_surface_init (&surface->base,
1232 &_cairo_tg_surface_backend,
1233 NULL, image_surface->content);
1235 surface->format = format;
1236 surface->pixman_format = ((cairo_image_surface_t *) image_surface)->pixman_format;
1237 surface->data = (unsigned char *) cairo_image_surface_get_data (image_surface);
1238 surface->width = width;
1239 surface->height = height;
1240 surface->stride = cairo_image_surface_get_stride (image_surface);
1241 surface->bpp = get_bpp_for_format (format);
1242 surface->image_surface = image_surface;
1243 surface->base.is_clear = image_surface->is_clear;
1245 _cairo_tg_journal_init (&surface->journal);
1247 if (_cairo_tg_surface_init_tile_surfaces (surface))
1249 cairo_surface_destroy (image_surface);
1250 _cairo_tg_journal_fini (&surface->journal);
1252 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
1255 return &surface->base;
1259 cairo_tg_surface_create_for_data (unsigned char *data,
1260 cairo_format_t format,
1265 cairo_tg_surface_t *surface;
1266 cairo_surface_t *image_surface;
1268 image_surface = cairo_image_surface_create_for_data (data, format, width, height, stride);
1270 if (unlikely (image_surface == NULL))
1271 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
1273 surface = malloc (sizeof (cairo_tg_surface_t));
1275 if (unlikely (surface == NULL))
1277 cairo_surface_destroy (image_surface);
1279 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
1282 _cairo_surface_init (&surface->base,
1283 &_cairo_tg_surface_backend,
1284 NULL, image_surface->content);
1286 surface->format = format;
1287 surface->pixman_format = ((cairo_image_surface_t *) image_surface)->pixman_format;
1288 surface->data = (unsigned char *) cairo_image_surface_get_data (image_surface);
1289 surface->width = width;
1290 surface->height = height;
1291 surface->stride = cairo_image_surface_get_stride (image_surface);
1292 surface->bpp = get_bpp_for_format (format);
1293 surface->image_surface = image_surface;
1294 surface->base.is_clear = image_surface->is_clear;
1296 _cairo_tg_journal_init (&surface->journal);
1298 if (_cairo_tg_surface_init_tile_surfaces (surface))
1300 cairo_surface_destroy (image_surface);
1301 _cairo_tg_journal_fini (&surface->journal);
1303 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
1306 return &surface->base;
1310 cairo_tg_surface_get_data (cairo_surface_t *surface)
1312 cairo_tg_surface_t *tg_surface = (cairo_tg_surface_t *) surface;
1314 if (! _cairo_surface_is_tg (surface)) {
1315 _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
1319 return tg_surface->data;
1323 cairo_tg_surface_get_format (cairo_surface_t *surface)
1325 cairo_tg_surface_t *tg_surface = (cairo_tg_surface_t *) surface;
1327 if (! _cairo_surface_is_tg (surface)) {
1328 _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
1329 return CAIRO_FORMAT_INVALID;
1332 return tg_surface->format;
1336 cairo_tg_surface_get_width (cairo_surface_t *surface)
1338 cairo_tg_surface_t *tg_surface = (cairo_tg_surface_t *) surface;
1340 if (! _cairo_surface_is_tg (surface)) {
1341 _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
1345 return tg_surface->width;
1349 cairo_tg_surface_get_height (cairo_surface_t *surface)
1351 cairo_tg_surface_t *tg_surface = (cairo_tg_surface_t *) surface;
1353 if (! _cairo_surface_is_tg (surface)) {
1354 _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
1358 return tg_surface->height;
1362 cairo_tg_surface_get_stride (cairo_surface_t *surface)
1364 cairo_tg_surface_t *tg_surface = (cairo_tg_surface_t *) surface;
1366 if (! _cairo_surface_is_tg (surface)) {
1367 _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
1371 return tg_surface->stride;