comparison src/redraw_man.c @ 28:604bc90d509d

Refactory
author Thinker K.F. Li <thinker@branda.to>
date Mon, 04 Aug 2008 20:08:37 +0800
parents 19c603dd6ff9
children f56c96b035a8
comparison
equal deleted inserted replaced
27:19c603dd6ff9 28:604bc90d509d
90 } 90 }
91 91
92 rdman->dirty_areas[rdman->n_dirty_areas++] = area; 92 rdman->dirty_areas[rdman->n_dirty_areas++] = area;
93 return OK; 93 return OK;
94 } 94 }
95
96 static void area_to_positions(area_t *area, co_aix (*poses)[2]) {
97 poses[0][0] = area->x;
98 poses[0][1] = area->y;
99 poses[1][0] = area->x + area->w;
100 poses[1][1] = area->y + area->h;;
101 }
102
103 int redraw_man_init(redraw_man_t *rdman, cairo_t *cr, cairo_t *backend) {
104 extern void redraw_man_destroy(redraw_man_t *rdman);
105
106 memset(rdman, 0, sizeof(redraw_man_t));
107
108 rdman->geo_pool = elmpool_new(sizeof(geo_t), 128);
109 if(rdman->geo_pool == NULL)
110 return ERR;
111
112 rdman->coord_pool = elmpool_new(sizeof(coord_t), 16);
113 if(rdman->coord_pool == NULL) {
114 elmpool_free(rdman->geo_pool);
115 return ERR;
116 }
117
118 rdman->shnode_pool = elmpool_new(sizeof(shnode_t), 16);
119 if(rdman->shnode_pool == NULL) {
120 elmpool_free(rdman->geo_pool);
121 elmpool_free(rdman->coord_pool);
122 return ERR;
123 }
124
125 rdman->root_coord = elmpool_elm_alloc(rdman->coord_pool);
126 if(rdman->root_coord == NULL)
127 redraw_man_destroy(rdman);
128 rdman->n_coords = 1;
129 coord_init(rdman->root_coord, NULL);
130
131 rdman->cr = cr;
132 rdman->backend = backend;
133
134 return OK;
135 }
136
137 void redraw_man_destroy(redraw_man_t *rdman) {
138 elmpool_free(rdman->coord_pool);
139 elmpool_free(rdman->geo_pool);
140 elmpool_free(rdman->shnode_pool);
141 if(rdman->dirty_coords)
142 free(rdman->dirty_coords);
143 if(rdman->dirty_geos)
144 free(rdman->dirty_geos);
145 }
146
147
148 #define ASSERT(x)
149 /*
150 * Change transformation matrix
151 * - update aggregated transformation matrix
152 * - of coord_t object been changed.
153 * - of children coord_t objects.
154 * - redraw members of coord_t objects.
155 * - redraw shape objects they are overlaid with members.
156 * - find out overlaid shape objects.
157 * - geo_t of a coord_t object
158 * - can make finding more efficiency.
159 * - fill overlay geo_t objects of members.
160 *
161 * Change a shape object
162 * - redraw changed object.
163 * - redraw shape objects they are overlaid with changed object.
164 * - find out overlaid shape objects.
165 *
166 * That coord and geo of shape objects are setted by user code
167 * give user code a chance to collect coord and geo objects together
168 * and gain interest of higher cache hit rate.
169 */
170
171 /*! \brief Find out all affected shape objects.
172 *
173 * Find out all shape objects that are overalid with geo_t of
174 * a geometry changed object.
175 *
176 * Linear scan geo_t objects of all shape objects in all_shapes
177 * list of a redraw_man_t object.
178 */
179 int rdman_find_overlaid_shapes(redraw_man_t *rdman, geo_t *geo,
180 geo_t ***overlays) {
181 int n_geos;
182 geo_t **geos;
183 geo_t *geo_cur;
184 int n_overlays;
185 geo_t **_overlays;
186 int i;
187
188 n_geos = rdman->n_geos;
189
190 geos = (geo_t **)malloc(sizeof(geo_t *) * n_geos);
191 if(geos == NULL)
192 return -1;
193
194 _overlays = (geo_t **)malloc(sizeof(geo_t *) * n_geos);
195 if(geos == NULL) {
196 free(geos);
197 return -1;
198 }
199
200 geo_cur = STAILQ_HEAD(rdman->all_geos);
201 for(i = 0; i < n_geos; i++) {
202 geos[i] = geo_cur;
203 geo_cur = STAILQ_NEXT(geo_t, next, geo_cur);
204 }
205 geo_mark_overlay(geo, n_geos, geos, &n_overlays, _overlays);
206
207 free(geos);
208 *overlays = _overlays;
209
210 return n_overlays;
211 }
212
213 int rdman_add_shape(redraw_man_t *rdman, shape_t *shape, coord_t *coord) {
214 geo_t *geo;
215 #ifdef GEO_ORDER
216 geo_t *visit;
217 unsigned int next_order;
218 #endif
219 int r;
220
221 geo = elmpool_elm_alloc(rdman->geo_pool);
222 if(geo == NULL)
223 return ERR;
224
225 geo_init(geo);
226
227 sh_attach_geo(shape, geo);
228 STAILQ_INS_TAIL(rdman->all_geos, geo_t, next, geo);
229 rdman->n_geos++;
230
231 #ifdef GEO_ORDER
232 /* TODO: remove order number. */
233 geo->order = ++rdman->next_geo_order;
234 if(geo->order == 0) {
235 next_order = 0;
236 for(visit = STAILQ_HEAD(rdman->all_geos);
237 visit != NULL;
238 visit = STAILQ_NEXT(geo_t, next, visit))
239 visit->order = ++next_order;
240 rdman->next_geo_order = next_order;
241 }
242 #endif
243
244 /* New one should be dirty to recompute it when drawing. */
245 geo->flags |= GEF_DIRTY;
246 r = add_dirty_geo(rdman, geo);
247 if(r != OK)
248 return ERR;
249
250 sh_attach_coord(shape, coord);
251
252 return OK;
253 }
254
255 /*! \brief Remove a shape object from redraw manager.
256 *
257 * TODO: redraw shape objects that overlaid with removed one.
258 */
259 int rdman_remove_shape(redraw_man_t *rdman, shape_t *shape) {
260 STAILQ_REMOVE(rdman->all_geos, geo_t, next, shape->geo);
261 elmpool_elm_free(rdman->geo_pool, shape->geo);
262 sh_detach_geo(shape);
263 rdman->n_geos--;
264 sh_detach_coord(shape);
265 return OK;
266 }
267
268 coord_t *rdman_coord_new(redraw_man_t *rdman, coord_t *parent) {
269 coord_t *coord, *root_coord;
270 coord_t *visit;
271
272 coord = elmpool_elm_alloc(rdman->coord_pool);
273 if(coord == NULL)
274 return NULL;
275
276 coord_init(coord, parent);
277 rdman->n_coords++;
278
279 coord->order = ++rdman->next_coord_order;
280 if(coord->order == 0) {
281 rdman->next_coord_order = 0;
282 root_coord = visit = rdman->root_coord;
283 /* skip root coord. */
284 visit = preorder_coord_subtree(root_coord, visit);
285 while(visit) {
286 visit->order = ++rdman->next_coord_order;
287 visit = preorder_coord_subtree(root_coord, visit);
288 }
289 }
290
291 return coord;
292 }
293
294 /*! \brief Free a coord of a redraw_man_t object.
295 *
296 * \param coord is a coord_t without children and members.
297 * \return 0 for successful, -1 for error.
298 */
299 int rdman_coord_free(redraw_man_t *rdman, coord_t *coord) {
300 coord_t *parent;
301
302 parent = coord->parent;
303 if(parent == NULL)
304 return ERR;
305
306 if(STAILQ_HEAD(coord->members) != NULL)
307 return ERR;
308
309 if(STAILQ_HEAD(coord->children) != NULL)
310 return ERR;
311
312 STAILQ_REMOVE(parent->children, coord_t, sibling, coord);
313 elmpool_elm_free(rdman->coord_pool, coord);
314 rdman->n_coords--;
315
316 return OK;
317 }
318
319 /*! \brief Mark a coord is changed.
320 *
321 * A changed coord_t object is marked as dirty and put
322 * into dirty_coords list.
323 */
324 int rdman_coord_changed(redraw_man_t *rdman, coord_t *coord) {
325 coord_t *child;
326 int max_dirty_coords;
327 int r;
328
329 if(coord->flags & COF_DIRTY)
330 return OK;
331
332 if(rdman->n_dirty_coords >= rdman->max_dirty_coords) {
333 /* Max of dirty_coords is not big enough. */
334 max_dirty_coords = rdman->max_dirty_coords + 16;
335
336 r = extend_memblk((void **)&rdman->dirty_coords,
337 sizeof(coord_t *) * rdman->n_dirty_coords,
338 sizeof(coord_t *) * max_dirty_coords);
339 rdman->max_dirty_coords = max_dirty_coords;
340 }
341
342 /* Make the coord and child coords dirty. */
343 for(child = coord;
344 child != NULL;
345 child = preorder_coord_subtree(coord, child)) {
346 rdman->dirty_coords[rdman->n_dirty_coords++] = coord;
347 coord->flags |= COF_DIRTY;
348 }
349
350 return OK;
351 }
352
353 static int _rdman_shape_changed(redraw_man_t *rdman, shape_t *shape) {
354 geo_t *geo;
355 int r;
356
357 geo = shape->geo;
358
359 if(geo->flags & GEF_DIRTY)
360 return OK;
361
362 r = add_dirty_geo(rdman, geo);
363 if(r == ERR)
364 return ERR;
365 geo->flags |= GEF_DIRTY;
366
367 return OK;
368 }
369
370 /*! \brief Mark a shape is changed.
371 *
372 * The geo_t object of a changed shape is mark as dirty and
373 * put into dirty_geos list.
374 */
375 int rdman_shape_changed(redraw_man_t *rdman, shape_t *shape) {
376 return _rdman_shape_changed(rdman, shape);
377 }
378
379 /* Clean dirties */
95 380
96 static void clean_shape(shape_t *shape) { 381 static void clean_shape(shape_t *shape) {
97 switch(shape->sh_type) { 382 switch(shape->sh_type) {
98 case SHT_PATH: 383 case SHT_PATH:
99 sh_path_transform(shape); 384 sh_path_transform(shape);
106 sh_dummy_transform(shape); 391 sh_dummy_transform(shape);
107 break; 392 break;
108 #endif /* UNITTEST */ 393 #endif /* UNITTEST */
109 } 394 }
110 shape->geo->flags &= ~GEF_DIRTY; 395 shape->geo->flags &= ~GEF_DIRTY;
111 }
112
113 static void area_to_positions(area_t *area, co_aix (*poses)[2]) {
114 poses[0][0] = area->x;
115 poses[0][1] = area->y;
116 poses[1][0] = area->x + area->w;
117 poses[1][1] = area->y + area->h;;
118 } 396 }
119 397
120 static int clean_coord(coord_t *coord) { 398 static int clean_coord(coord_t *coord) {
121 shape_t *shape; 399 shape_t *shape;
122 geo_t *geo; 400 geo_t *geo;
185 rdman->n_dirty_coords = 0; 463 rdman->n_dirty_coords = 0;
186 } 464 }
187 return OK; 465 return OK;
188 } 466 }
189 467
190 int redraw_man_init(redraw_man_t *rdman, cairo_t *cr, cairo_t *backend) { 468 static int clean_rdman_geos(redraw_man_t *rdman) {
191 extern void redraw_man_destroy(redraw_man_t *rdman);
192
193 memset(rdman, 0, sizeof(redraw_man_t));
194
195 rdman->geo_pool = elmpool_new(sizeof(geo_t), 128);
196 if(rdman->geo_pool == NULL)
197 return ERR;
198
199 rdman->coord_pool = elmpool_new(sizeof(coord_t), 16);
200 if(rdman->coord_pool == NULL) {
201 elmpool_free(rdman->geo_pool);
202 return ERR;
203 }
204
205 rdman->shnode_pool = elmpool_new(sizeof(shnode_t), 16);
206 if(rdman->shnode_pool == NULL) {
207 elmpool_free(rdman->geo_pool);
208 elmpool_free(rdman->coord_pool);
209 return ERR;
210 }
211
212 rdman->root_coord = elmpool_elm_alloc(rdman->coord_pool);
213 if(rdman->root_coord == NULL)
214 redraw_man_destroy(rdman);
215 rdman->n_coords = 1;
216 coord_init(rdman->root_coord, NULL);
217
218 rdman->cr = cr;
219 rdman->backend = backend;
220
221 return OK;
222 }
223
224 void redraw_man_destroy(redraw_man_t *rdman) {
225 elmpool_free(rdman->coord_pool);
226 elmpool_free(rdman->geo_pool);
227 elmpool_free(rdman->shnode_pool);
228 if(rdman->dirty_coords)
229 free(rdman->dirty_coords);
230 if(rdman->dirty_geos)
231 free(rdman->dirty_geos);
232 }
233
234
235 #define ASSERT(x)
236 /*
237 * Change transformation matrix
238 * - update aggregated transformation matrix
239 * - of coord_t object been changed.
240 * - of children coord_t objects.
241 * - redraw members of coord_t objects.
242 * - redraw shape objects they are overlaid with members.
243 * - find out overlaid shape objects.
244 * - geo_t of a coord_t object
245 * - can make finding more efficiency.
246 * - fill overlay geo_t objects of members.
247 *
248 * Change a shape object
249 * - redraw changed object.
250 * - redraw shape objects they are overlaid with changed object.
251 * - find out overlaid shape objects.
252 *
253 * That coord and geo of shape objects are setted by user code
254 * give user code a chance to collect coord and geo objects together
255 * and gain interest of higher cache hit rate.
256 */
257
258 /*! \brief Find out all affected shape objects.
259 *
260 * Find out all shape objects that are overalid with geo_t of
261 * a geometry changed object.
262 *
263 * Linear scan geo_t objects of all shape objects in all_shapes
264 * list of a redraw_man_t object.
265 */
266 int rdman_find_overlaid_shapes(redraw_man_t *rdman, geo_t *geo,
267 geo_t ***overlays) {
268 int n_geos;
269 geo_t **geos;
270 geo_t *geo_cur;
271 int n_overlays;
272 geo_t **_overlays;
273 int i; 469 int i;
274 470 int n_dirty_geos;
275 n_geos = rdman->n_geos; 471 geo_t **dirty_geos;
276 472 geo_t *visit_geo;
277 geos = (geo_t **)malloc(sizeof(geo_t *) * n_geos); 473
278 if(geos == NULL) 474 n_dirty_geos = rdman->n_dirty_geos;
279 return -1; 475 if(n_dirty_geos > 0) {
280 476 dirty_geos = rdman->dirty_geos;
281 _overlays = (geo_t **)malloc(sizeof(geo_t *) * n_geos); 477 for(i = 0; i < n_dirty_geos; i++) {
282 if(geos == NULL) { 478 visit_geo = dirty_geos[i];
283 free(geos); 479 if(!(visit_geo->flags & GEF_DIRTY))
284 return -1; 480 continue;
285 } 481
286 482 SWAP(visit_geo->cur_area, visit_geo->last_area, area_t *);
287 geo_cur = STAILQ_HEAD(rdman->all_geos); 483 clean_shape(visit_geo->shape);
288 for(i = 0; i < n_geos; i++) { 484 add_dirty_area(rdman, visit_geo->cur_area);
289 geos[i] = geo_cur; 485 add_dirty_area(rdman, visit_geo->last_area);
290 geo_cur = STAILQ_NEXT(geo_t, next, geo_cur);
291 }
292 geo_mark_overlay(geo, n_geos, geos, &n_overlays, _overlays);
293
294 free(geos);
295 *overlays = _overlays;
296
297 return n_overlays;
298 }
299
300 int rdman_add_shape(redraw_man_t *rdman, shape_t *shape, coord_t *coord) {
301 geo_t *geo;
302 #ifdef GEO_ORDER
303 geo_t *visit;
304 unsigned int next_order;
305 #endif
306 int r;
307
308 geo = elmpool_elm_alloc(rdman->geo_pool);
309 if(geo == NULL)
310 return ERR;
311
312 geo_init(geo);
313
314 sh_attach_geo(shape, geo);
315 STAILQ_INS_TAIL(rdman->all_geos, geo_t, next, geo);
316 rdman->n_geos++;
317
318 #ifdef GEO_ORDER
319 /* TODO: remove order number. */
320 geo->order = ++rdman->next_geo_order;
321 if(geo->order == 0) {
322 next_order = 0;
323 for(visit = STAILQ_HEAD(rdman->all_geos);
324 visit != NULL;
325 visit = STAILQ_NEXT(geo_t, next, visit))
326 visit->order = ++next_order;
327 rdman->next_geo_order = next_order;
328 }
329 #endif
330
331 /* New one should be dirty to recompute it when drawing. */
332 geo->flags |= GEF_DIRTY;
333 r = add_dirty_geo(rdman, geo);
334 if(r != OK)
335 return ERR;
336
337 sh_attach_coord(shape, coord);
338
339 return OK;
340 }
341
342 /*! \brief Remove a shape object from redraw manager.
343 *
344 * TODO: redraw shape objects that overlaid with removed one.
345 */
346 int rdman_remove_shape(redraw_man_t *rdman, shape_t *shape) {
347 STAILQ_REMOVE(rdman->all_geos, geo_t, next, shape->geo);
348 elmpool_elm_free(rdman->geo_pool, shape->geo);
349 sh_detach_geo(shape);
350 rdman->n_geos--;
351 sh_detach_coord(shape);
352 return OK;
353 }
354
355 coord_t *rdman_coord_new(redraw_man_t *rdman, coord_t *parent) {
356 coord_t *coord, *root_coord;
357 coord_t *visit;
358
359 coord = elmpool_elm_alloc(rdman->coord_pool);
360 if(coord == NULL)
361 return NULL;
362
363 coord_init(coord, parent);
364 rdman->n_coords++;
365
366 coord->order = ++rdman->next_coord_order;
367 if(coord->order == 0) {
368 rdman->next_coord_order = 0;
369 root_coord = visit = rdman->root_coord;
370 /* skip root coord. */
371 visit = preorder_coord_subtree(root_coord, visit);
372 while(visit) {
373 visit->order = ++rdman->next_coord_order;
374 visit = preorder_coord_subtree(root_coord, visit);
375 } 486 }
376 } 487 rdman->n_dirty_geos = 0;
377 488 }
378 return coord; 489
379 } 490 return OK;
380
381 /*! \brief Free a coord of a redraw_man_t object.
382 *
383 * \param coord is a coord_t without children and members.
384 * \return 0 for successful, -1 for error.
385 */
386 int rdman_coord_free(redraw_man_t *rdman, coord_t *coord) {
387 coord_t *parent;
388
389 parent = coord->parent;
390 if(parent == NULL)
391 return ERR;
392
393 if(STAILQ_HEAD(coord->members) != NULL)
394 return ERR;
395
396 if(STAILQ_HEAD(coord->children) != NULL)
397 return ERR;
398
399 STAILQ_REMOVE(parent->children, coord_t, sibling, coord);
400 elmpool_elm_free(rdman->coord_pool, coord);
401 rdman->n_coords--;
402
403 return OK;
404 }
405
406 /*! \brief Mark a coord is changed.
407 *
408 * A changed coord_t object is marked as dirty and put
409 * into dirty_coords list.
410 */
411 int rdman_coord_changed(redraw_man_t *rdman, coord_t *coord) {
412 coord_t *child;
413 int max_dirty_coords;
414 int r;
415
416 if(coord->flags & COF_DIRTY)
417 return OK;
418
419 if(rdman->n_dirty_coords >= rdman->max_dirty_coords) {
420 /* Max of dirty_coords is not big enough. */
421 max_dirty_coords = rdman->max_dirty_coords + 16;
422
423 r = extend_memblk((void **)&rdman->dirty_coords,
424 sizeof(coord_t *) * rdman->n_dirty_coords,
425 sizeof(coord_t *) * max_dirty_coords);
426 rdman->max_dirty_coords = max_dirty_coords;
427 }
428
429 /* Make the coord and child coords dirty. */
430 for(child = coord;
431 child != NULL;
432 child = preorder_coord_subtree(coord, child)) {
433 rdman->dirty_coords[rdman->n_dirty_coords++] = coord;
434 coord->flags |= COF_DIRTY;
435 }
436
437 return OK;
438 }
439
440 static int _rdman_shape_changed(redraw_man_t *rdman, shape_t *shape) {
441 geo_t *geo;
442 int r;
443
444 geo = shape->geo;
445
446 if(geo->flags & GEF_DIRTY)
447 return OK;
448
449 r = add_dirty_geo(rdman, geo);
450 if(r == ERR)
451 return ERR;
452 geo->flags |= GEF_DIRTY;
453
454 return OK;
455 }
456
457 /*! \brief Mark a shape is changed.
458 *
459 * The geo_t object of a changed shape is mark as dirty and
460 * put into dirty_geos list.
461 */
462 int rdman_shape_changed(redraw_man_t *rdman, shape_t *shape) {
463 return _rdman_shape_changed(rdman, shape);
464 } 491 }
465 492
466 /* Drawing and Redrawing 493 /* Drawing and Redrawing
467 * ============================================================ 494 * ============================================================
468 */ 495 */
549 } 576 }
550 #else /* UNITTEST */ 577 #else /* UNITTEST */
551 static void clean_canvas(cairo_t *cr) { 578 static void clean_canvas(cairo_t *cr) {
552 } 579 }
553 580
554 static void make_clip(cairo_t *cr, int n_dirty_areas,
555 area_t **dirty_areas) {
556 }
557
558 static void reset_clip(redraw_man_t *rdman) { 581 static void reset_clip(redraw_man_t *rdman) {
559 } 582 }
560 583
561 static void copy_cr_2_backend(redraw_man_t *rdman, int n_dirty_areas, 584 static void copy_cr_2_backend(redraw_man_t *rdman, int n_dirty_areas,
562 area_t **dirty_areas) { 585 area_t **dirty_areas) {
615 * Clean dirty flag can prevent redundant computing for geo and 638 * Clean dirty flag can prevent redundant computing for geo and
616 * corod objects. 639 * corod objects.
617 * 640 *
618 */ 641 */
619 int rdman_redraw_changed(redraw_man_t *rdman) { 642 int rdman_redraw_changed(redraw_man_t *rdman) {
620 int i, r; 643 int r;
621 geo_t *visit_geo, **dirty_geos;
622 int n_dirty_geos;
623 int n_dirty_areas; 644 int n_dirty_areas;
624 area_t **dirty_areas; 645 area_t **dirty_areas;
625 646
626 r = clean_rdman_coords(rdman); 647 r = clean_rdman_coords(rdman);
627 if(r != OK) 648 if(r != OK)
628 return ERR; 649 return ERR;
629 650
630 n_dirty_geos = rdman->n_dirty_geos; 651 r = clean_rdman_geos(rdman);
631 if(n_dirty_geos > 0) { 652 if(r != OK)
632 dirty_geos = rdman->dirty_geos; 653 return ERR;
633 for(i = 0; i < n_dirty_geos; i++) { 654
634 visit_geo = dirty_geos[i];
635 if(!(visit_geo->flags & GEF_DIRTY))
636 continue;
637
638 SWAP(visit_geo->cur_area, visit_geo->last_area, area_t *);
639 clean_shape(visit_geo->shape);
640 add_dirty_area(rdman, visit_geo->cur_area);
641 add_dirty_area(rdman, visit_geo->last_area);
642 }
643 rdman->n_dirty_geos = 0;
644 }
645
646 n_dirty_areas = rdman->n_dirty_areas; 655 n_dirty_areas = rdman->n_dirty_areas;
647 dirty_areas = rdman->dirty_areas; 656 dirty_areas = rdman->dirty_areas;
648 if(n_dirty_areas > 0) { 657 if(n_dirty_areas > 0) {
649 clean_canvas(rdman->cr); 658 clean_canvas(rdman->cr);
650 draw_shapes_in_areas(rdman, n_dirty_areas, dirty_areas); 659 draw_shapes_in_areas(rdman, n_dirty_areas, dirty_areas);