1 | #include <stdlib.h> |
2 | #include <string.h> |
3 | #include <pango/pango.h> |
4 | #include <pango/pangocairo.h> |
5 | |
6 | #define WIDTH 100 |
7 | #define HEIGHT 100 |
8 | const char *text = "Hamburgerfonts\nวิวิวิวิวิวิ\nبهداد" ; |
9 | |
10 | int num_iters = 50; |
11 | int num_threads = 5; |
12 | |
13 | GMutex mutex; |
14 | |
15 | static cairo_surface_t * |
16 | create_surface (void) |
17 | { |
18 | return cairo_image_surface_create (format: CAIRO_FORMAT_A8, WIDTH, HEIGHT); |
19 | } |
20 | |
21 | static PangoLayout * |
22 | create_layout (cairo_t *cr) |
23 | { |
24 | PangoLayout *layout = pango_cairo_create_layout (cr); |
25 | pango_layout_set_text (layout, text, length: -1); |
26 | pango_layout_set_width (layout, WIDTH * PANGO_SCALE); |
27 | return layout; |
28 | } |
29 | |
30 | static void |
31 | draw (cairo_t *cr, PangoLayout *layout, unsigned int i) |
32 | { |
33 | cairo_set_source_rgba (cr, red: 1, green: 1, blue: 1, alpha: 1); |
34 | cairo_paint (cr); |
35 | cairo_set_source_rgba (cr, red: 1, green: 1, blue: 1, alpha: 0); |
36 | cairo_set_operator (cr, op: CAIRO_OPERATOR_SOURCE); |
37 | |
38 | cairo_identity_matrix (cr); |
39 | cairo_scale (cr, sx: (100 + i) / 100., sy: (100 + i) / 100.); |
40 | pango_cairo_update_layout (cr, layout); |
41 | |
42 | pango_cairo_show_layout (cr, layout); |
43 | } |
44 | |
45 | static gpointer |
46 | thread_func (gpointer data) |
47 | { |
48 | cairo_surface_t *surface = data; |
49 | PangoLayout *layout; |
50 | int i; |
51 | |
52 | cairo_t *cr = cairo_create (target: surface); |
53 | |
54 | layout = create_layout (cr); |
55 | |
56 | g_mutex_lock (mutex: &mutex); |
57 | g_mutex_unlock (mutex: &mutex); |
58 | |
59 | for (i = 0; i < num_iters; i++) |
60 | draw (cr, layout, i); |
61 | |
62 | g_object_unref (object: layout); |
63 | |
64 | cairo_destroy (cr); |
65 | |
66 | return 0; |
67 | } |
68 | |
69 | static void |
70 | pangocairo_threads (void) |
71 | { |
72 | GPtrArray *threads = g_ptr_array_new (); |
73 | GPtrArray *surfaces = g_ptr_array_new (); |
74 | int i; |
75 | |
76 | g_mutex_lock (mutex: &mutex); |
77 | |
78 | for (i = 0; i < num_threads; i++) |
79 | { |
80 | char buf[10]; |
81 | cairo_surface_t *surface = create_surface (); |
82 | g_ptr_array_add (array: surfaces, data: surface); |
83 | g_snprintf (string: buf, n: sizeof (buf), format: "%d" , i); |
84 | g_ptr_array_add (array: threads, |
85 | data: g_thread_new (name: buf, |
86 | func: thread_func, |
87 | data: surface)); |
88 | } |
89 | |
90 | /* Let them loose! */ |
91 | g_mutex_unlock (mutex: &mutex); |
92 | |
93 | for (i = 0; i < num_threads; i++) |
94 | g_thread_join (g_ptr_array_index (threads, i)); |
95 | |
96 | g_ptr_array_unref (array: threads); |
97 | |
98 | /* Now, draw a reference image and check results. */ |
99 | { |
100 | cairo_surface_t *ref_surface = create_surface (); |
101 | cairo_t *cr = cairo_create (target: ref_surface); |
102 | PangoLayout *layout = create_layout (cr); |
103 | unsigned char *ref_data = cairo_image_surface_get_data (surface: ref_surface); |
104 | unsigned int len = WIDTH * HEIGHT; |
105 | |
106 | draw (cr, layout, i: num_iters - 1); |
107 | |
108 | g_object_unref (object: layout); |
109 | cairo_destroy (cr); |
110 | |
111 | /* cairo_surface_write_to_png (ref_surface, "test-pangocairo-threads-reference.png"); */ |
112 | |
113 | g_assert (WIDTH == cairo_format_stride_for_width (CAIRO_FORMAT_A8, WIDTH)); |
114 | |
115 | for (i = 0; i < num_threads; i++) |
116 | { |
117 | cairo_surface_t *surface = g_ptr_array_index (surfaces, i); |
118 | unsigned char *data = cairo_image_surface_get_data (surface); |
119 | if (memcmp (s1: ref_data, s2: data, n: len)) |
120 | { |
121 | g_test_message (format: "image for thread %d different from reference image" , i); |
122 | cairo_surface_write_to_png (surface: ref_surface, filename: "test-pangocairo-threads-reference.png" ); |
123 | cairo_surface_write_to_png (surface, filename: "test-pangocairo-threads-failed.png" ); |
124 | g_test_fail (); |
125 | break; |
126 | } |
127 | cairo_surface_destroy (surface); |
128 | } |
129 | |
130 | cairo_surface_destroy (surface: ref_surface); |
131 | } |
132 | |
133 | g_ptr_array_unref (array: surfaces); |
134 | |
135 | pango_cairo_font_map_set_default (NULL); |
136 | |
137 | } |
138 | |
139 | int |
140 | main (int argc, char **argv) |
141 | { |
142 | g_test_init (argc: &argc, argv: &argv, NULL); |
143 | |
144 | if (argc > 1) |
145 | num_threads = atoi (nptr: argv[1]); |
146 | if (argc > 2) |
147 | num_iters = atoi (nptr: argv[2]); |
148 | |
149 | g_test_add_func (testpath: "/pangocairo/threads" , test_func: pangocairo_threads); |
150 | |
151 | return g_test_run (); |
152 | } |
153 | |