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-tg-private.h"
32 #include "cairo-tg-journal-private.h"
33 #include "cairo-tg-allocator-private.h"
34 #include "cairo-tg-composite-extents-private.h"
36 static inline cairo_int_status_t
37 _cairo_tg_journal_pattern_snapshot (cairo_pattern_t *dst,
38 const cairo_pattern_t *src)
40 return _cairo_pattern_init_snapshot (dst, src);
43 /* Allocator for various types of journal entries. */
44 static cairo_tg_journal_entry_t *
45 _cairo_tg_journal_entry_alloc (cairo_tg_mono_allocator_t *allocator,
46 cairo_tg_journal_entry_type_t type)
48 cairo_tg_journal_entry_t *entry = NULL;
52 case CAIRO_TG_JOURNAL_ENTRY_PAINT:
53 entry = _cairo_tg_mono_allocator_alloc (allocator,
54 sizeof (cairo_tg_journal_entry_paint_t));
56 case CAIRO_TG_JOURNAL_ENTRY_MASK:
57 entry = _cairo_tg_mono_allocator_alloc (allocator,
58 sizeof (cairo_tg_journal_entry_mask_t));
60 case CAIRO_TG_JOURNAL_ENTRY_STROKE:
61 entry = _cairo_tg_mono_allocator_alloc (allocator,
62 sizeof (cairo_tg_journal_entry_stroke_t));
64 case CAIRO_TG_JOURNAL_ENTRY_FILL:
65 entry = _cairo_tg_mono_allocator_alloc (allocator,
66 sizeof (cairo_tg_journal_entry_fill_t));
68 case CAIRO_TG_JOURNAL_ENTRY_GLYPHS:
69 entry = _cairo_tg_mono_allocator_alloc (allocator,
70 sizeof (cairo_tg_journal_entry_glyphs_t));
77 /* One should not change the type of an entry.
78 * It is determined at the moment of allocation. */
85 _cairo_tg_journal_entry_fini (cairo_tg_journal_entry_t *entry)
88 _cairo_pattern_fini (&entry->source.base);
91 _cairo_clip_destroy (entry->clip);
93 /* For each entry types... */
96 case CAIRO_TG_JOURNAL_ENTRY_PAINT:
98 case CAIRO_TG_JOURNAL_ENTRY_MASK:
100 cairo_tg_journal_entry_mask_t *entry_mask =
101 (cairo_tg_journal_entry_mask_t *) entry;
103 _cairo_pattern_fini (&entry_mask->mask.base);
106 case CAIRO_TG_JOURNAL_ENTRY_STROKE:
108 cairo_tg_journal_entry_stroke_t *entry_stroke =
109 (cairo_tg_journal_entry_stroke_t *) entry;
111 _cairo_path_fixed_fini (&entry_stroke->path);
112 _cairo_stroke_style_fini (&entry_stroke->style);
115 case CAIRO_TG_JOURNAL_ENTRY_FILL:
117 cairo_tg_journal_entry_fill_t *entry_fill =
118 (cairo_tg_journal_entry_fill_t *) entry;
120 _cairo_path_fixed_fini (&entry_fill->path);
123 case CAIRO_TG_JOURNAL_ENTRY_GLYPHS:
125 cairo_tg_journal_entry_glyphs_t *entry_glyphs =
126 (cairo_tg_journal_entry_glyphs_t *) entry;
128 free (entry_glyphs->glyphs);
129 cairo_scaled_font_destroy (entry_glyphs->scaled_font);
138 _cairo_tg_journal_init (cairo_tg_journal_t *journal)
140 cairo_int_status_t status;
142 CAIRO_MUTEX_INIT (journal->mutex);
143 journal->num_entries = 0;
144 cairo_list_init (&journal->entry_list);
145 journal->extents = _cairo_empty_rectangle;
147 status = _cairo_tg_mono_allocator_init (&journal->allocator, 4096 -
148 sizeof (cairo_tg_mem_chunk_t));
154 _cairo_tg_journal_fini (cairo_tg_journal_t *journal)
156 cairo_tg_journal_entry_t *entry;
157 cairo_tg_journal_entry_t *next;
159 CAIRO_MUTEX_FINI (journal->mutex);
160 cairo_list_foreach_entry_safe (entry, next, cairo_tg_journal_entry_t,
161 &journal->entry_list, link)
163 _cairo_tg_journal_entry_fini (entry);
166 _cairo_tg_mono_allocator_fini (&journal->allocator);
170 _cairo_tg_journal_lock (cairo_tg_journal_t *journal)
172 CAIRO_MUTEX_LOCK (journal->mutex);
176 _cairo_tg_journal_unlock (cairo_tg_journal_t *journal)
178 CAIRO_MUTEX_UNLOCK (journal->mutex);
182 _cairo_tg_journal_log_paint (cairo_tg_journal_t *journal,
184 const cairo_pattern_t *source,
185 const cairo_clip_t *clip)
187 cairo_int_status_t status;
188 cairo_tg_journal_entry_paint_t *entry;
190 entry = (cairo_tg_journal_entry_paint_t *)
191 _cairo_tg_journal_entry_alloc (&journal->allocator, CAIRO_TG_JOURNAL_ENTRY_PAINT);
193 if (unlikely (entry == NULL))
194 return CAIRO_INT_STATUS_NO_MEMORY;
196 status = _cairo_tg_journal_pattern_snapshot (&entry->base.source.base, source);
198 if (unlikely (status))
202 entry->base.clip = _cairo_clip_copy (clip);
203 _cairo_tg_approximate_paint_extents (&entry->base.extents, op, source, clip);
204 _cairo_rectangle_union (&journal->extents, &entry->base.extents);
206 cairo_list_add_tail (&entry->base.link, &journal->entry_list);
207 journal->num_entries++;
209 return CAIRO_INT_STATUS_SUCCESS;
213 _cairo_tg_journal_log_mask (cairo_tg_journal_t *journal,
215 const cairo_pattern_t *source,
216 const cairo_pattern_t *mask,
217 const cairo_clip_t *clip)
219 cairo_int_status_t status;
220 cairo_tg_journal_entry_mask_t *entry;
222 entry = (cairo_tg_journal_entry_mask_t *)
223 _cairo_tg_journal_entry_alloc (&journal->allocator, CAIRO_TG_JOURNAL_ENTRY_MASK);
225 if (unlikely (entry == NULL))
226 return CAIRO_INT_STATUS_NO_MEMORY;
228 status = _cairo_tg_journal_pattern_snapshot (&entry->base.source.base, source);
230 if (unlikely (status))
233 status = _cairo_tg_journal_pattern_snapshot (&entry->mask.base, mask);
235 if (unlikely (status))
237 _cairo_pattern_fini (&entry->base.source.base);
242 entry->base.clip = _cairo_clip_copy (clip);
243 _cairo_tg_approximate_mask_extents (&entry->base.extents, op, source, mask, clip);
244 _cairo_rectangle_union (&journal->extents, &entry->base.extents);
246 cairo_list_add_tail (&entry->base.link, &journal->entry_list);
247 journal->num_entries++;
249 return CAIRO_INT_STATUS_SUCCESS;
253 _cairo_tg_journal_log_stroke (cairo_tg_journal_t *journal,
255 const cairo_pattern_t *source,
256 const cairo_path_fixed_t *path,
257 const cairo_stroke_style_t *style,
258 const cairo_matrix_t *ctm,
259 const cairo_matrix_t *ctm_inverse,
261 cairo_antialias_t antialias,
262 const cairo_clip_t *clip)
264 cairo_int_status_t status;
265 cairo_tg_journal_entry_stroke_t *entry;
267 entry = (cairo_tg_journal_entry_stroke_t *)
268 _cairo_tg_journal_entry_alloc (&journal->allocator, CAIRO_TG_JOURNAL_ENTRY_STROKE);
270 if (unlikely (entry == NULL))
271 return CAIRO_INT_STATUS_NO_MEMORY;
273 status = _cairo_tg_journal_pattern_snapshot (&entry->base.source.base, source);
275 if (unlikely (status))
278 status = _cairo_path_fixed_init_copy (&entry->path, path);
280 if (unlikely (status))
282 _cairo_pattern_fini (&entry->base.source.base);
286 status = _cairo_stroke_style_init_copy (&entry->style, style);
288 if (unlikely (status))
290 _cairo_path_fixed_fini (&entry->path);
291 _cairo_pattern_fini (&entry->base.source.base);
296 entry->base.clip = _cairo_clip_copy (clip);
298 entry->ctm_inverse = *ctm_inverse;
299 entry->tolerance = tolerance;
300 entry->antialias = antialias;
301 _cairo_tg_approximate_stroke_extents (&entry->base.extents, op, source,
302 path, style, ctm, ctm_inverse,
303 tolerance, antialias, clip);
304 _cairo_rectangle_union (&journal->extents, &entry->base.extents);
306 cairo_list_add_tail (&entry->base.link, &journal->entry_list);
307 journal->num_entries++;
309 return CAIRO_INT_STATUS_SUCCESS;
313 _cairo_tg_journal_log_fill (cairo_tg_journal_t *journal,
315 const cairo_pattern_t *source,
316 const cairo_path_fixed_t *path,
317 cairo_fill_rule_t fill_rule,
319 cairo_antialias_t antialias,
320 const cairo_clip_t *clip)
322 cairo_int_status_t status;
323 cairo_tg_journal_entry_fill_t *entry;
325 entry = (cairo_tg_journal_entry_fill_t *)
326 _cairo_tg_journal_entry_alloc (&journal->allocator, CAIRO_TG_JOURNAL_ENTRY_FILL);
328 if (unlikely (entry == NULL))
329 return CAIRO_INT_STATUS_NO_MEMORY;
331 status = _cairo_tg_journal_pattern_snapshot (&entry->base.source.base, source);
333 if (unlikely (status))
336 status = _cairo_path_fixed_init_copy (&entry->path, path);
338 if (unlikely (status))
340 _cairo_pattern_fini (&entry->base.source.base);
345 entry->base.clip = _cairo_clip_copy (clip);
346 entry->fill_rule = fill_rule;
347 entry->tolerance = tolerance;
348 entry->antialias = antialias;
349 _cairo_tg_approximate_fill_extents (&entry->base.extents, op, source,
350 path, fill_rule, tolerance, antialias, clip);
351 _cairo_rectangle_union (&journal->extents, &entry->base.extents);
353 cairo_list_add_tail (&entry->base.link, &journal->entry_list);
354 journal->num_entries++;
356 return CAIRO_INT_STATUS_SUCCESS;
360 _cairo_tg_journal_log_glyphs (cairo_tg_journal_t *journal,
362 const cairo_pattern_t *source,
363 cairo_glyph_t *glyphs,
365 cairo_scaled_font_t *scaled_font,
366 const cairo_clip_t *clip)
368 cairo_int_status_t status;
369 cairo_tg_journal_entry_glyphs_t *entry;
371 entry = (cairo_tg_journal_entry_glyphs_t *)
372 _cairo_tg_journal_entry_alloc (&journal->allocator, CAIRO_TG_JOURNAL_ENTRY_GLYPHS);
374 if (unlikely (entry == NULL))
375 return CAIRO_INT_STATUS_NO_MEMORY;
377 status = _cairo_tg_journal_pattern_snapshot (&entry->base.source.base, source);
379 if (unlikely (status))
382 entry->scaled_font = cairo_scaled_font_reference (scaled_font);
384 if (unlikely (entry->scaled_font == NULL))
386 _cairo_pattern_fini (&entry->base.source.base);
387 return CAIRO_INT_STATUS_NO_MEMORY;
392 entry->glyphs = malloc (sizeof (cairo_glyph_t) * num_glyphs);
394 if (unlikely (entry->glyphs == NULL))
396 cairo_scaled_font_destroy (entry->scaled_font);
397 _cairo_pattern_fini (&entry->base.source.base);
398 return CAIRO_INT_STATUS_NO_MEMORY;
401 memcpy (entry->glyphs, glyphs, sizeof (cairo_glyph_t) * num_glyphs);
405 entry->glyphs = NULL;
408 entry->num_glyphs = num_glyphs;
410 entry->base.clip = _cairo_clip_copy (clip);
411 _cairo_tg_approximate_glyphs_extents (&entry->base.extents, op, source,
412 glyphs, num_glyphs, scaled_font, clip);
413 _cairo_rectangle_union (&journal->extents, &entry->base.extents);
415 cairo_list_add_tail (&entry->base.link, &journal->entry_list);
416 journal->num_entries++;
418 return CAIRO_INT_STATUS_SUCCESS;
422 _cairo_tg_journal_clear (cairo_tg_journal_t *journal)
424 cairo_tg_journal_entry_t *entry;
425 cairo_tg_journal_entry_t *next;
427 cairo_list_foreach_entry_safe (entry, next, cairo_tg_journal_entry_t,
428 &journal->entry_list, link)
430 _cairo_tg_journal_entry_fini (entry);
433 journal->num_entries = 0;
434 cairo_list_init (&journal->entry_list);
435 _cairo_tg_mono_allocator_reset(&journal->allocator);
436 journal->extents = _cairo_empty_rectangle;
440 _cairo_tg_journal_replay (const cairo_tg_journal_t *journal,
442 const cairo_rectangle_int_t *extents,
443 const cairo_tg_journal_replay_funcs_t *funcs)
445 const cairo_tg_journal_entry_t *entry;
446 const cairo_tg_journal_entry_t *next;
447 cairo_int_status_t status;
449 cairo_list_foreach_entry_safe (entry, next, cairo_tg_journal_entry_t,
450 &journal->entry_list, link)
452 if (extents && ! _cairo_rectangle_intersects (extents, &entry->extents))
459 case CAIRO_TG_JOURNAL_ENTRY_PAINT:
461 cairo_tg_journal_entry_paint_t *e =
462 (cairo_tg_journal_entry_paint_t *) entry;
464 status = funcs->paint (closure, e->base.op, &e->base.source.base,
468 case CAIRO_TG_JOURNAL_ENTRY_MASK:
470 cairo_tg_journal_entry_mask_t *e =
471 (cairo_tg_journal_entry_mask_t *) entry;
473 status = funcs->mask (closure, e->base.op, &e->base.source.base,
474 &e->mask.base, e->base.clip);
477 case CAIRO_TG_JOURNAL_ENTRY_STROKE:
479 cairo_tg_journal_entry_stroke_t *e =
480 (cairo_tg_journal_entry_stroke_t *) entry;
482 status = funcs->stroke (closure, e->base.op, &e->base.source.base,
483 &e->path, &e->style, &e->ctm, &e->ctm_inverse,
484 e->tolerance, e->antialias, e->base.clip);
487 case CAIRO_TG_JOURNAL_ENTRY_FILL:
489 cairo_tg_journal_entry_fill_t *e =
490 (cairo_tg_journal_entry_fill_t *) entry;
492 status = funcs->fill (closure, e->base.op, &e->base.source.base,
493 &e->path, e->fill_rule,
494 e->tolerance, e->antialias, e->base.clip);
497 case CAIRO_TG_JOURNAL_ENTRY_GLYPHS:
499 cairo_tg_journal_entry_glyphs_t *e =
500 (cairo_tg_journal_entry_glyphs_t *) entry;
502 status = funcs->glyphs (closure, e->base.op, &e->base.source.base,
503 e->glyphs, e->num_glyphs,
504 e->scaled_font, e->base.clip);
512 if (unlikely (status) && status != CAIRO_INT_STATUS_NOTHING_TO_DO)
519 return CAIRO_INT_STATUS_SUCCESS;