tizen 2.3.1 release
[framework/graphics/cairo.git] / src / cairo-tg-journal.c
1 /*
2  * Copyright © 2012 SCore Corporation
3  *
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.
11  *
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
17  *
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/
22  *
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.
26  *
27  * Author: Taekyun Kim (podain77@gmail.com)
28  */
29
30 #include "cairo-tg.h"
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"
35
36 static inline cairo_int_status_t
37 _cairo_tg_journal_pattern_snapshot (cairo_pattern_t         *dst,
38                                     const cairo_pattern_t   *src)
39 {
40     return _cairo_pattern_init_snapshot (dst, src);
41 }
42
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)
47 {
48     cairo_tg_journal_entry_t *entry = NULL;
49
50     switch (type)
51     {
52     case CAIRO_TG_JOURNAL_ENTRY_PAINT:
53         entry = _cairo_tg_mono_allocator_alloc (allocator,
54                                                 sizeof (cairo_tg_journal_entry_paint_t));
55         break;
56     case CAIRO_TG_JOURNAL_ENTRY_MASK:
57         entry = _cairo_tg_mono_allocator_alloc (allocator,
58                                                 sizeof (cairo_tg_journal_entry_mask_t));
59         break;
60     case CAIRO_TG_JOURNAL_ENTRY_STROKE:
61         entry = _cairo_tg_mono_allocator_alloc (allocator,
62                                                 sizeof (cairo_tg_journal_entry_stroke_t));
63         break;
64     case CAIRO_TG_JOURNAL_ENTRY_FILL:
65         entry = _cairo_tg_mono_allocator_alloc (allocator,
66                                                 sizeof (cairo_tg_journal_entry_fill_t));
67         break;
68     case CAIRO_TG_JOURNAL_ENTRY_GLYPHS:
69         entry = _cairo_tg_mono_allocator_alloc (allocator,
70                                                 sizeof (cairo_tg_journal_entry_glyphs_t));
71         break;
72     default:
73         ASSERT_NOT_REACHED;
74         return NULL;
75     }
76
77     /* One should not change the type of an entry.
78      * It is determined at the moment of allocation. */
79     entry->type = type;
80
81     return entry;
82 }
83
84 static void
85 _cairo_tg_journal_entry_fini (cairo_tg_journal_entry_t *entry)
86 {
87     /* common part. */
88     _cairo_pattern_fini (&entry->source.base);
89
90     if (entry->clip)
91         _cairo_clip_destroy (entry->clip);
92
93     /* For each entry types... */
94     switch (entry->type)
95     {
96     case CAIRO_TG_JOURNAL_ENTRY_PAINT:
97         break;
98     case CAIRO_TG_JOURNAL_ENTRY_MASK:
99         {
100             cairo_tg_journal_entry_mask_t *entry_mask =
101                 (cairo_tg_journal_entry_mask_t *) entry;
102
103             _cairo_pattern_fini (&entry_mask->mask.base);
104         }
105         break;
106     case CAIRO_TG_JOURNAL_ENTRY_STROKE:
107         {
108             cairo_tg_journal_entry_stroke_t *entry_stroke =
109                 (cairo_tg_journal_entry_stroke_t *) entry;
110
111             _cairo_path_fixed_fini (&entry_stroke->path);
112             _cairo_stroke_style_fini (&entry_stroke->style);
113         }
114         break;
115     case CAIRO_TG_JOURNAL_ENTRY_FILL:
116         {
117             cairo_tg_journal_entry_fill_t *entry_fill =
118                 (cairo_tg_journal_entry_fill_t *) entry;
119
120             _cairo_path_fixed_fini (&entry_fill->path);
121         }
122         break;
123     case CAIRO_TG_JOURNAL_ENTRY_GLYPHS:
124         {
125             cairo_tg_journal_entry_glyphs_t *entry_glyphs =
126                 (cairo_tg_journal_entry_glyphs_t *) entry;
127
128             free (entry_glyphs->glyphs);
129             cairo_scaled_font_destroy (entry_glyphs->scaled_font);
130         }
131         break;
132     default:
133         ASSERT_NOT_REACHED;
134     }
135 }
136
137 cairo_int_status_t
138 _cairo_tg_journal_init (cairo_tg_journal_t *journal)
139 {
140     cairo_int_status_t status;
141
142     CAIRO_MUTEX_INIT (journal->mutex);
143     journal->num_entries = 0;
144     cairo_list_init (&journal->entry_list);
145     journal->extents = _cairo_empty_rectangle;
146
147     status =  _cairo_tg_mono_allocator_init (&journal->allocator, 4096 -
148                                              sizeof (cairo_tg_mem_chunk_t));
149
150     return status;
151 }
152
153 void
154 _cairo_tg_journal_fini (cairo_tg_journal_t *journal)
155 {
156     cairo_tg_journal_entry_t *entry;
157     cairo_tg_journal_entry_t *next;
158
159     CAIRO_MUTEX_FINI (journal->mutex);
160     cairo_list_foreach_entry_safe (entry, next, cairo_tg_journal_entry_t,
161                                    &journal->entry_list, link)
162     {
163         _cairo_tg_journal_entry_fini (entry);
164     }
165
166     _cairo_tg_mono_allocator_fini (&journal->allocator);
167 }
168
169 void
170 _cairo_tg_journal_lock (cairo_tg_journal_t *journal)
171 {
172     CAIRO_MUTEX_LOCK (journal->mutex);
173 }
174
175 void
176 _cairo_tg_journal_unlock (cairo_tg_journal_t *journal)
177 {
178     CAIRO_MUTEX_UNLOCK (journal->mutex);
179 }
180
181 cairo_int_status_t
182 _cairo_tg_journal_log_paint (cairo_tg_journal_t     *journal,
183                              cairo_operator_t       op,
184                              const cairo_pattern_t  *source,
185                              const cairo_clip_t     *clip)
186 {
187     cairo_int_status_t              status;
188     cairo_tg_journal_entry_paint_t  *entry;
189
190     entry = (cairo_tg_journal_entry_paint_t *)
191         _cairo_tg_journal_entry_alloc (&journal->allocator, CAIRO_TG_JOURNAL_ENTRY_PAINT);
192
193     if (unlikely (entry == NULL))
194         return CAIRO_INT_STATUS_NO_MEMORY;
195
196     status = _cairo_tg_journal_pattern_snapshot (&entry->base.source.base, source);
197
198     if (unlikely (status))
199         return status;
200
201     entry->base.op = op;
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);
205
206     cairo_list_add_tail (&entry->base.link, &journal->entry_list);
207     journal->num_entries++;
208
209     return CAIRO_INT_STATUS_SUCCESS;
210 }
211
212 cairo_int_status_t
213 _cairo_tg_journal_log_mask (cairo_tg_journal_t      *journal,
214                             cairo_operator_t        op,
215                             const cairo_pattern_t   *source,
216                             const cairo_pattern_t   *mask,
217                             const cairo_clip_t      *clip)
218 {
219     cairo_int_status_t              status;
220     cairo_tg_journal_entry_mask_t   *entry;
221
222     entry = (cairo_tg_journal_entry_mask_t *)
223         _cairo_tg_journal_entry_alloc (&journal->allocator, CAIRO_TG_JOURNAL_ENTRY_MASK);
224
225     if (unlikely (entry == NULL))
226         return CAIRO_INT_STATUS_NO_MEMORY;
227
228     status = _cairo_tg_journal_pattern_snapshot (&entry->base.source.base, source);
229
230     if (unlikely (status))
231         return status;
232
233     status = _cairo_tg_journal_pattern_snapshot (&entry->mask.base, mask);
234
235     if (unlikely (status))
236     {
237         _cairo_pattern_fini (&entry->base.source.base);
238         return status;
239     }
240
241     entry->base.op = op;
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);
245
246     cairo_list_add_tail (&entry->base.link, &journal->entry_list);
247     journal->num_entries++;
248
249     return CAIRO_INT_STATUS_SUCCESS;
250 }
251
252 cairo_int_status_t
253 _cairo_tg_journal_log_stroke (cairo_tg_journal_t            *journal,
254                               cairo_operator_t              op,
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,
260                               double                        tolerance,
261                               cairo_antialias_t             antialias,
262                               const cairo_clip_t            *clip)
263 {
264     cairo_int_status_t              status;
265     cairo_tg_journal_entry_stroke_t *entry;
266
267     entry = (cairo_tg_journal_entry_stroke_t *)
268         _cairo_tg_journal_entry_alloc (&journal->allocator, CAIRO_TG_JOURNAL_ENTRY_STROKE);
269
270     if (unlikely (entry == NULL))
271         return CAIRO_INT_STATUS_NO_MEMORY;
272
273     status = _cairo_tg_journal_pattern_snapshot (&entry->base.source.base, source);
274
275     if (unlikely (status))
276         return status;
277
278     status = _cairo_path_fixed_init_copy (&entry->path, path);
279
280     if (unlikely (status))
281     {
282         _cairo_pattern_fini (&entry->base.source.base);
283         return status;
284     }
285
286     status = _cairo_stroke_style_init_copy (&entry->style, style);
287
288     if (unlikely (status))
289     {
290         _cairo_path_fixed_fini (&entry->path);
291         _cairo_pattern_fini (&entry->base.source.base);
292         return status;
293     }
294
295     entry->base.op = op;
296     entry->base.clip = _cairo_clip_copy (clip);
297     entry->ctm = *ctm;
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);
305
306     cairo_list_add_tail (&entry->base.link, &journal->entry_list);
307     journal->num_entries++;
308
309     return CAIRO_INT_STATUS_SUCCESS;
310 }
311
312 cairo_int_status_t
313 _cairo_tg_journal_log_fill (cairo_tg_journal_t          *journal,
314                             cairo_operator_t            op,
315                             const cairo_pattern_t       *source,
316                             const cairo_path_fixed_t    *path,
317                             cairo_fill_rule_t           fill_rule,
318                             double                      tolerance,
319                             cairo_antialias_t           antialias,
320                             const cairo_clip_t          *clip)
321 {
322     cairo_int_status_t              status;
323     cairo_tg_journal_entry_fill_t   *entry;
324
325     entry = (cairo_tg_journal_entry_fill_t *)
326         _cairo_tg_journal_entry_alloc (&journal->allocator, CAIRO_TG_JOURNAL_ENTRY_FILL);
327
328     if (unlikely (entry == NULL))
329         return CAIRO_INT_STATUS_NO_MEMORY;
330
331     status = _cairo_tg_journal_pattern_snapshot (&entry->base.source.base, source);
332
333     if (unlikely (status))
334         return status;
335
336     status = _cairo_path_fixed_init_copy (&entry->path, path);
337
338     if (unlikely (status))
339     {
340         _cairo_pattern_fini (&entry->base.source.base);
341         return status;
342     }
343
344     entry->base.op = op;
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);
352
353     cairo_list_add_tail (&entry->base.link, &journal->entry_list);
354     journal->num_entries++;
355
356     return CAIRO_INT_STATUS_SUCCESS;
357 }
358
359 cairo_int_status_t
360 _cairo_tg_journal_log_glyphs (cairo_tg_journal_t    *journal,
361                               cairo_operator_t      op,
362                               const cairo_pattern_t *source,
363                               cairo_glyph_t         *glyphs,
364                               int                   num_glyphs,
365                               cairo_scaled_font_t   *scaled_font,
366                               const cairo_clip_t    *clip)
367 {
368     cairo_int_status_t              status;
369     cairo_tg_journal_entry_glyphs_t *entry;
370
371     entry = (cairo_tg_journal_entry_glyphs_t *)
372         _cairo_tg_journal_entry_alloc (&journal->allocator, CAIRO_TG_JOURNAL_ENTRY_GLYPHS);
373
374     if (unlikely (entry == NULL))
375         return CAIRO_INT_STATUS_NO_MEMORY;
376
377     status = _cairo_tg_journal_pattern_snapshot (&entry->base.source.base, source);
378
379     if (unlikely (status))
380         return status;
381
382     entry->scaled_font = cairo_scaled_font_reference (scaled_font);
383
384     if (unlikely (entry->scaled_font == NULL))
385     {
386         _cairo_pattern_fini (&entry->base.source.base);
387         return CAIRO_INT_STATUS_NO_MEMORY;
388     }
389
390     if (num_glyphs)
391     {
392         entry->glyphs = malloc (sizeof (cairo_glyph_t) * num_glyphs);
393
394         if (unlikely (entry->glyphs == NULL))
395         {
396             cairo_scaled_font_destroy (entry->scaled_font);
397             _cairo_pattern_fini (&entry->base.source.base);
398             return CAIRO_INT_STATUS_NO_MEMORY;
399         }
400
401         memcpy (entry->glyphs, glyphs, sizeof (cairo_glyph_t) * num_glyphs);
402     }
403     else
404     {
405         entry->glyphs = NULL;
406     }
407
408     entry->num_glyphs = num_glyphs;
409     entry->base.op = op;
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);
414
415     cairo_list_add_tail (&entry->base.link, &journal->entry_list);
416     journal->num_entries++;
417
418     return CAIRO_INT_STATUS_SUCCESS;
419 }
420
421 void
422 _cairo_tg_journal_clear (cairo_tg_journal_t *journal)
423 {
424     cairo_tg_journal_entry_t *entry;
425     cairo_tg_journal_entry_t *next;
426
427     cairo_list_foreach_entry_safe (entry, next, cairo_tg_journal_entry_t,
428                                    &journal->entry_list, link)
429     {
430         _cairo_tg_journal_entry_fini (entry);
431     }
432
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;
437 }
438
439 cairo_int_status_t
440 _cairo_tg_journal_replay (const cairo_tg_journal_t              *journal,
441                           void                                  *closure,
442                           const cairo_rectangle_int_t           *extents,
443                           const cairo_tg_journal_replay_funcs_t *funcs)
444 {
445     const cairo_tg_journal_entry_t  *entry;
446     const cairo_tg_journal_entry_t  *next;
447     cairo_int_status_t              status;
448
449     cairo_list_foreach_entry_safe (entry, next, cairo_tg_journal_entry_t,
450                                    &journal->entry_list, link)
451     {
452         if (extents && ! _cairo_rectangle_intersects (extents, &entry->extents))
453         {
454             continue;
455         }
456
457         switch (entry->type)
458         {
459         case CAIRO_TG_JOURNAL_ENTRY_PAINT:
460             {
461                 cairo_tg_journal_entry_paint_t *e =
462                     (cairo_tg_journal_entry_paint_t *) entry;
463
464                 status = funcs->paint (closure, e->base.op, &e->base.source.base,
465                                        e->base.clip);
466             }
467             break;
468         case CAIRO_TG_JOURNAL_ENTRY_MASK:
469             {
470                 cairo_tg_journal_entry_mask_t *e =
471                     (cairo_tg_journal_entry_mask_t *) entry;
472
473                 status = funcs->mask (closure, e->base.op, &e->base.source.base,
474                                       &e->mask.base, e->base.clip);
475             }
476             break;
477         case CAIRO_TG_JOURNAL_ENTRY_STROKE:
478             {
479                 cairo_tg_journal_entry_stroke_t *e =
480                     (cairo_tg_journal_entry_stroke_t *) entry;
481
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);
485             }
486             break;
487         case CAIRO_TG_JOURNAL_ENTRY_FILL:
488             {
489                 cairo_tg_journal_entry_fill_t *e =
490                     (cairo_tg_journal_entry_fill_t *) entry;
491
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);
495             }
496             break;
497         case CAIRO_TG_JOURNAL_ENTRY_GLYPHS:
498             {
499                 cairo_tg_journal_entry_glyphs_t *e =
500                     (cairo_tg_journal_entry_glyphs_t *) entry;
501
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);
505             }
506             break;
507         default:
508             ASSERT_NOT_REACHED;
509             break;
510         }
511
512         if (unlikely (status) && status != CAIRO_INT_STATUS_NOTHING_TO_DO)
513         {
514             assert (0);
515             return status;
516         }
517     }
518
519     return CAIRO_INT_STATUS_SUCCESS;
520 }