Mercurial > MadButterfly
comparison src/redraw_man.c @ 17:41f0907b27ac
Unittest for rdman_redraw_changed().
geo_init() is seperated into geo_init() and geo_from_positions().
author | Thinker K.F. Li <thinker@branda.to> |
---|---|
date | Fri, 01 Aug 2008 23:32:22 +0800 |
parents | e17e12b112c4 |
children | 0f3baa488a62 |
comparison
equal
deleted
inserted
replaced
16:e17e12b112c4 | 17:41f0907b27ac |
---|---|
10 #define OK 0 | 10 #define OK 0 |
11 #define ERR -1 | 11 #define ERR -1 |
12 | 12 |
13 #define OFFSET(type, field) ((void *)&((type *)NULL)->field - (void *)NULL) | 13 #define OFFSET(type, field) ((void *)&((type *)NULL)->field - (void *)NULL) |
14 #define SWAP(a, b, t) do { t c; c = a; a = b; b = c; } while(0) | 14 #define SWAP(a, b, t) do { t c; c = a; a = b; b = c; } while(0) |
15 | |
16 #ifdef UNITTEST | |
17 typedef struct _sh_dummy sh_dummy_t; | |
18 | |
19 extern void sh_dummy_transform(shape_t *shape); | |
20 extern void sh_dummy_draw(shape_t *, cairo_t *); | |
21 #endif /* UNITTEST */ | |
15 | 22 |
16 /*! \brief Sort a list of element by a unsigned integer. | 23 /*! \brief Sort a list of element by a unsigned integer. |
17 * | 24 * |
18 * The result is in ascend order. The unsigned integers is | 25 * The result is in ascend order. The unsigned integers is |
19 * at offset specified by 'off' from start address of elemnts. | 26 * at offset specified by 'off' from start address of elemnts. |
81 | 88 |
82 rdman->dirty_areas[rdman->n_dirty_areas++] = area; | 89 rdman->dirty_areas[rdman->n_dirty_areas++] = area; |
83 return OK; | 90 return OK; |
84 } | 91 } |
85 | 92 |
86 int redraw_man_init(redraw_man_t *rdman, cairo_t *cr) { | |
87 extern void redraw_man_destroy(redraw_man_t *rdman); | |
88 | |
89 memset(rdman, 0, sizeof(redraw_man_t)); | |
90 | |
91 rdman->geo_pool = elmpool_new(sizeof(geo_t), 128); | |
92 if(rdman->geo_pool == NULL) | |
93 return ERR; | |
94 | |
95 rdman->coord_pool = elmpool_new(sizeof(coord_t), 16); | |
96 if(rdman->coord_pool == NULL) { | |
97 elmpool_free(rdman->geo_pool); | |
98 return ERR; | |
99 } | |
100 | |
101 rdman->root_coord = elmpool_elm_alloc(rdman->coord_pool); | |
102 if(rdman->root_coord == NULL) | |
103 redraw_man_destroy(rdman); | |
104 rdman->n_coords = 1; | |
105 coord_init(rdman->root_coord, NULL); | |
106 | |
107 rdman->cr = cr; | |
108 | |
109 return OK; | |
110 } | |
111 | |
112 void redraw_man_destroy(redraw_man_t *rdman) { | |
113 elmpool_free(rdman->coord_pool); | |
114 elmpool_free(rdman->geo_pool); | |
115 if(rdman->dirty_coords) | |
116 free(rdman->dirty_coords); | |
117 if(rdman->dirty_geos) | |
118 free(rdman->dirty_geos); | |
119 } | |
120 | |
121 | |
122 #define ASSERT(x) | |
123 /* | |
124 * Change transformation matrix | |
125 * - update aggregated transformation matrix | |
126 * - of coord_t object been changed. | |
127 * - of children coord_t objects. | |
128 * - redraw members of coord_t objects. | |
129 * - redraw shape objects they are overlaid with members. | |
130 * - find out overlaid shape objects. | |
131 * - geo_t of a coord_t object | |
132 * - can make finding more efficiency. | |
133 * - fill overlay geo_t objects of members. | |
134 * | |
135 * Change a shape object | |
136 * - redraw changed object. | |
137 * - redraw shape objects they are overlaid with changed object. | |
138 * - find out overlaid shape objects. | |
139 * | |
140 * That coord and geo of shape objects are setted by user code | |
141 * give user code a chance to collect coord and geo objects together | |
142 * and gain interest of higher cache hit rate. | |
143 */ | |
144 | |
145 /*! \brief Find out all affected shape objects. | |
146 * | |
147 * Find out all shape objects that are overalid with geo_t of | |
148 * a geometry changed object. | |
149 * | |
150 * Linear scan geo_t objects of all shape objects in all_shapes | |
151 * list of a redraw_man_t object. | |
152 */ | |
153 int rdman_find_overlaid_shapes(redraw_man_t *rdman, geo_t *geo, | |
154 geo_t ***overlays) { | |
155 int n_geos; | |
156 geo_t **geos; | |
157 geo_t *geo_cur; | |
158 int n_overlays; | |
159 geo_t **_overlays; | |
160 int i; | |
161 | |
162 n_geos = rdman->n_geos; | |
163 | |
164 geos = (geo_t **)malloc(sizeof(geo_t *) * n_geos); | |
165 if(geos == NULL) | |
166 return -1; | |
167 | |
168 _overlays = (geo_t **)malloc(sizeof(geo_t *) * n_geos); | |
169 if(geos == NULL) { | |
170 free(geos); | |
171 return -1; | |
172 } | |
173 | |
174 geo_cur = STAILQ_HEAD(rdman->all_geos); | |
175 for(i = 0; i < n_geos; i++) { | |
176 geos[i] = geo_cur; | |
177 geo_cur = STAILQ_NEXT(geo_t, next, geo_cur); | |
178 } | |
179 geo_mark_overlay(geo, n_geos, geos, &n_overlays, _overlays); | |
180 | |
181 free(geos); | |
182 *overlays = _overlays; | |
183 | |
184 return n_overlays; | |
185 } | |
186 | |
187 int rdman_add_shape(redraw_man_t *rdman, shape_t *shape, coord_t *coord) { | |
188 geo_t *geo; | |
189 #ifdef GEO_ORDER | |
190 geo_t *visit; | |
191 unsigned int next_order; | |
192 #endif | |
193 int r; | |
194 | |
195 geo = elmpool_elm_alloc(rdman->geo_pool); | |
196 if(geo == NULL) | |
197 return ERR; | |
198 sh_attach_geo(shape, geo); | |
199 STAILQ_INS_TAIL(rdman->all_geos, geo_t, next, geo); | |
200 rdman->n_geos++; | |
201 | |
202 #ifdef GEO_ORDER | |
203 /* TODO: remove order number. */ | |
204 geo->order = ++rdman->next_geo_order; | |
205 if(geo->order == 0) { | |
206 next_order = 0; | |
207 for(visit = STAILQ_HEAD(rdman->all_geos); | |
208 visit != NULL; | |
209 visit = STAILQ_NEXT(geo_t, next, visit)) | |
210 visit->order = ++next_order; | |
211 rdman->next_geo_order = next_order; | |
212 } | |
213 #endif | |
214 | |
215 /* New one should be dirty to recompute it when drawing. */ | |
216 geo->flags |= GEF_DIRTY; | |
217 r = add_dirty_geo(rdman, geo); | |
218 if(r != OK) | |
219 return ERR; | |
220 | |
221 sh_attach_coord(shape, coord); | |
222 | |
223 return OK; | |
224 } | |
225 | |
226 int rdman_remove_shape(redraw_man_t *rdman, shape_t *shape) { | |
227 STAILQ_REMOVE(rdman->all_geos, geo_t, next, shape->geo); | |
228 elmpool_elm_free(rdman->geo_pool, shape->geo); | |
229 sh_detach_geo(shape); | |
230 rdman->n_geos--; | |
231 sh_detach_coord(shape); | |
232 return OK; | |
233 } | |
234 | |
235 coord_t *rdman_coord_new(redraw_man_t *rdman, coord_t *parent) { | |
236 coord_t *coord, *root_coord; | |
237 coord_t *visit; | |
238 | |
239 coord = elmpool_elm_alloc(rdman->coord_pool); | |
240 if(coord == NULL) | |
241 return NULL; | |
242 | |
243 coord_init(coord, parent); | |
244 rdman->n_coords++; | |
245 | |
246 coord->order = ++rdman->next_coord_order; | |
247 if(coord->order == 0) { | |
248 rdman->next_coord_order = 0; | |
249 root_coord = visit = rdman->root_coord; | |
250 /* skip root coord. */ | |
251 visit = preorder_coord_subtree(root_coord, visit); | |
252 while(visit) { | |
253 visit->order = ++rdman->next_coord_order; | |
254 visit = preorder_coord_subtree(root_coord, visit); | |
255 } | |
256 } | |
257 | |
258 return coord; | |
259 } | |
260 | |
261 /*! \brief Free a coord of a redraw_man_t object. | |
262 * | |
263 * \param coord is a coord_t without children and members. | |
264 * \return 0 for successful, -1 for error. | |
265 */ | |
266 int rdman_coord_free(redraw_man_t *rdman, coord_t *coord) { | |
267 coord_t *parent; | |
268 | |
269 parent = coord->parent; | |
270 if(parent == NULL) | |
271 return ERR; | |
272 | |
273 if(STAILQ_HEAD(coord->members) != NULL) | |
274 return ERR; | |
275 | |
276 if(STAILQ_HEAD(coord->children) != NULL) | |
277 return ERR; | |
278 | |
279 STAILQ_REMOVE(parent->children, coord_t, sibling, coord); | |
280 elmpool_elm_free(rdman->coord_pool, coord); | |
281 rdman->n_coords--; | |
282 | |
283 return OK; | |
284 } | |
285 | |
286 /*! \brief Mark a coord is changed. | |
287 * | |
288 * A changed coord_t object is marked as dirty and put | |
289 * into dirty_coords list. | |
290 */ | |
291 int rdman_coord_changed(redraw_man_t *rdman, coord_t *coord) { | |
292 coord_t *child; | |
293 int max_dirty_coords; | |
294 int r; | |
295 | |
296 if(coord->flags & COF_DIRTY) | |
297 return OK; | |
298 | |
299 if(rdman->n_dirty_coords >= rdman->max_dirty_coords) { | |
300 /* Max of dirty_coords is not big enough. */ | |
301 max_dirty_coords = rdman->max_dirty_coords + 16; | |
302 | |
303 r = extend_memblk((void **)&rdman->dirty_coords, | |
304 sizeof(coord_t *) * rdman->n_dirty_coords, | |
305 sizeof(coord_t *) * max_dirty_coords); | |
306 rdman->max_dirty_coords = max_dirty_coords; | |
307 } | |
308 | |
309 /* Make the coord and child coords dirty. */ | |
310 for(child = coord; | |
311 child != NULL; | |
312 child = preorder_coord_subtree(coord, child)) { | |
313 rdman->dirty_coords[rdman->n_dirty_coords++] = coord; | |
314 coord->flags |= COF_DIRTY; | |
315 } | |
316 | |
317 return OK; | |
318 } | |
319 | |
320 /*! \brief Mark a shape is changed. | |
321 * | |
322 * The geo_t object of a changed shape is mark as dirty and | |
323 * put into dirty_geos list. | |
324 */ | |
325 int rdman_shape_changed(redraw_man_t *rdman, shape_t *shape) { | |
326 geo_t *geo; | |
327 int r; | |
328 | |
329 geo = shape->geo; | |
330 | |
331 if(geo->flags & GEF_DIRTY) | |
332 return OK; | |
333 | |
334 r = add_dirty_geo(rdman, geo); | |
335 if(r == ERR) | |
336 return ERR; | |
337 geo->flags |= GEF_DIRTY; | |
338 | |
339 return OK; | |
340 } | |
341 | |
342 static void clean_shape(shape_t *shape) { | 93 static void clean_shape(shape_t *shape) { |
343 switch(shape->sh_type) { | 94 switch(shape->sh_type) { |
344 case SHT_PATH: | 95 case SHT_PATH: |
345 sh_path_transform(shape); | 96 sh_path_transform(shape); |
346 break; | 97 break; |
98 #ifdef UNITTEST | |
99 default: | |
100 sh_dummy_transform(shape); | |
101 break; | |
102 #endif /* UNITTEST */ | |
347 } | 103 } |
348 shape->geo->flags &= ~GEF_DIRTY; | 104 shape->geo->flags &= ~GEF_DIRTY; |
349 } | 105 } |
350 | 106 |
351 static void area_to_positions(area_t *area, co_aix (*poses)[2]) { | 107 static void area_to_positions(area_t *area, co_aix (*poses)[2]) { |
358 static int clean_coord(coord_t *coord) { | 114 static int clean_coord(coord_t *coord) { |
359 shape_t *shape; | 115 shape_t *shape; |
360 geo_t *geo; | 116 geo_t *geo; |
361 co_aix (*poses)[2]; | 117 co_aix (*poses)[2]; |
362 int cnt, pos_cnt; | 118 int cnt, pos_cnt; |
363 int i; | |
364 | 119 |
365 compute_aggr_of_coord(coord); | 120 compute_aggr_of_coord(coord); |
366 | 121 |
367 /* Clean member shapes. */ | 122 /* Clean member shapes. */ |
368 cnt = 0; | 123 cnt = 0; |
384 for(shape = STAILQ_HEAD(coord->members); | 139 for(shape = STAILQ_HEAD(coord->members); |
385 shape != NULL; | 140 shape != NULL; |
386 shape = STAILQ_NEXT(shape_t, coord_mem_next, shape)) { | 141 shape = STAILQ_NEXT(shape_t, coord_mem_next, shape)) { |
387 geo = shape->geo; | 142 geo = shape->geo; |
388 | 143 |
389 area_to_positions(&geo->areas[0], poses + pos_cnt); | 144 area_to_positions(geo->cur_area, poses + pos_cnt); |
390 pos_cnt += 2; | 145 pos_cnt += 2; |
391 area_to_positions(&geo->areas[1], poses + pos_cnt); | 146 } |
392 pos_cnt += 2; | |
393 } | |
394 | |
395 #if 0 | |
396 for(i = 0; i < pos_cnt; i++) | |
397 coord_trans_pos(coord, &poses[i][0], &poses[i][1]); | |
398 #endif | |
399 | 147 |
400 SWAP(coord->cur_area, coord->last_area, area_t *); | 148 SWAP(coord->cur_area, coord->last_area, area_t *); |
401 area_init(coord->cur_area, pos_cnt, poses); | 149 area_init(coord->cur_area, pos_cnt, poses); |
402 free(poses); | 150 free(poses); |
403 | 151 |
431 rdman->n_dirty_coords = 0; | 179 rdman->n_dirty_coords = 0; |
432 } | 180 } |
433 return OK; | 181 return OK; |
434 } | 182 } |
435 | 183 |
184 int redraw_man_init(redraw_man_t *rdman, cairo_t *cr) { | |
185 extern void redraw_man_destroy(redraw_man_t *rdman); | |
186 | |
187 memset(rdman, 0, sizeof(redraw_man_t)); | |
188 | |
189 rdman->geo_pool = elmpool_new(sizeof(geo_t), 128); | |
190 if(rdman->geo_pool == NULL) | |
191 return ERR; | |
192 | |
193 rdman->coord_pool = elmpool_new(sizeof(coord_t), 16); | |
194 if(rdman->coord_pool == NULL) { | |
195 elmpool_free(rdman->geo_pool); | |
196 return ERR; | |
197 } | |
198 | |
199 rdman->root_coord = elmpool_elm_alloc(rdman->coord_pool); | |
200 if(rdman->root_coord == NULL) | |
201 redraw_man_destroy(rdman); | |
202 rdman->n_coords = 1; | |
203 coord_init(rdman->root_coord, NULL); | |
204 | |
205 rdman->cr = cr; | |
206 | |
207 return OK; | |
208 } | |
209 | |
210 void redraw_man_destroy(redraw_man_t *rdman) { | |
211 elmpool_free(rdman->coord_pool); | |
212 elmpool_free(rdman->geo_pool); | |
213 if(rdman->dirty_coords) | |
214 free(rdman->dirty_coords); | |
215 if(rdman->dirty_geos) | |
216 free(rdman->dirty_geos); | |
217 } | |
218 | |
219 | |
220 #define ASSERT(x) | |
221 /* | |
222 * Change transformation matrix | |
223 * - update aggregated transformation matrix | |
224 * - of coord_t object been changed. | |
225 * - of children coord_t objects. | |
226 * - redraw members of coord_t objects. | |
227 * - redraw shape objects they are overlaid with members. | |
228 * - find out overlaid shape objects. | |
229 * - geo_t of a coord_t object | |
230 * - can make finding more efficiency. | |
231 * - fill overlay geo_t objects of members. | |
232 * | |
233 * Change a shape object | |
234 * - redraw changed object. | |
235 * - redraw shape objects they are overlaid with changed object. | |
236 * - find out overlaid shape objects. | |
237 * | |
238 * That coord and geo of shape objects are setted by user code | |
239 * give user code a chance to collect coord and geo objects together | |
240 * and gain interest of higher cache hit rate. | |
241 */ | |
242 | |
243 /*! \brief Find out all affected shape objects. | |
244 * | |
245 * Find out all shape objects that are overalid with geo_t of | |
246 * a geometry changed object. | |
247 * | |
248 * Linear scan geo_t objects of all shape objects in all_shapes | |
249 * list of a redraw_man_t object. | |
250 */ | |
251 int rdman_find_overlaid_shapes(redraw_man_t *rdman, geo_t *geo, | |
252 geo_t ***overlays) { | |
253 int n_geos; | |
254 geo_t **geos; | |
255 geo_t *geo_cur; | |
256 int n_overlays; | |
257 geo_t **_overlays; | |
258 int i; | |
259 | |
260 n_geos = rdman->n_geos; | |
261 | |
262 geos = (geo_t **)malloc(sizeof(geo_t *) * n_geos); | |
263 if(geos == NULL) | |
264 return -1; | |
265 | |
266 _overlays = (geo_t **)malloc(sizeof(geo_t *) * n_geos); | |
267 if(geos == NULL) { | |
268 free(geos); | |
269 return -1; | |
270 } | |
271 | |
272 geo_cur = STAILQ_HEAD(rdman->all_geos); | |
273 for(i = 0; i < n_geos; i++) { | |
274 geos[i] = geo_cur; | |
275 geo_cur = STAILQ_NEXT(geo_t, next, geo_cur); | |
276 } | |
277 geo_mark_overlay(geo, n_geos, geos, &n_overlays, _overlays); | |
278 | |
279 free(geos); | |
280 *overlays = _overlays; | |
281 | |
282 return n_overlays; | |
283 } | |
284 | |
285 int rdman_add_shape(redraw_man_t *rdman, shape_t *shape, coord_t *coord) { | |
286 geo_t *geo; | |
287 #ifdef GEO_ORDER | |
288 geo_t *visit; | |
289 unsigned int next_order; | |
290 #endif | |
291 int r; | |
292 | |
293 geo = elmpool_elm_alloc(rdman->geo_pool); | |
294 if(geo == NULL) | |
295 return ERR; | |
296 | |
297 geo_init(geo); | |
298 | |
299 sh_attach_geo(shape, geo); | |
300 STAILQ_INS_TAIL(rdman->all_geos, geo_t, next, geo); | |
301 rdman->n_geos++; | |
302 | |
303 #ifdef GEO_ORDER | |
304 /* TODO: remove order number. */ | |
305 geo->order = ++rdman->next_geo_order; | |
306 if(geo->order == 0) { | |
307 next_order = 0; | |
308 for(visit = STAILQ_HEAD(rdman->all_geos); | |
309 visit != NULL; | |
310 visit = STAILQ_NEXT(geo_t, next, visit)) | |
311 visit->order = ++next_order; | |
312 rdman->next_geo_order = next_order; | |
313 } | |
314 #endif | |
315 | |
316 /* New one should be dirty to recompute it when drawing. */ | |
317 geo->flags |= GEF_DIRTY; | |
318 r = add_dirty_geo(rdman, geo); | |
319 if(r != OK) | |
320 return ERR; | |
321 | |
322 sh_attach_coord(shape, coord); | |
323 | |
324 return OK; | |
325 } | |
326 | |
327 /*! \brief Remove a shape object from redraw manager. | |
328 * | |
329 * TODO: redraw shape objects that overlaid with removed one. | |
330 */ | |
331 int rdman_remove_shape(redraw_man_t *rdman, shape_t *shape) { | |
332 STAILQ_REMOVE(rdman->all_geos, geo_t, next, shape->geo); | |
333 elmpool_elm_free(rdman->geo_pool, shape->geo); | |
334 sh_detach_geo(shape); | |
335 rdman->n_geos--; | |
336 sh_detach_coord(shape); | |
337 return OK; | |
338 } | |
339 | |
340 coord_t *rdman_coord_new(redraw_man_t *rdman, coord_t *parent) { | |
341 coord_t *coord, *root_coord; | |
342 coord_t *visit; | |
343 | |
344 coord = elmpool_elm_alloc(rdman->coord_pool); | |
345 if(coord == NULL) | |
346 return NULL; | |
347 | |
348 coord_init(coord, parent); | |
349 rdman->n_coords++; | |
350 | |
351 coord->order = ++rdman->next_coord_order; | |
352 if(coord->order == 0) { | |
353 rdman->next_coord_order = 0; | |
354 root_coord = visit = rdman->root_coord; | |
355 /* skip root coord. */ | |
356 visit = preorder_coord_subtree(root_coord, visit); | |
357 while(visit) { | |
358 visit->order = ++rdman->next_coord_order; | |
359 visit = preorder_coord_subtree(root_coord, visit); | |
360 } | |
361 } | |
362 | |
363 return coord; | |
364 } | |
365 | |
366 /*! \brief Free a coord of a redraw_man_t object. | |
367 * | |
368 * \param coord is a coord_t without children and members. | |
369 * \return 0 for successful, -1 for error. | |
370 */ | |
371 int rdman_coord_free(redraw_man_t *rdman, coord_t *coord) { | |
372 coord_t *parent; | |
373 | |
374 parent = coord->parent; | |
375 if(parent == NULL) | |
376 return ERR; | |
377 | |
378 if(STAILQ_HEAD(coord->members) != NULL) | |
379 return ERR; | |
380 | |
381 if(STAILQ_HEAD(coord->children) != NULL) | |
382 return ERR; | |
383 | |
384 STAILQ_REMOVE(parent->children, coord_t, sibling, coord); | |
385 elmpool_elm_free(rdman->coord_pool, coord); | |
386 rdman->n_coords--; | |
387 | |
388 return OK; | |
389 } | |
390 | |
391 /*! \brief Mark a coord is changed. | |
392 * | |
393 * A changed coord_t object is marked as dirty and put | |
394 * into dirty_coords list. | |
395 */ | |
396 int rdman_coord_changed(redraw_man_t *rdman, coord_t *coord) { | |
397 coord_t *child; | |
398 int max_dirty_coords; | |
399 int r; | |
400 | |
401 if(coord->flags & COF_DIRTY) | |
402 return OK; | |
403 | |
404 if(rdman->n_dirty_coords >= rdman->max_dirty_coords) { | |
405 /* Max of dirty_coords is not big enough. */ | |
406 max_dirty_coords = rdman->max_dirty_coords + 16; | |
407 | |
408 r = extend_memblk((void **)&rdman->dirty_coords, | |
409 sizeof(coord_t *) * rdman->n_dirty_coords, | |
410 sizeof(coord_t *) * max_dirty_coords); | |
411 rdman->max_dirty_coords = max_dirty_coords; | |
412 } | |
413 | |
414 /* Make the coord and child coords dirty. */ | |
415 for(child = coord; | |
416 child != NULL; | |
417 child = preorder_coord_subtree(coord, child)) { | |
418 rdman->dirty_coords[rdman->n_dirty_coords++] = coord; | |
419 coord->flags |= COF_DIRTY; | |
420 } | |
421 | |
422 return OK; | |
423 } | |
424 | |
425 /*! \brief Mark a shape is changed. | |
426 * | |
427 * The geo_t object of a changed shape is mark as dirty and | |
428 * put into dirty_geos list. | |
429 */ | |
430 int rdman_shape_changed(redraw_man_t *rdman, shape_t *shape) { | |
431 geo_t *geo; | |
432 int r; | |
433 | |
434 geo = shape->geo; | |
435 | |
436 if(geo->flags & GEF_DIRTY) | |
437 return OK; | |
438 | |
439 r = add_dirty_geo(rdman, geo); | |
440 if(r == ERR) | |
441 return ERR; | |
442 geo->flags |= GEF_DIRTY; | |
443 | |
444 return OK; | |
445 } | |
446 | |
447 /* Drawing and Redrawing | |
448 * ============================================================ | |
449 */ | |
450 | |
436 static void draw_shape(redraw_man_t *rdman, shape_t *shape) { | 451 static void draw_shape(redraw_man_t *rdman, shape_t *shape) { |
437 switch(shape->sh_type) { | 452 switch(shape->sh_type) { |
438 case SHT_PATH: | 453 case SHT_PATH: |
439 sh_path_draw(shape, rdman->cr); | 454 sh_path_draw(shape, rdman->cr); |
440 break; | 455 break; |
441 } | 456 #ifdef UNITTEST |
442 } | 457 default: |
443 | 458 sh_dummy_draw(shape, rdman->cr); |
459 break; | |
460 #endif /* UNITTEST */ | |
461 } | |
462 } | |
463 | |
464 #ifndef UNITTEST | |
444 static void clean_clip(cairo_t *cr) { | 465 static void clean_clip(cairo_t *cr) { |
445 cairo_pattern_t *pt; | 466 cairo_pattern_t *pt; |
446 | 467 |
447 pt = cairo_get_source(cr); | 468 pt = cairo_get_source(cr); |
448 cairo_pattern_reference(pt); | 469 cairo_pattern_reference(pt); |
459 area_t *area; | 480 area_t *area; |
460 cairo_t *cr; | 481 cairo_t *cr; |
461 | 482 |
462 cr = rdman->cr; | 483 cr = rdman->cr; |
463 | 484 |
464 cairo_reset_clip(cr); | |
465 for(i = 0; i < n_dirty_areas; i++) { | 485 for(i = 0; i < n_dirty_areas; i++) { |
466 area = dirty_areas[i]; | 486 area = dirty_areas[i]; |
467 cairo_rectangle(cr, area->x, area->y, area->w, area->h); | 487 cairo_rectangle(cr, area->x, area->y, area->w, area->h); |
468 } | 488 } |
469 clean_clip(cr); | 489 clean_clip(cr); |
470 cairo_clip(cr); | 490 cairo_clip(cr); |
471 } | 491 } |
492 | |
493 static void reset_clip(redraw_man_t *rdman) { | |
494 cairo_reset_clip(rdman->cr); | |
495 } | |
496 #else /* UNITTEST */ | |
497 static void make_clip(redraw_man_t *rdman, int n_dirty_areas, | |
498 area_t **dirty_areas) { | |
499 } | |
500 | |
501 static void reset_clip(redraw_man_t *rdman) { | |
502 } | |
503 #endif /* UNITTEST */ | |
472 | 504 |
473 static void draw_shapes_in_areas(redraw_man_t *rdman, | 505 static void draw_shapes_in_areas(redraw_man_t *rdman, |
474 int n_areas, | 506 int n_areas, |
475 area_t **areas) { | 507 area_t **areas) { |
476 geo_t *visit_geo; | 508 geo_t *visit_geo; |
553 dirty_areas = rdman->dirty_areas; | 585 dirty_areas = rdman->dirty_areas; |
554 if(n_dirty_areas > 0) { | 586 if(n_dirty_areas > 0) { |
555 make_clip(rdman, n_dirty_areas, dirty_areas); | 587 make_clip(rdman, n_dirty_areas, dirty_areas); |
556 draw_shapes_in_areas(rdman, n_dirty_areas, dirty_areas); | 588 draw_shapes_in_areas(rdman, n_dirty_areas, dirty_areas); |
557 rdman->n_dirty_areas = 0; | 589 rdman->n_dirty_areas = 0; |
590 reset_clip(rdman); | |
558 } | 591 } |
559 rdman->n_dirty_areas = 0; | 592 rdman->n_dirty_areas = 0; |
560 | |
561 cairo_reset_clip(rdman->cr); | |
562 | 593 |
563 return OK; | 594 return OK; |
564 } | 595 } |
565 | 596 |
566 int rdman_redraw_all(redraw_man_t *rdman) { | 597 int rdman_redraw_all(redraw_man_t *rdman) { |
567 geo_t *geo; | 598 geo_t *geo; |
568 | 599 |
569 clean_rdman_coords(rdman); | 600 clean_rdman_coords(rdman); |
570 rdman->n_dirty_areas = 0; | 601 rdman->n_dirty_areas = 0; |
571 | 602 |
572 cairo_reset_clip(rdman->cr); | |
573 for(geo = STAILQ_HEAD(rdman->all_geos); | 603 for(geo = STAILQ_HEAD(rdman->all_geos); |
574 geo != NULL; | 604 geo != NULL; |
575 geo = STAILQ_NEXT(geo_t, next, geo)) { | 605 geo = STAILQ_NEXT(geo_t, next, geo)) { |
576 if(geo->flags & GEF_DIRTY) | 606 if(geo->flags & GEF_DIRTY) |
577 clean_shape(geo->shape); | 607 clean_shape(geo->shape); |
578 draw_shape(rdman, geo->shape); | 608 draw_shape(rdman, geo->shape); |
579 } | 609 } |
580 cairo_reset_clip(rdman->cr); | |
581 | 610 |
582 return OK; | 611 return OK; |
583 } | 612 } |
584 | 613 |
585 /* | 614 /* |
651 | 680 |
652 struct _sh_dummy { | 681 struct _sh_dummy { |
653 shape_t shape; | 682 shape_t shape; |
654 co_aix x, y; | 683 co_aix x, y; |
655 co_aix w, h; | 684 co_aix w, h; |
685 int draw_cnt; | |
656 }; | 686 }; |
657 typedef struct _sh_dummy sh_dummy_t; | |
658 | 687 |
659 shape_t *sh_dummy_new(co_aix x, co_aix y, co_aix w, co_aix h) { | 688 shape_t *sh_dummy_new(co_aix x, co_aix y, co_aix w, co_aix h) { |
660 sh_dummy_t *dummy; | 689 sh_dummy_t *dummy; |
661 | 690 |
662 dummy = (sh_dummy_t *)malloc(sizeof(sh_dummy_t)); | 691 dummy = (sh_dummy_t *)malloc(sizeof(sh_dummy_t)); |
663 if(dummy == NULL) | 692 if(dummy == NULL) |
664 return NULL; | 693 return NULL; |
694 | |
695 memset(dummy, 0, sizeof(sh_dummy_t)); | |
665 | 696 |
666 dummy->x = x; | 697 dummy->x = x; |
667 dummy->y = y; | 698 dummy->y = y; |
668 dummy->w = w; | 699 dummy->w = w; |
669 dummy->h = h; | 700 dummy->h = h; |
701 dummy->draw_cnt = 0; | |
670 | 702 |
671 return (shape_t *)dummy; | 703 return (shape_t *)dummy; |
672 } | 704 } |
673 | 705 |
674 void sh_dummy_free(shape_t *sh) { | 706 void sh_dummy_free(shape_t *sh) { |
691 poses[0][0] = x1; | 723 poses[0][0] = x1; |
692 poses[0][1] = y1; | 724 poses[0][1] = y1; |
693 poses[1][0] = x2; | 725 poses[1][0] = x2; |
694 poses[1][1] = y2; | 726 poses[1][1] = y2; |
695 | 727 |
696 geo_init(shape->geo, 2, poses); | 728 if(shape->geo) |
697 } | 729 geo_from_positions(shape->geo, 2, poses); |
730 } | |
731 } | |
732 | |
733 void sh_dummy_draw(shape_t *shape, cairo_t *cr) { | |
734 sh_dummy_t *dummy; | |
735 | |
736 dummy = (sh_dummy_t *)shape; | |
737 dummy->draw_cnt++; | |
698 } | 738 } |
699 | 739 |
700 void test_rdman_find_overlaid_shapes(void) { | 740 void test_rdman_find_overlaid_shapes(void) { |
701 redraw_man_t rdman; | 741 redraw_man_t rdman; |
702 geo_t geo; | 742 geo_t geo; |
730 | 770 |
731 pos[0][0] = 100; | 771 pos[0][0] = 100; |
732 pos[0][1] = 120; | 772 pos[0][1] = 120; |
733 pos[1][0] = 100 + 140; | 773 pos[1][0] = 100 + 140; |
734 pos[1][1] = 120 + 40; | 774 pos[1][1] = 120 + 40; |
735 geo_init(&geo, 2, pos); | 775 geo_init(&geo); |
776 geo_from_positions(&geo, 2, pos); | |
736 | 777 |
737 n = rdman_find_overlaid_shapes(&rdman, &geo, &overlays); | 778 n = rdman_find_overlaid_shapes(&rdman, &geo, &overlays); |
738 CU_ASSERT(n == 2); | 779 CU_ASSERT(n == 2); |
739 CU_ASSERT(overlays != NULL); | 780 CU_ASSERT(overlays != NULL); |
740 CU_ASSERT(overlays[0] == shapes[2]->geo); | 781 CU_ASSERT(overlays[0] == shapes[2]->geo); |
745 sh_dummy_free(shapes[i]); | 786 sh_dummy_free(shapes[i]); |
746 | 787 |
747 redraw_man_destroy(&rdman); | 788 redraw_man_destroy(&rdman); |
748 } | 789 } |
749 | 790 |
791 void test_rdman_redraw_changed(void) { | |
792 coord_t *coords[3]; | |
793 shape_t *shapes[3]; | |
794 sh_dummy_t **dummys; | |
795 redraw_man_t *rdman; | |
796 redraw_man_t _rdman; | |
797 int i; | |
798 | |
799 dummys = (sh_dummy_t **)shapes; | |
800 | |
801 rdman = &_rdman; | |
802 redraw_man_init(rdman, NULL); | |
803 for(i = 0; i < 3; i++) { | |
804 shapes[i] = sh_dummy_new(0, 0, 50, 50); | |
805 coords[i] = rdman_coord_new(rdman, rdman->root_coord); | |
806 coords[i]->matrix[2] = 10 + i * 100; | |
807 coords[i]->matrix[5] = 10 + i * 100; | |
808 rdman_coord_changed(rdman, coords[i]); | |
809 rdman_add_shape(rdman, shapes[i], coords[i]); | |
810 } | |
811 rdman_redraw_all(rdman); | |
812 CU_ASSERT(dummys[0]->draw_cnt == 1); | |
813 CU_ASSERT(dummys[1]->draw_cnt == 1); | |
814 CU_ASSERT(dummys[2]->draw_cnt == 1); | |
815 | |
816 coords[2]->matrix[2] = 100; | |
817 coords[2]->matrix[5] = 100; | |
818 rdman_coord_changed(rdman, coords[2]); | |
819 rdman_redraw_changed(rdman); | |
820 | |
821 CU_ASSERT(dummys[0]->draw_cnt == 1); | |
822 CU_ASSERT(dummys[1]->draw_cnt == 2); | |
823 CU_ASSERT(dummys[2]->draw_cnt == 2); | |
824 } | |
825 | |
750 CU_pSuite get_redraw_man_suite(void) { | 826 CU_pSuite get_redraw_man_suite(void) { |
751 CU_pSuite suite; | 827 CU_pSuite suite; |
752 | 828 |
753 suite = CU_add_suite("Suite_redraw_man", NULL, NULL); | 829 suite = CU_add_suite("Suite_redraw_man", NULL, NULL); |
754 CU_ADD_TEST(suite, test_rdman_find_overlaid_shapes); | 830 CU_ADD_TEST(suite, test_rdman_find_overlaid_shapes); |
831 CU_ADD_TEST(suite, test_rdman_redraw_changed); | |
755 | 832 |
756 return suite; | 833 return suite; |
757 } | 834 } |
758 | 835 |
759 #endif /* UNITTEST */ | 836 #endif /* UNITTEST */ |