1 /* Fo
2 * fo-area.c: Base area object of area object system
3 *
4 * Copyright (C) 2001 Sun Microsystems
5 * Copyright (C) 2007-2010 Menteith Consulting Ltd
6 * Copyright (C) 2011-2012 Mentea
7 *
8 * See COPYING for the status of this software.
9 */
10
11 #include "fo-utils.h"
12 #include "fo-node.h"
13 #include "property/fo-property-break-after.h"
14 #include "property/fo-property-break-before.h"
15 #include "property/fo-property-start-indent.h"
16 #include "property/fo-property-end-indent.h"
17 #include "property/fo-property-space-before.h"
18 #include "property/fo-property-space-after.h"
19 #include "property/fo-property-border-before-width.h"
20 #include "property/fo-property-border-after-width.h"
21 #include "property/fo-property-border-start-width.h"
22 #include "property/fo-property-border-end-width.h"
23 #include "property/fo-property-padding-before.h"
24 #include "property/fo-property-padding-after.h"
25 #include "property/fo-property-padding-start.h"
26 #include "property/fo-property-padding-end.h"
27 #include "fo/fo-block-fo.h"
28 #include "area/fo-area.h"
29 #include "area/fo-area-private.h"
30 #include "area/fo-area-area.h"
31 #include "area/fo-area-reference.h"
32 #include "area/fo-area-page.h"
33
34 GType
fo_area_flags_class_get_type(void)35 fo_area_flags_class_get_type (void)
36 {
37 static GType ftype = 0;
38 if (ftype == 0)
39 {
40 static const GFlagsValue values[] = {
41 { FO_AREA_FLAG_CLASS_UNKNOWN, "FO_AREA_FLAG_CLASS_UNKNOWN", "unknown" },
42 { FO_AREA_FLAG_CLASS_NORMAL, "FO_AREA_FLAG_CLASS_NORMAL", "normal" },
43 { FO_AREA_FLAG_CLASS_ABSOLUTE, "FO_AREA_FLAG_CLASS_ABSOLUTE", "absolute" },
44 { FO_AREA_FLAG_CLASS_FIXED, "FO_AREA_FLAG_CLASS_FIXED", "fixed" },
45 { FO_AREA_FLAG_CLASS_BEFORE_FLOAT, "FO_AREA_FLAG_CLASS_BEFORE_FLOAT", "before-float" },
46 { FO_AREA_FLAG_CLASS_SIDE_FLOAT, "FO_AREA_FLAG_CLASS_SIDE_FLOAT", "side-float" },
47 { FO_AREA_FLAG_CLASS_FOOTNOTE, "FO_AREA_FLAG_CLASS_FOOTNOTE", "footnote" },
48 { FO_AREA_FLAG_CLASS_ANCHOR, "FO_AREA_FLAG_CLASS_ANCHOR", "anchor" },
49 { FO_AREA_FLAG_CLASS_STACKABLE, "FO_AREA_FLAG_CLASS_STACKABLE", "stackable" },
50 { FO_AREA_FLAG_CLASS_PAGE_LEVEL_OUT_OF_LINE, "FO_AREA_FLAG_CLASS_PAGE_LEVEL_OUT_OF_LINE", "page-level-out-of-line" },
51 { FO_AREA_FLAG_CLASS_REFERENCE_LEVEL_OUT_OF_LINE, "FO_AREA_FLAG_CLASS_REFERENCE_LEVEL_OUT_OF_LINE", "reference-level-out-of-line" },
52 { FO_AREA_FLAG_CLASS_OUT_OF_LINE, "FO_AREA_FLAG_CLASS_OUT_OF_LINE", "out-of-line" },
53 { 0, NULL, NULL }
54 };
55 ftype = g_flags_register_static ("FoAreaFlagsClass", values);
56 }
57 return ftype;
58 }
59
60 enum {
61 PROP_0,
62 PROP_CLASS,
63 PROP_PAGE_SEQUENCE,
64 PROP_IS_FIRST,
65 PROP_IS_LAST,
66 PROP_NEXT_X,
67 PROP_NEXT_Y,
68 PROP_AVAILABLE_WIDTH,
69 PROP_AVAILABLE_HEIGHT,
70 PROP_CHILD_AVAILABLE_IPDIM,
71 PROP_CHILD_AVAILABLE_BPDIM,
72 PROP_GENERATED_BY
73 };
74
75 static void _init (FoArea *object);
76 static void _base_class_init (FoAreaClass *klass);
77 static void fo_area_class_init (FoAreaClass *klass);
78 static void fo_area_get_property (GObject *object,
79 guint prop_id,
80 GValue *value,
81 GParamSpec *pspec);
82 static void fo_area_set_property (GObject *object,
83 guint prop_id,
84 const GValue *value,
85 GParamSpec *pspec);
86 static void _dispose (GObject *object);
87
88 static void fo_area_debug_dump (FoObject *object,
89 gint depth);
90 static gchar* fo_area_sprintf (FoObject *object);
91 static void _debug_dump_properties_default (FoArea *area,
92 gint depth);
93 static void fo_area_draw (FoArea *area, gpointer output);
94 static FoArea* fo_area_clone_default (FoArea *original);
95 static void _update_after_clone_default (FoArea *clone,
96 FoArea *original);
97 static FoArea* fo_area_split_before_height_default (FoArea *area,
98 gdouble height);
99 static gboolean fo_area_split_before_height_check_default (FoArea *area,
100 gdouble height);
101 static FoArea* fo_area_split_after_height_default (FoArea *area,
102 gdouble height);
103 static gboolean fo_area_split_after_height_check_default (FoArea *area,
104 gdouble height);
105 static FoArea* _size_request (FoArea *child);
106 static void fo_area_default_resolve_text_align (FoArea *area);
107 static void _node_unlink_with_next_siblings (FoNode *area);
108 static FoNode* _node_insert_with_next_siblings (FoNode *parent,
109 gint position,
110 FoNode *area);
111 static FoNode* _node_insert (FoNode *parent,
112 gint position,
113 FoNode *area);
114 static FoNode* _node_insert_before (FoNode *parent,
115 FoNode *sibling,
116 FoNode *area);
117 static FoNode* _node_insert_after (FoNode *parent,
118 FoNode *sibling,
119 FoNode *area);
120 static FoNode* _node_prepend (FoNode *parent,
121 FoNode *area);
122 static FoNode* _node_append (FoNode *parent,
123 FoNode *area);
124 static gboolean _release_default (FoNode *fo_node,
125 gpointer data);
126
127 static gpointer parent_class;
128
129 /**
130 * fo_area_get_type:
131 *
132 * Register the #FoArea object type.
133 *
134 * Return value: #GType value of the #FoArea object type.
135 **/
136 GType
fo_area_get_type(void)137 fo_area_get_type (void)
138 {
139 static GType object_type = 0;
140
141 if (!object_type)
142 {
143 static const GTypeInfo object_info =
144 {
145 sizeof (FoAreaClass),
146 (GBaseInitFunc) _base_class_init,
147 (GBaseFinalizeFunc) NULL,
148 (GClassInitFunc) fo_area_class_init,
149 NULL, /* class_finalize */
150 NULL, /* class_data */
151 sizeof (FoArea),
152 0, /* n_preallocs */
153 (GInstanceInitFunc) _init,
154 NULL /* value_table */
155 };
156
157 object_type = g_type_register_static (FO_TYPE_NODE,
158 "FoArea",
159 &object_info,
160 0);
161 }
162
163 return object_type;
164 }
165
166 /**
167 * _init:
168 * @fo_area: #FoArea object to initialise
169 *
170 * Implements #GInstanceInitFunc for #FoArea
171 **/
172 static void
_init(FoArea * object)173 _init (FoArea *object)
174 {
175 object->is_first = TRUE;
176 object->is_last = TRUE;
177 }
178
179 /**
180 * _base_class_init:
181 * @klass: #FoAreaClass base class object to initialise
182 *
183 * Implements #GBaseInitFunc for #FoAreaClass
184 **/
185 static void
_base_class_init(FoAreaClass * klass)186 _base_class_init (FoAreaClass *klass)
187 {
188 FoObjectClass *fo_object_class = FO_OBJECT_CLASS (klass);
189
190 fo_object_class->debug_dump = fo_area_debug_dump;
191 fo_object_class->print_sprintf = fo_area_sprintf;
192
193 FoNodeClass *fo_node_class = FO_NODE_CLASS (klass);
194
195 fo_node_class->insert = _node_insert;
196 fo_node_class->insert_before = _node_insert_before;
197 fo_node_class->insert_after = _node_insert_after;
198 fo_node_class->insert_with_next_siblings =
199 _node_insert_with_next_siblings;
200 fo_node_class->unlink_with_next_siblings =
201 _node_unlink_with_next_siblings;
202 fo_node_class->prepend = _node_prepend;
203 fo_node_class->append = _node_append;
204
205 klass->debug_dump_properties = _debug_dump_properties_default;
206 klass->add_child = fo_area_real_add_child;
207 klass->clone = fo_area_clone_default;
208 klass->update_after_clone = _update_after_clone_default;
209 klass->split_before_height = fo_area_split_before_height_default;
210 klass->split_before_height_check = fo_area_split_before_height_check_default;
211 klass->split_after_height = fo_area_split_after_height_default;
212 klass->split_after_height_check = fo_area_split_after_height_check_default;
213 klass->size_request = _size_request;
214 klass->resolve_text_align = fo_area_default_resolve_text_align;
215 klass->release =
216 _release_default;
217 }
218
219 /**
220 * fo_area_class_init:
221 * @klass: #FoAreaClass object to initialise
222 *
223 * Implements #GClassInitFunc for #FoAreaClass
224 **/
225 void
fo_area_class_init(FoAreaClass * klass)226 fo_area_class_init (FoAreaClass *klass)
227 {
228 GObjectClass *object_class = G_OBJECT_CLASS (klass);
229
230 parent_class = g_type_class_peek_parent (klass);
231
232 object_class->dispose = _dispose;
233
234 object_class->get_property = fo_area_get_property;
235 object_class->set_property = fo_area_set_property;
236
237 klass->debug_dump_properties = fo_area_debug_dump_properties;
238 klass->draw = fo_area_draw;
239
240 g_object_class_install_property
241 (object_class,
242 PROP_CLASS,
243 g_param_spec_flags ("class",
244 _("Area class"),
245 _("XSL area-class trait"),
246 FO_TYPE_AREA_FLAGS_CLASS,
247 FO_AREA_FLAG_CLASS_UNKNOWN,
248 G_PARAM_READABLE));
249 g_object_class_install_property
250 (object_class,
251 PROP_PAGE_SEQUENCE,
252 g_param_spec_object ("page_sequence",
253 _("fo:page_sequence node"),
254 _("Ancestor fo:page_sequence node in the formatting object tree"),
255 FO_TYPE_FO,
256 G_PARAM_READWRITE));
257 g_object_class_install_property
258 (object_class,
259 PROP_PAGE_SEQUENCE,
260 g_param_spec_object ("page",
261 _("Page area"),
262 _("Ancestor FoAreaPage node in the area tree"),
263 FO_TYPE_AREA,
264 G_PARAM_READABLE));
265 g_object_class_install_property
266 (object_class,
267 PROP_IS_FIRST,
268 g_param_spec_boolean ("is-first",
269 _("Is first?"),
270 _("Is this the first area produced by the formatting object?"),
271 TRUE,
272 G_PARAM_READABLE));
273 g_object_class_install_property
274 (object_class,
275 PROP_IS_LAST,
276 g_param_spec_boolean ("is-last",
277 _("Is last?"),
278 _("Is this the last area produced by the formatting object?"),
279 TRUE,
280 G_PARAM_READABLE));
281 g_object_class_install_property
282 (object_class,
283 PROP_NEXT_X,
284 g_param_spec_float ("next-x",
285 _("next x"),
286 _("x-coordinate of next child area"),
287 0,
288 G_MAXFLOAT,
289 0,
290 G_PARAM_READWRITE));
291 g_object_class_install_property
292 (object_class,
293 PROP_NEXT_Y,
294 g_param_spec_float ("next-y",
295 _("next y"),
296 _("y-coordinate of next child area"),
297 0,
298 G_MAXFLOAT,
299 0,
300 G_PARAM_READWRITE));
301 g_object_class_install_property
302 (object_class,
303 PROP_AVAILABLE_WIDTH,
304 g_param_spec_float ("available-width",
305 _("Available width"),
306 _("Width available to child areas"),
307 0,
308 G_MAXFLOAT,
309 0,
310 G_PARAM_READWRITE));
311 g_object_class_install_property
312 (object_class,
313 PROP_AVAILABLE_HEIGHT,
314 g_param_spec_float ("available-height",
315 _("Available height"),
316 _("Height available to child areas"),
317 -G_MAXFLOAT,
318 G_MAXFLOAT,
319 0,
320 G_PARAM_READWRITE));
321 g_object_class_install_property
322 (object_class,
323 PROP_CHILD_AVAILABLE_IPDIM,
324 g_param_spec_float ("child-available-ipdim",
325 _("Child available IPDim"),
326 _("Inline-progression-dimension available to child areas"),
327 0,
328 G_MAXFLOAT,
329 0,
330 G_PARAM_READWRITE));
331 g_object_class_install_property
332 (object_class,
333 PROP_CHILD_AVAILABLE_BPDIM,
334 g_param_spec_float ("child-available-bpdim",
335 _("Child available BPDim"),
336 _("Block-progression-dimension available to child areas"),
337 0,
338 G_MAXFLOAT,
339 0,
340 G_PARAM_READWRITE));
341 g_object_class_install_property
342 (object_class,
343 PROP_GENERATED_BY,
344 g_param_spec_object ("generated-by",
345 _("Generated by"),
346 _("Formatting object that generated this area"),
347 FO_TYPE_FO,
348 G_PARAM_READWRITE));
349 }
350
351 /**
352 * _dispose:
353 * @object: #FoArea object to dispose
354 *
355 * Implements #GObject dispose() function for #FoArea
356 **/
357 void
_dispose(GObject * object)358 _dispose (GObject *object)
359 {
360 FoArea *area = FO_AREA (object);
361
362 fo_area_set_page (area, NULL);
363
364 if (area->generated_by != NULL)
365 {
366 fo_fo_area_list_remove (area->generated_by,
367 area);
368 area->generated_by = NULL;
369 }
370
371 G_OBJECT_CLASS (parent_class)->dispose (object);
372 }
373
374
375 /**
376 * fo_area_get_property:
377 * @object: #GObject whose property will be retreived
378 * @prop_id: Property ID assigned when property registered
379 * @value: #GValue to set with property value
380 * @pspec: Parameter specification for this property type
381 *
382 * Implements #GObjectGetPropertyFunc for #FoArea
383 **/
384 void
fo_area_get_property(GObject * object,guint param_id,GValue * value,GParamSpec * pspec)385 fo_area_get_property (GObject *object,
386 guint param_id,
387 GValue *value,
388 GParamSpec *pspec)
389 {
390 FoArea *area = FO_AREA (object);
391
392 switch (param_id)
393 {
394 case PROP_CLASS:
395 g_value_set_flags (value,
396 area->class);
397 break;
398 case PROP_PAGE_SEQUENCE:
399 g_value_set_object (value,
400 area->page_sequence ? G_OBJECT (area->page_sequence) : NULL);
401 break;
402 case PROP_IS_FIRST:
403 g_value_set_boolean (value, area->is_first);
404 break;
405 case PROP_IS_LAST:
406 g_value_set_boolean (value, area->is_last);
407 break;
408 case PROP_NEXT_X:
409 g_value_set_float (value, area->next_x);
410 break;
411 case PROP_NEXT_Y:
412 g_value_set_float (value, area->next_y);
413 break;
414 case PROP_AVAILABLE_WIDTH:
415 g_value_set_float (value, fo_area_get_available_width (area));
416 break;
417 case PROP_AVAILABLE_HEIGHT:
418 g_value_set_float (value, fo_area_get_available_height (area));
419 break;
420 case PROP_CHILD_AVAILABLE_IPDIM:
421 g_value_set_float (value, fo_area_get_child_available_ipdim (area));
422 break;
423 case PROP_CHILD_AVAILABLE_BPDIM:
424 g_value_set_float (value, fo_area_get_child_available_bpdim (area));
425 break;
426 case PROP_GENERATED_BY:
427 g_value_set_object (value,
428 area->generated_by ? G_OBJECT (area->generated_by) : NULL);
429 break;
430 default:
431 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
432 break;
433 }
434 }
435
436 /**
437 * fo_area_set_property:
438 * @object: #GObject whose property will be set
439 * @prop_id: Property ID assigned when property registered
440 * @value: New value for property
441 * @pspec: Parameter specification for this property type
442 *
443 * Implements #GObjectSetPropertyFunc for #FoArea
444 **/
445 void
fo_area_set_property(GObject * object,guint param_id,const GValue * value,GParamSpec * pspec)446 fo_area_set_property (GObject *object,
447 guint param_id,
448 const GValue *value,
449 GParamSpec *pspec)
450 {
451 FoArea *fo_area;
452
453 fo_area = FO_AREA (object);
454
455 switch (param_id)
456 {
457 case PROP_PAGE_SEQUENCE:
458 fo_area_set_page_sequence (fo_area, g_value_get_object (value));
459 break;
460 case PROP_IS_FIRST:
461 fo_area_set_is_first (fo_area, g_value_get_boolean (value));
462 break;
463 case PROP_IS_LAST:
464 fo_area_set_is_last (fo_area, g_value_get_boolean (value));
465 break;
466 case PROP_NEXT_X:
467 fo_area_set_next_x (fo_area, g_value_get_float (value));
468 break;
469 case PROP_NEXT_Y:
470 fo_area_set_next_y (fo_area, g_value_get_float (value));
471 break;
472 case PROP_AVAILABLE_WIDTH:
473 fo_area_set_available_width (fo_area, g_value_get_float (value));
474 break;
475 case PROP_AVAILABLE_HEIGHT:
476 fo_area_set_available_height (fo_area, g_value_get_float (value));
477 break;
478 case PROP_CHILD_AVAILABLE_IPDIM:
479 fo_area_set_child_available_ipdim (fo_area, g_value_get_float (value));
480 break;
481 case PROP_CHILD_AVAILABLE_BPDIM:
482 fo_area_set_child_available_bpdim (fo_area, g_value_get_float (value));
483 break;
484 case PROP_GENERATED_BY:
485 fo_area_set_generated_by (fo_area, g_value_get_object (value));
486 break;
487 default:
488 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
489 break;
490 }
491 }
492
493 /**
494 * fo_area_new:
495 *
496 * Creates a new #FoArea initialized to default value.
497 *
498 * Return value: the new #FoArea
499 **/
500 FoArea *
fo_area_new(void)501 fo_area_new (void)
502 {
503 FoArea *object;
504
505 object = FO_AREA (g_object_new (fo_area_get_type (),
506 NULL));
507
508 return object;
509 }
510
511 /**
512 * fo_area_get_class:
513 * @fo_area: The @FoArea object
514 *
515 * Gets the #class property of @area
516 *
517 * Return value: The "class" property value
518 **/
519 FoAreaFlagsClass
fo_area_get_class(FoArea * fo_area)520 fo_area_get_class (FoArea *fo_area)
521 {
522 g_return_val_if_fail (fo_area != NULL, 0);
523 g_return_val_if_fail (FO_IS_AREA (fo_area), 0);
524
525 return fo_area->class;
526 }
527
528 /**
529 * fo_area_get_is_first:
530 * @fo_area: The @FoArea object
531 *
532 * Gets the #is_first property of @area
533 *
534 * Return value: The "is-first" property value
535 **/
536 gboolean
fo_area_get_is_first(FoArea * fo_area)537 fo_area_get_is_first (FoArea *fo_area)
538 {
539 g_return_val_if_fail (fo_area != NULL, 0);
540 g_return_val_if_fail (FO_IS_AREA (fo_area), 0);
541
542 return fo_area->is_first;
543 }
544
545 /**
546 * fo_area_set_is_first:
547 * @fo_area: The @FoArea object
548 * @new_is_first: The new "is-first" property value
549 *
550 * Sets the #is-first property of @fo_area to @new_is_first
551 **/
552 void
fo_area_set_is_first(FoArea * fo_area,gboolean new_is_first)553 fo_area_set_is_first (FoArea *fo_area,
554 gboolean new_is_first)
555 {
556 g_return_if_fail (fo_area != NULL);
557 g_return_if_fail (FO_IS_AREA (fo_area));
558
559 fo_area->is_first = new_is_first;
560 /*g_object_notify (G_OBJECT (fo_area), "is-first");*/
561 }
562
563 /**
564 * fo_area_get_page:
565 * @fo_area: The @FoArea object
566 *
567 * Gets the #page property of @area
568 *
569 * Return value: The "page" property value
570 **/
571 FoArea*
fo_area_get_page(FoArea * fo_area)572 fo_area_get_page (FoArea *fo_area)
573 {
574 g_return_val_if_fail (fo_area != NULL, 0);
575 g_return_val_if_fail (FO_IS_AREA (fo_area), 0);
576
577 return fo_area->page;
578 }
579
580 /**
581 * fo_area_set_page:
582 * @fo_area: The @FoArea object
583 * @page_area: The new "page" property value
584 *
585 * Sets the #page property of @fo_area to @page_area
586 **/
587 void
fo_area_set_page(FoArea * fo_area,FoArea * page_area)588 fo_area_set_page (FoArea *fo_area,
589 FoArea *page_area)
590 {
591 g_return_if_fail (fo_area != NULL);
592 g_return_if_fail (FO_IS_AREA (fo_area));
593 g_return_if_fail ((page_area == NULL) ||
594 FO_IS_AREA_PAGE (page_area));
595
596 if (page_area != NULL)
597 {
598 g_object_ref (page_area);
599 }
600
601 if ((fo_area->page != NULL) &&
602 ((GObject *) fo_area->page)->ref_count > 0)
603 {
604 g_object_unref (fo_area->page);
605 }
606
607 fo_area->page = page_area;
608 /*g_object_notify (G_OBJECT (fo_area), "page");*/
609 }
610
611 /**
612 * fo_area_get_reference:
613 * @fo_area: The @FoArea object
614 *
615 * Gets the #reference property of @area
616 *
617 * Return value: The "reference" property value
618 **/
619 FoArea*
fo_area_get_reference(FoArea * fo_area)620 fo_area_get_reference (FoArea *fo_area)
621 {
622 g_return_val_if_fail (fo_area != NULL, 0);
623 g_return_val_if_fail (FO_IS_AREA (fo_area), 0);
624
625 return fo_area->reference;
626 }
627
628 /**
629 * fo_area_set_reference:
630 * @fo_area: The @FoArea object
631 * @reference_area: The new "reference" property value
632 *
633 * Sets the #reference property of @fo_area to @reference_area
634 **/
635 void
fo_area_set_reference(FoArea * fo_area,FoArea * reference_area)636 fo_area_set_reference (FoArea *fo_area,
637 FoArea *reference_area)
638 {
639 g_return_if_fail (fo_area != NULL);
640 g_return_if_fail (FO_IS_AREA (fo_area));
641
642 fo_area->reference = reference_area;
643 /*g_object_notify (G_OBJECT (fo_area), "reference");*/
644 }
645
646 /**
647 * fo_area_get_page_sequence:
648 * @fo_area: The @FoArea object
649 *
650 * Gets the #page_sequence property of @area
651 *
652 * Return value: The "page-sequence" property value
653 **/
654 FoArea*
fo_area_get_page_sequence(FoArea * fo_area)655 fo_area_get_page_sequence (FoArea *fo_area)
656 {
657 g_return_val_if_fail (fo_area != NULL, 0);
658 g_return_val_if_fail (FO_IS_AREA (fo_area), 0);
659
660 return fo_area->page_sequence;
661 }
662
663 /**
664 * fo_area_set_page_sequence:
665 * @fo_area: The @FoArea object
666 * @page_sequence_area: The new "page_sequence" property value
667 *
668 * Sets the "page-sequence" property of @area to @page_sequence_area
669 **/
670 void
fo_area_set_page_sequence(FoArea * fo_area,FoArea * page_sequence_area)671 fo_area_set_page_sequence (FoArea *fo_area,
672 FoArea *page_sequence_area)
673 {
674 g_return_if_fail (fo_area != NULL);
675 g_return_if_fail (FO_IS_AREA (fo_area));
676
677 fo_area->page_sequence = page_sequence_area;
678 /*g_object_notify (G_OBJECT (fo_area), "page-sequence");*/
679 }
680
681 /**
682 * fo_area_get_is_last:
683 * @fo_area: The @FoArea object
684 *
685 * Gets the #is_last property of @area
686 *
687 * Return value: The "is-last" property value
688 **/
689 gboolean
fo_area_get_is_last(FoArea * fo_area)690 fo_area_get_is_last (FoArea *fo_area)
691 {
692 g_return_val_if_fail (fo_area != NULL, 0);
693 g_return_val_if_fail (FO_IS_AREA (fo_area), 0);
694
695 return fo_area->is_last;
696 }
697
698 /**
699 * fo_area_set_is_last:
700 * @fo_area: The @FoArea object
701 * @new_is_last: The new "is-last" property value
702 *
703 * Sets the #is-last property of @area to @new_is_last
704 **/
705 void
fo_area_set_is_last(FoArea * fo_area,gboolean new_is_last)706 fo_area_set_is_last (FoArea *fo_area,
707 gboolean new_is_last)
708 {
709 g_return_if_fail (fo_area != NULL);
710 g_return_if_fail (FO_IS_AREA (fo_area));
711
712 fo_area->is_last = new_is_last;
713 /*g_object_notify (G_OBJECT (fo_area), "is-last");*/
714 }
715
716 /**
717 * fo_area_get_next_x:
718 * @fo_area: The @FoArea object
719 *
720 * Gets the #next_x property of @area
721 *
722 * Return value: The "next_x" property value
723 **/
724 gdouble
fo_area_get_next_x(FoArea * fo_area)725 fo_area_get_next_x (FoArea *fo_area)
726 {
727 g_return_val_if_fail (fo_area != NULL, 0);
728 g_return_val_if_fail (FO_IS_AREA (fo_area), 0);
729
730 return fo_area->next_x;
731 }
732
733 /**
734 * fo_area_set_next_x:
735 * @fo_area: The @FoArea object
736 * @new_next_x: The new "next_x" property value
737 *
738 * Sets the #next-x property of @area to @new_next_x
739 **/
740 void
fo_area_set_next_x(FoArea * fo_area,gdouble new_next_x)741 fo_area_set_next_x (FoArea *fo_area,
742 gdouble new_next_x)
743 {
744 g_return_if_fail (fo_area != NULL);
745 g_return_if_fail (FO_IS_AREA (fo_area));
746
747 fo_area->next_x = new_next_x;
748 /*g_object_notify (G_OBJECT (fo_area), "next-x");*/
749 }
750
751 /**
752 * fo_area_get_next_y:
753 * @fo_area: The @FoArea object
754 *
755 * Gets the "next_y" property of @area
756 *
757 * Return value: The "next-y" property value
758 **/
759 gdouble
fo_area_get_next_y(FoArea * fo_area)760 fo_area_get_next_y (FoArea *fo_area)
761 {
762 g_return_val_if_fail (fo_area != NULL, 0);
763 g_return_val_if_fail (FO_IS_AREA (fo_area), 0);
764
765 return fo_area->next_y;
766 }
767
768 /**
769 * fo_area_set_next_y:
770 * @fo_area: The @FoArea object
771 * @new_next_y: The new "next-y" property value
772 *
773 * Sets the #next-y property of @area to @new_next_y
774 **/
775 void
fo_area_set_next_y(FoArea * fo_area,gdouble new_next_y)776 fo_area_set_next_y (FoArea *fo_area,
777 gdouble new_next_y)
778 {
779 g_return_if_fail (fo_area != NULL);
780 g_return_if_fail (FO_IS_AREA (fo_area));
781
782 fo_area->next_y = new_next_y;
783 /*g_object_notify (G_OBJECT (fo_area), "next-y");*/
784 }
785
786 /**
787 * fo_area_get_available_width:
788 * @fo_area: The @FoArea object
789 *
790 * Gets the "available-width" property of @area
791 *
792 * Return value: The "available-width" property value
793 **/
794 gdouble
fo_area_get_available_width(FoArea * fo_area)795 fo_area_get_available_width (FoArea *fo_area)
796 {
797 g_return_val_if_fail (fo_area != NULL, 0);
798 g_return_val_if_fail (FO_IS_AREA (fo_area), 0);
799
800 return fo_area->available_width;
801 }
802
803 /**
804 * fo_area_set_available_width:
805 * @fo_area: The @FoArea object
806 * @new_available_width: The new "available-width" property value
807 *
808 * Sets the "available-width" property of @area to @new_available_width
809 **/
810 void
fo_area_set_available_width(FoArea * fo_area,gdouble new_available_width)811 fo_area_set_available_width (FoArea *fo_area,
812 gdouble new_available_width)
813 {
814 g_return_if_fail (fo_area != NULL);
815 g_return_if_fail (FO_IS_AREA (fo_area));
816
817 fo_area->available_width = new_available_width;
818 /*g_object_notify (G_OBJECT (fo_area), "available-width");*/
819 }
820
821 /**
822 * fo_area_get_available_height:
823 * @fo_area: The @FoArea object
824 *
825 * Gets the #available-height property of @area
826 *
827 * Return value: The "available_height" property value
828 **/
829 gdouble
fo_area_get_available_height(FoArea * fo_area)830 fo_area_get_available_height (FoArea *fo_area)
831 {
832 g_return_val_if_fail (fo_area != NULL, 0);
833 g_return_val_if_fail (FO_IS_AREA (fo_area), 0);
834
835 return fo_area->available_height;
836 }
837
838 /**
839 * fo_area_set_available_height:
840 * @fo_area: The @FoArea object
841 * @new_available_height: The new "available-height" property value
842 *
843 * Sets the #available-height property of @area to @new_available_height
844 **/
845 void
fo_area_set_available_height(FoArea * fo_area,gdouble new_available_height)846 fo_area_set_available_height (FoArea *fo_area,
847 gdouble new_available_height)
848 {
849 g_return_if_fail (fo_area != NULL);
850 g_return_if_fail (FO_IS_AREA (fo_area));
851
852 fo_area->available_height = new_available_height;
853 g_object_notify (G_OBJECT (fo_area), "available-height");
854 }
855
856 /**
857 * fo_area_get_child_available_ipdim:
858 * @fo_area: The @FoArea object
859 *
860 * Gets the "child-available-ipdim" property of @area
861 *
862 * Return value: The "child-available-ipdim" property value
863 **/
864 gdouble
fo_area_get_child_available_ipdim(FoArea * fo_area)865 fo_area_get_child_available_ipdim (FoArea *fo_area)
866 {
867 g_return_val_if_fail (fo_area != NULL, 0);
868 g_return_val_if_fail (FO_IS_AREA (fo_area), 0);
869
870 return fo_area->child_available_ipdim;
871 }
872
873 /**
874 * fo_area_set_child_available_ipdim:
875 * @fo_area: The @FoArea object
876 * @new_child_available_ipdim: The new "child-available-ipdim" property value
877 *
878 * Sets the "child-available-ipdim" property of @area to
879 * @new_child_available_ipdim
880 **/
881 void
fo_area_set_child_available_ipdim(FoArea * fo_area,gdouble new_child_available_ipdim)882 fo_area_set_child_available_ipdim (FoArea *fo_area,
883 gdouble new_child_available_ipdim)
884 {
885 g_return_if_fail (fo_area != NULL);
886 g_return_if_fail (FO_IS_AREA (fo_area));
887
888 fo_area->child_available_ipdim = new_child_available_ipdim;
889 /*g_object_notify (G_OBJECT (fo_area), "child-available-ipdim");*/
890 }
891
892 /**
893 * fo_area_get_child_available_bpdim:
894 * @fo_area: The @FoArea object
895 *
896 * Gets the "child-available-bpdim" property of @area
897 *
898 * Return value: The "child-available-bpdim" property value
899 **/
900 gdouble
fo_area_get_child_available_bpdim(FoArea * fo_area)901 fo_area_get_child_available_bpdim (FoArea *fo_area)
902 {
903 g_return_val_if_fail (fo_area != NULL, 0);
904 g_return_val_if_fail (FO_IS_AREA (fo_area), 0);
905
906 return fo_area->child_available_bpdim;
907 }
908
909 /**
910 * fo_area_set_child_available_bpdim:
911 * @fo_area: The @FoArea object
912 * @new_child_available_bpdim: The new "child-available-bpdim" property value
913 *
914 * Sets the "child-available-bpdim" property of @area to
915 * @new_child_available_bpdim
916 **/
917 void
fo_area_set_child_available_bpdim(FoArea * fo_area,gdouble new_child_available_bpdim)918 fo_area_set_child_available_bpdim (FoArea *fo_area,
919 gdouble new_child_available_bpdim)
920 {
921 g_return_if_fail (fo_area != NULL);
922 g_return_if_fail (FO_IS_AREA (fo_area));
923
924 fo_area->child_available_bpdim = new_child_available_bpdim;
925 /*g_object_notify (G_OBJECT (fo_area), "child-available-bpdim");*/
926 }
927
928 /**
929 * fo_area_get_generated_by:
930 * @fo_area: The @FoArea object
931 *
932 * Gets the #generated-by property of @area
933 *
934 * Return value: The "generated-by" property value
935 **/
936 FoFo*
fo_area_get_generated_by(FoArea * fo_area)937 fo_area_get_generated_by (FoArea *fo_area)
938 {
939 g_return_val_if_fail (fo_area != NULL, 0);
940 g_return_val_if_fail (FO_IS_AREA (fo_area), 0);
941
942 return fo_area->generated_by;
943 }
944
945 /**
946 * fo_area_set_generated_by:
947 * @fo_area: The @FoArea object
948 * @new_fo: The new "generated-by" property value
949 *
950 * Sets the #generated-by property of @area to @new_fo
951 **/
952 void
fo_area_set_generated_by(FoArea * fo_area,FoFo * new_fo)953 fo_area_set_generated_by (FoArea *fo_area,
954 FoFo *new_fo)
955 {
956 g_return_if_fail (fo_area != NULL);
957 g_return_if_fail (FO_IS_AREA (fo_area));
958
959 fo_area->generated_by = new_fo;
960 /*g_object_notify (G_OBJECT (fo_area), "generated-by");*/
961 }
962
963 /**
964 * fo_area_debug_dump:
965 * @object: #FoArea or subclass object instance to be dumped
966 * @depth: Relative indent to apply to the output
967 *
968 * Dump information about @object and its properties
969 **/
970 void
fo_area_debug_dump(FoObject * object,gint depth)971 fo_area_debug_dump (FoObject *object,
972 gint depth)
973 {
974 gchar *indent = g_strnfill (depth * 2, ' ');
975 gchar* object_sprintf;
976 FoArea *child;
977
978 g_return_if_fail (object != NULL);
979 g_return_if_fail (FO_IS_AREA (object));
980
981 object_sprintf = fo_object_debug_sprintf (object);
982
983 g_log (G_LOG_DOMAIN,
984 G_LOG_LEVEL_DEBUG,
985 "%s%s",
986 indent,
987 object_sprintf);
988
989 g_free (object_sprintf);
990 g_free (indent);
991
992 FO_AREA_GET_CLASS (object)->debug_dump_properties (FO_AREA (object),
993 depth + 2);
994 child = fo_area_first_child (FO_AREA (object));
995 while (child)
996 {
997 fo_object_debug_dump (child,
998 depth + 1);
999
1000 child = fo_area_next_sibling (child);
1001 }
1002 }
1003
1004 /**
1005 * fo_area_sprintf:
1006 * @object: #FoArea to print
1007 *
1008 * Returns a string name of the object type of #object.
1009 *
1010 * String must be freed by caller.
1011 *
1012 * Return value: String value of @object.
1013 **/
1014 gchar*
fo_area_sprintf(FoObject * object)1015 fo_area_sprintf (FoObject *object)
1016 {
1017 g_return_val_if_fail (object != NULL, NULL);
1018 g_return_val_if_fail (FO_IS_AREA (object), NULL);
1019
1020 return (g_strdup_printf("%s",
1021 g_type_name (G_TYPE_FROM_INSTANCE (object))));
1022 }
1023
1024
1025 /**
1026 * fo_area_real_add_child:
1027 * @parent: Parent area node
1028 * @child: Child area node
1029 *
1030 * Add @child as a child of @parent in the area tree and set @child's
1031 * page_sequence, page, and reference instance variables as
1032 * appropriate for both @parent and @child.
1033 *
1034 * Does NOT modify any other properties -- including geometric
1035 * properties -- of either @child or @parent.
1036 *
1037 * Return value: @child
1038 **/
1039 FoArea*
fo_area_real_add_child(FoArea * parent,FoArea * child)1040 fo_area_real_add_child (FoArea *parent, FoArea *child)
1041 {
1042 g_return_val_if_fail (parent != NULL, NULL);
1043 g_return_val_if_fail (FO_IS_AREA (parent), NULL);
1044 g_return_val_if_fail (child != NULL, NULL);
1045 g_return_val_if_fail (FO_IS_AREA (child), NULL);
1046
1047 fo_area_append (parent, child);
1048
1049 if (parent->page_sequence != NULL)
1050 child->page_sequence = parent->page_sequence;
1051 if (parent->page != NULL)
1052 child->page = parent->page;
1053 if (FO_IS_AREA_REFERENCE (child))
1054 {
1055 child->reference = child;
1056 }
1057 else
1058 {
1059 child->reference = parent->reference;
1060 }
1061
1062 return child;
1063 }
1064
1065 /**
1066 * fo_area_add_child:
1067 * @parent: Parent area node
1068 * @child: Child area node
1069 *
1070 * Add @child to @parent by calling the _add_child() function for
1071 * @parent.
1072 *
1073 * Return value: @child
1074 **/
1075 FoArea*
fo_area_add_child(FoArea * parent,FoArea * child)1076 fo_area_add_child (FoArea *parent, FoArea *child)
1077 {
1078 if (parent == NULL)
1079 {
1080 g_error ("area_add_child:: parent is NULL");
1081 return NULL;
1082 }
1083 else if (!FO_IS_AREA (parent))
1084 {
1085 g_error ("area_add_child:: parent is not an area: %s",
1086 fo_object_debug_sprintf (parent));
1087 return NULL;
1088 }
1089 else
1090 {
1091 return FO_AREA_GET_CLASS (parent)->add_child (parent, child);
1092 }
1093 }
1094
1095 /**
1096 * _debug_dump_properties_default:
1097 * @area: #FoArea or subclass object
1098 * @depth: Indent level to add to the output
1099 *
1100 * Default _debug_dump_properties() procedure that is used when an
1101 * FoArea subclass does not override the debug_dump_properties class
1102 * method.
1103 **/
1104 static void
_debug_dump_properties_default(FoArea * area,gint depth)1105 _debug_dump_properties_default (FoArea *area, gint depth)
1106 {
1107 gchar *indent = g_strnfill (depth * 2, ' ');
1108
1109 g_return_if_fail (FO_IS_AREA (area));
1110
1111 g_log (G_LOG_DOMAIN,
1112 G_LOG_LEVEL_DEBUG,
1113 "%s(No 'debug_dump_properties')",
1114 indent);
1115
1116 g_free (indent);
1117
1118 fo_area_debug_dump_properties (area, depth + 1);
1119 }
1120
1121 /**
1122 * fo_area_debug_dump_properties:
1123 * @area: The #FoArea object
1124 * @depth: Indent level to add to the output
1125 *
1126 * Dump the properties of @area.
1127 **/
1128 void
fo_area_debug_dump_properties(FoArea * area,gint depth)1129 fo_area_debug_dump_properties (FoArea *area, gint depth)
1130 {
1131 gchar *indent = g_strnfill (depth * 2, ' ');
1132 gchar *fo_sprintf;
1133
1134 g_return_if_fail (area != NULL);
1135 g_return_if_fail (FO_IS_AREA (area));
1136
1137 g_log (G_LOG_DOMAIN,
1138 G_LOG_LEVEL_DEBUG,
1139 "%sclass: %s",
1140 indent,
1141 g_flags_get_first_value (g_type_class_peek_static (FO_TYPE_AREA_FLAGS_CLASS),
1142 area->class)->value_nick);
1143 g_log (G_LOG_DOMAIN,
1144 G_LOG_LEVEL_DEBUG,
1145 "%sis-first: %s",
1146 indent,
1147 area->is_first ? "true" : "false");
1148
1149 fo_sprintf = fo_object_debug_sprintf (area->prev_part);
1150 g_log (G_LOG_DOMAIN,
1151 G_LOG_LEVEL_DEBUG,
1152 "%sprev-part: %s",
1153 indent,
1154 fo_sprintf);
1155 g_free (fo_sprintf);
1156
1157 g_log (G_LOG_DOMAIN,
1158 G_LOG_LEVEL_DEBUG,
1159 "%sis-last: %s",
1160 indent,
1161 area->is_last ? "true" : "false");
1162
1163 fo_sprintf = fo_object_debug_sprintf (area->next_part);
1164 g_log (G_LOG_DOMAIN,
1165 G_LOG_LEVEL_DEBUG,
1166 "%snext-part: %s",
1167 indent,
1168 fo_sprintf);
1169 g_free (fo_sprintf);
1170
1171 g_log (G_LOG_DOMAIN,
1172 G_LOG_LEVEL_DEBUG,
1173 "%snext-x: %g pt",
1174 indent,
1175 area->next_x);
1176 g_log (G_LOG_DOMAIN,
1177 G_LOG_LEVEL_DEBUG,
1178 "%snext-y: %g pt",
1179 indent,
1180 area->next_y);
1181 g_log (G_LOG_DOMAIN,
1182 G_LOG_LEVEL_DEBUG,
1183 "%savailable-width: %g pt",
1184 indent,
1185 area->available_width);
1186 g_log (G_LOG_DOMAIN,
1187 G_LOG_LEVEL_DEBUG,
1188 "%savailable-height: %g pt",
1189 indent,
1190 area->available_height);
1191 g_log (G_LOG_DOMAIN,
1192 G_LOG_LEVEL_DEBUG,
1193 "%schild-available-ipdim: %g pt",
1194 indent,
1195 area->child_available_ipdim);
1196 g_log (G_LOG_DOMAIN,
1197 G_LOG_LEVEL_DEBUG,
1198 "%schild-available-bpdim: %g pt",
1199 indent,
1200 area->child_available_bpdim);
1201
1202 fo_sprintf = fo_object_debug_sprintf (area->generated_by);
1203 g_log (G_LOG_DOMAIN,
1204 G_LOG_LEVEL_DEBUG,
1205 "%sgenerated-by: %s",
1206 indent,
1207 fo_sprintf);
1208 g_free (fo_sprintf);
1209
1210 fo_sprintf = fo_object_debug_sprintf (area->reference);
1211 g_log (G_LOG_DOMAIN,
1212 G_LOG_LEVEL_DEBUG,
1213 "%sreference: %s",
1214 indent,
1215 fo_sprintf);
1216 g_free (fo_sprintf);
1217
1218 fo_sprintf = fo_object_debug_sprintf (area->page);
1219 g_log (G_LOG_DOMAIN,
1220 G_LOG_LEVEL_DEBUG,
1221 "%spage: %s",
1222 indent,
1223 fo_sprintf);
1224 g_free (fo_sprintf);
1225
1226 g_free (indent);
1227 }
1228
1229 /**
1230 * fo_area_draw:
1231 * @area: #FoArea to draw.
1232 * @output: Where to draw it.
1233 *
1234 * Unused.
1235 **/
1236 void
fo_area_draw(FoArea * area,gpointer output G_GNUC_UNUSED)1237 fo_area_draw (FoArea *area,
1238 gpointer output G_GNUC_UNUSED)
1239 {
1240 g_return_if_fail (area != NULL);
1241
1242 g_warning (_("Area has no 'draw' function."));
1243 }
1244
1245 /**
1246 * fo_area_update_after_clone:
1247 * @clone: New object cloned from @original.
1248 * @original: Original area object.
1249 *
1250 * Update the instance variables of @clone to match those of @original.
1251 **/
1252 void
fo_area_update_after_clone(FoArea * clone,FoArea * original)1253 fo_area_update_after_clone (FoArea *clone,
1254 FoArea *original)
1255 {
1256 if (original == NULL || clone == NULL)
1257 {
1258 return;
1259 }
1260 else
1261 {
1262 FO_AREA_GET_CLASS (clone)->update_after_clone (clone, original);
1263 }
1264 }
1265
1266 /**
1267 * _update_after_clone_default:
1268 * @clone: New object cloned from @original
1269 * @original: Original area object
1270 *
1271 * Update the FoArea-specific instance variables of @clone to match
1272 * those of @original.
1273 **/
1274 static void
_update_after_clone_default(FoArea * clone,FoArea * original)1275 _update_after_clone_default (FoArea *clone,
1276 FoArea *original)
1277 {
1278 g_return_if_fail (clone != NULL);
1279 g_return_if_fail (FO_IS_AREA (clone));
1280 g_return_if_fail (original != NULL);
1281 g_return_if_fail (FO_IS_AREA (original));
1282
1283 fo_area_set_page_sequence (clone, original->page_sequence);
1284 fo_area_set_page (clone, fo_area_get_page (original));
1285 fo_area_set_reference (clone, original->reference);
1286 clone->is_first = FALSE;
1287 clone->prev_part = original;
1288 original->is_last = FALSE;
1289 original->next_part = clone;
1290 clone->generated_by = original->generated_by;
1291
1292 fo_fo_area_list_insert_after (clone->generated_by,
1293 original,
1294 clone);
1295
1296 if (fo_area_parent (original) != NULL)
1297 {
1298 fo_area_insert_after (fo_area_parent (original),
1299 original,
1300 clone);
1301 }
1302 }
1303
1304 /**
1305 * fo_area_clone:
1306 * @original: Area object to be cloned.
1307 *
1308 * Make a clone of @original and insert the clone after @original in
1309 * the area tree. Set instance properties of the clone to match
1310 * @original.
1311 *
1312 * Return value: Clone of @original.
1313 **/
1314 FoArea*
fo_area_clone(FoArea * original)1315 fo_area_clone (FoArea *original)
1316 {
1317 if (original != NULL)
1318 {
1319 return FO_AREA_GET_CLASS (original)->clone (original);
1320 }
1321 else
1322 {
1323 return NULL;
1324 }
1325 }
1326
1327 /**
1328 * fo_area_clone_default:
1329 * @original: Area object to be cloned
1330 *
1331 * Make a clone of @original and insert the clone after @original in
1332 * the area tree. Set instance properties of the clone to match
1333 * @original.
1334 *
1335 * Return value: Clone of @original
1336 **/
1337 FoArea*
fo_area_clone_default(FoArea * original)1338 fo_area_clone_default (FoArea *original)
1339 {
1340 FoArea *clone;
1341
1342 g_return_val_if_fail (original != NULL, NULL);
1343 g_return_val_if_fail (FO_IS_AREA (original), NULL);
1344
1345 clone = FO_AREA (g_object_new (G_TYPE_FROM_INSTANCE (original), NULL));
1346
1347 fo_area_update_after_clone (clone, original);
1348
1349 return clone;
1350 }
1351
1352 /**
1353 * fo_area_dump_path_to_root:
1354 * @area: #FoArea for which to dump path to root.
1355 *
1356 * Logs a representation of the area tree path from @area to the
1357 * tree's root.
1358 **/
1359 static void
fo_area_dump_path_to_root(FoArea * area)1360 fo_area_dump_path_to_root (FoArea *area)
1361 {
1362 FoArea *use_area;
1363 gint depth = 0;
1364 gchar *indent, *object_sprintf;
1365
1366 use_area = area;
1367
1368 while (!FO_AREA_IS_ROOT (use_area))
1369 {
1370 indent = g_strnfill (2 * depth++, ' ');
1371 object_sprintf = fo_object_debug_sprintf (use_area);
1372
1373 g_log (G_LOG_DOMAIN,
1374 G_LOG_LEVEL_DEBUG,
1375 "%s%s",
1376 indent,
1377 object_sprintf);
1378
1379 g_free (object_sprintf);
1380 g_free (indent);
1381
1382 use_area = fo_area_parent (use_area);
1383 }
1384 }
1385
1386 /**
1387 * fo_area_border_padding_space_resolve:
1388 * @parent_area: Parent area of @child_area.
1389 * @child_area: #FoArea for which to resolve properties.
1390 *
1391 * Resolves the border, padding, and space properties of @child_area.
1392 **/
1393 void
fo_area_border_padding_space_resolve(FoArea * parent_area,FoArea * child_area)1394 fo_area_border_padding_space_resolve (FoArea *parent_area, FoArea *child_area)
1395 {
1396 FoFo *child_fo;
1397 gdouble child_available_ipdim, child_available_bpdim;
1398 gdouble parent_next_x, parent_next_y;
1399 gdouble border_start_width = 0;
1400 gdouble border_end_width = 0;
1401 gdouble border_before_width = 0;
1402 gdouble border_after_width = 0;
1403 gdouble padding_start = 0;
1404 gdouble padding_end = 0;
1405 gdouble padding_before = 0;
1406 gdouble padding_after = 0;
1407 gdouble start_indent = 0, end_indent = 0;
1408 gdouble space_before = 0, space_after = 0;
1409 gboolean is_first, is_last;
1410
1411 g_return_if_fail (parent_area != NULL);
1412 g_return_if_fail (FO_IS_AREA (parent_area));
1413 g_return_if_fail (child_area != NULL);
1414 g_return_if_fail (FO_IS_AREA (child_area));
1415
1416 child_fo = child_area->generated_by;
1417
1418 g_object_get (parent_area,
1419 "child-available-ipdim", &child_available_ipdim,
1420 "child-available-bpdim", &child_available_bpdim,
1421 "next-x", &parent_next_x,
1422 "next-y", &parent_next_y,
1423 NULL);
1424
1425 #if defined(LIBFO_DEBUG) && 0
1426 g_message ("bps_resolve:: area: %s; area fo: %s; parent: %s; parent fo: %s",
1427 fo_object_debug_sprintf (child_area),
1428 fo_object_debug_sprintf (child_fo),
1429 fo_object_debug_sprintf (parent_area),
1430 fo_object_debug_sprintf (parent_area->generated_by);
1431 g_message ("bps_resolve:: parent:: child-available-ipdim: %f; child-available-bpdim: %f; next-x: %f; next-y: %f",
1432 child_available_ipdim,
1433 child_available_bpdim,
1434 parent_next_x,
1435 parent_next_y);
1436 #endif
1437
1438 g_object_get (child_area,
1439 "is-first", &is_first,
1440 "is_last", &is_last,
1441 NULL);
1442
1443 if (FO_IS_BLOCK_FO (child_fo))
1444 {
1445 border_start_width =
1446 fo_length_get_value (fo_property_get_value (fo_block_fo_get_border_start_width (child_fo)));
1447 border_end_width =
1448 fo_length_get_value (fo_property_get_value (fo_block_fo_get_border_end_width (child_fo)));
1449 border_before_width =
1450 fo_length_get_value (fo_property_get_value (fo_block_fo_get_border_before_width (child_fo)));
1451 border_after_width =
1452 fo_length_get_value (fo_property_get_value (fo_block_fo_get_border_after_width (child_fo)));
1453
1454 padding_start =
1455 fo_length_get_value (fo_property_get_value (fo_block_fo_get_padding_start (child_fo)));
1456 padding_end =
1457 fo_length_get_value (fo_property_get_value (fo_block_fo_get_padding_end (child_fo)));
1458 padding_before =
1459 fo_length_get_value (fo_property_get_value (fo_block_fo_get_padding_before (child_fo)));
1460 padding_after =
1461 fo_length_get_value (fo_property_get_value (fo_block_fo_get_padding_after (child_fo)));
1462
1463 start_indent =
1464 fo_length_get_value (fo_property_get_value (fo_block_fo_get_start_indent (child_fo)));
1465 end_indent =
1466 fo_length_get_value (fo_property_get_value (fo_block_fo_get_end_indent (child_fo)));
1467
1468 space_before =
1469 fo_length_get_value (fo_property_get_value (fo_block_fo_get_space_before (child_fo)));
1470 space_after =
1471 fo_length_get_value (fo_property_get_value (fo_block_fo_get_space_after (child_fo)));
1472
1473 #if defined(LIBFO_DEBUG) && 0
1474 g_message ("bps_resolve:: borders:: start: %f; end: %f; before: %f; after: %f",
1475 border_start_width,
1476 border_end_width,
1477 border_before_width,
1478 border_after_width);
1479
1480 g_message ("bps_resolve:: padding:: start: %f; end: %f; before: %f; after: %f",
1481 padding_start,
1482 padding_end,
1483 padding_before,
1484 padding_after);
1485 g_message ("bps_resolve:: indent:: start: %f; end: %f; space:: before: %f; after: %f",
1486 start_indent,
1487 end_indent,
1488 space_before,
1489 space_after);
1490 #endif
1491 }
1492
1493 fo_area_area_set_border_after (child_area,
1494 is_last ? border_after_width : 0.0);
1495 fo_area_area_set_border_before (child_area,
1496 is_first ? border_before_width: 0.0);
1497 fo_area_area_set_border_end (child_area,
1498 border_end_width);
1499 fo_area_area_set_border_start (child_area,
1500 border_start_width);
1501 fo_area_area_set_padding_before (child_area,
1502 padding_before);
1503 fo_area_area_set_padding_end (child_area,
1504 padding_end);
1505 fo_area_area_set_padding_after (child_area,
1506 padding_after);
1507 fo_area_area_set_padding_start (child_area,
1508 padding_start);
1509 fo_area_area_set_start_indent (child_area,
1510 start_indent);
1511 fo_area_area_set_end_indent (child_area,
1512 end_indent);
1513 fo_area_area_set_space_before (child_area,
1514 space_before);
1515 fo_area_area_set_space_after (child_area,
1516 space_after);
1517
1518 fo_area_area_set_x (child_area,
1519 parent_next_x + start_indent);
1520 fo_area_area_set_y (child_area,
1521 parent_next_y);
1522
1523 fo_area_area_set_height (child_area,
1524 space_before +
1525 border_before_width +
1526 padding_before +
1527 padding_after +
1528 border_after_width +
1529 space_after);
1530 fo_area_area_set_width (child_area,
1531 start_indent + end_indent);
1532 fo_area_set_next_x (child_area,
1533 start_indent);
1534 fo_area_set_next_y (child_area,
1535 - (space_before + padding_before + border_before_width));
1536 fo_area_set_available_height (child_area,
1537 MAX (child_available_bpdim -
1538 space_before -
1539 space_after -
1540 border_before_width -
1541 border_after_width -
1542 padding_before -
1543 padding_after,
1544 0));
1545 fo_area_set_available_width (child_area,
1546 MAX (child_available_ipdim -
1547 start_indent -
1548 end_indent,
1549 0));
1550 }
1551
1552 /**
1553 * fo_area_break_resolve:
1554 * @parent_area: Parent area of @new_area.
1555 * @new_area: #FoArea for which to resolve breaks.
1556 *
1557 * Resolves the break properties of @new_area, which may result in
1558 * @new_area being split into multiple areas.
1559 *
1560 * Return value: Last area resulting from resolving breaks.
1561 **/
1562 FoArea*
1563 fo_area_break_resolve (FoArea *parent_area,
1564 FoArea *new_area)
1565 {
1566 gint break_before = FO_ENUM_ENUM_AUTO;
1567 gint prev_break_after = FO_ENUM_ENUM_AUTO;
1568 FoFo *fo;
1569 FoProperty *prev_break_after_prop = NULL;
1570 FoProperty *break_before_prop = NULL;
1571 gint page_number;
1572
1573 g_return_val_if_fail (parent_area != NULL, NULL);
1574 g_return_val_if_fail (FO_IS_AREA (parent_area), NULL);
1575 g_return_val_if_fail (new_area != NULL, NULL);
1576 g_return_val_if_fail (FO_IS_AREA (new_area), NULL);
1577
1578 fo = new_area->generated_by;
1579
1580 if (g_object_class_find_property (G_OBJECT_GET_CLASS (fo),
1581 "break-before"))
1582 {
1583 g_object_get (fo,
1584 "break-before", &break_before_prop,
1585 NULL);
1586
1587 break_before =
1588 fo_enum_get_value (fo_property_get_value (break_before_prop));
1589 }
1590
1591 if (!FO_AREA_IS_LEAF (parent_area) &&
1592 g_object_class_find_property (G_OBJECT_GET_CLASS (fo_area_last_child (parent_area)->generated_by),
1593 "break-after"))
1594 {
1595 g_object_get (fo_area_last_child (parent_area)->generated_by,
1596 "break-after", &prev_break_after_prop,
1597 NULL);
1598 prev_break_after =
1599 fo_enum_get_value (fo_property_get_value (prev_break_after_prop));
1600 }
1601
1602 page_number =
1603 fo_area_page_get_page_number (parent_area->page);
1604
1605 #if defined(LIBFO_DEBUG) && 0
1606 g_message ("break_resolve:: page_number: %d; break_before: %d; prev break_after: %d",
1607 page_number, break_before, prev_break_after);
1608 #endif
1609
1610 if (((break_before == FO_ENUM_ENUM_PAGE) &&
1611 (!FO_AREA_IS_LEAF (parent_area))) ||
1612 ((break_before == FO_ENUM_ENUM_ODD_PAGE) &&
1613 ((!FO_AREA_IS_LEAF (parent_area)) ||
1614 (page_number % 2 == 0))) ||
1615 ((break_before == FO_ENUM_ENUM_EVEN_PAGE) &&
1616 ((!FO_AREA_IS_LEAF (parent_area)) ||
1617 (page_number % 2 == 1))) ||
1618 ((prev_break_after_prop != NULL) &&
1619 (((prev_break_after == FO_ENUM_ENUM_PAGE) &&
1620 (!FO_AREA_IS_LEAF (parent_area))) ||
1621 ((prev_break_after == FO_ENUM_ENUM_ODD_PAGE) &&
1622 ((!FO_AREA_IS_LEAF (parent_area)) ||
1623 (page_number % 2 == 1)))||
1624 ((prev_break_after == FO_ENUM_ENUM_EVEN_PAGE) &&
1625 ((!FO_AREA_IS_LEAF (parent_area)) ||
1626 (page_number % 2 == 0))))))
1627 {
1628 FoArea *clone;
1629
1630 g_message ("break_resolve:: make new page: %d", ++page_number);
1631
1632 clone = fo_area_clone (parent_area);
1633 fo_area_dump_path_to_root (clone);
1634
1635 /*
1636 parent_area = fo_add_to_new_page_area (fo_node,
1637 parent_area,
1638 context,
1639 NULL,
1640 debug_level);
1641 page_number =
1642 fo_area_page_get_page_number (parent_area->page);
1643
1644 */
1645 if (((page_number % 2 == 1) &&
1646 ((break_before == FO_ENUM_ENUM_PAGE) ||
1647 ((prev_break_after_prop != NULL) &&
1648 (prev_break_after == FO_ENUM_ENUM_EVEN_PAGE)))) ||
1649 ((page_number % 2 == 0) &&
1650 ((break_before == FO_ENUM_ENUM_ODD_PAGE) ||
1651 ((prev_break_after_prop != NULL) &&
1652 (prev_break_after == FO_ENUM_ENUM_ODD_PAGE)))))
1653 {
1654 g_message ("break_resolve:: make another new page: %d",
1655 ++page_number);
1656 clone = fo_area_clone (clone);
1657 fo_area_dump_path_to_root (clone);
1658 /*
1659 parent_area =
1660 fo_add_to_new_page_area (fo_node, parent_area,
1661 context, NULL, debug_level);
1662 */
1663 }
1664 g_message ("break_resolve:: clone: %p; parent_area: %p; new_area: %p",
1665 clone, parent_area, new_area);
1666 return clone;
1667 }
1668 return parent_area;
1669 }
1670
1671 /**
1672 * fo_area_split_before_height:
1673 * @area: #FoArea to be split
1674 * @height: Maximum block-progression-dimension of @area
1675 *
1676 * Split @area at or before @height.
1677 *
1678 * Return value: The part of @area spit from @area, or NULL if unsplit.
1679 **/
1680 FoArea*
1681 fo_area_split_before_height (FoArea *area,
1682 gdouble height)
1683 {
1684 return FO_AREA_GET_CLASS (area)->split_before_height (area, height);
1685 }
1686
1687 /**
1688 * fo_area_split_before_height_default:
1689 * @area: #FoArea to be split
1690 * @height: Maximum block-progression-dimension of @area
1691 *
1692 * Default function for split_before_height class method.
1693 *
1694 * Class method should be overridden by subclasses of #FoArea.
1695 *
1696 * Return value: NULL, indicating that @area was not split.
1697 **/
1698 FoArea*
1699 fo_area_split_before_height_default (FoArea *area,
1700 gdouble height G_GNUC_UNUSED)
1701 {
1702 g_warning ("%s does not have a 'split_before_height' function.",
1703 g_type_name (G_TYPE_FROM_INSTANCE (area)));
1704 return NULL;
1705 }
1706
1707 /**
1708 * fo_area_split_before_height_check:
1709 * @area: #FoArea to be split
1710 * @height: Maximum block-progression-dimension of @area
1711 *
1712 * Check whether @area can split at or before @height.
1713 *
1714 * Return value: TRUE if can split, otherwise FALSE.
1715 **/
1716 gboolean
1717 fo_area_split_before_height_check (FoArea *area, gdouble height)
1718 {
1719 return FO_AREA_GET_CLASS (area)->split_before_height_check (area,
1720 height);
1721 }
1722
1723 /**
1724 * fo_area_split_before_height_check_default:
1725 * @area: #FoArea to be split
1726 * @height: Maximum block-progression-dimension of @area
1727 *
1728 * Default function for split_before_height_check class method.
1729 *
1730 * Class method should be overridden by subclasses of #FoArea.
1731 *
1732 * Return value: %FALSE, indicating that @area cannot split
1733 **/
1734 gboolean
1735 fo_area_split_before_height_check_default (FoArea *area,
1736 gdouble height G_GNUC_UNUSED)
1737 {
1738 g_warning ("%s does not have a 'split_before_height_check' function.",
1739 g_type_name (G_TYPE_FROM_INSTANCE (area)));
1740 return FALSE;
1741 }
1742
1743 /**
1744 * fo_area_split_after_height:
1745 * @area: #FoArea to be split
1746 * @height: Maximum block-progression-dimension of @area
1747 *
1748 * Split @area at or after @height.
1749 *
1750 * Return value: The part of @area spit from @area, or NULL if unsplit.
1751 **/
1752 FoArea*
1753 fo_area_split_after_height (FoArea *area, gdouble height)
1754 {
1755 return FO_AREA_GET_CLASS (area)->split_after_height (area, height);
1756 }
1757
1758 /**
1759 * fo_area_split_after_height_default:
1760 * @area: #FoArea to be split
1761 * @height: Maximum block-progression-dimension of @area
1762 *
1763 * Default function for split_after_height class method.
1764 *
1765 * Class method should be overridden by subclasses of #FoArea.
1766 *
1767 * Return value: NULL, indicating that @area was not split.
1768 **/
1769 FoArea*
1770 fo_area_split_after_height_default (FoArea *area,
1771 gdouble height G_GNUC_UNUSED)
1772 {
1773 g_warning ("%s does not have a 'split_after_height' function.",
1774 g_type_name (G_TYPE_FROM_INSTANCE (area)));
1775 return NULL;
1776 }
1777
1778 /**
1779 * fo_area_split_after_height_check:
1780 * @area: #FoArea to be split
1781 * @height: Maximum block-progression-dimension of @area
1782 *
1783 * Check whether @area can split at or after @height.
1784 *
1785 * Return value: TRUE if can split, otherwise FALSE.
1786 **/
1787 gboolean
1788 fo_area_split_after_height_check (FoArea *area, gdouble height)
1789 {
1790 return FO_AREA_GET_CLASS (area)->split_after_height_check (area,
1791 height);
1792 }
1793
1794 /**
1795 * fo_area_split_after_height_check_default:
1796 * @area: #FoArea to be split
1797 * @height: Maximum block-progression-dimension of @area
1798 *
1799 * Default function for split_after_height_check class method.
1800 *
1801 * Class method should be overridden by subclasses of #FoArea.
1802 *
1803 * Return value: %FALSE, indicating that @area cannot split
1804 **/
1805 gboolean
1806 fo_area_split_after_height_check_default (FoArea *area,
1807 gdouble height G_GNUC_UNUSED)
1808 {
1809 g_warning ("%s does not have a 'split_after_height_check' function.",
1810 g_type_name (G_TYPE_FROM_INSTANCE (area)));
1811 return FALSE;
1812 }
1813
1814 /**
1815 * fo_area_default_resolve_text_align:
1816 * @area: #FoArea for which to resolve text alignment.
1817 *
1818 * Resolves the text alignment value for @area and its descendants.
1819 **/
1820 static void
1821 fo_area_default_resolve_text_align (FoArea *area)
1822 {
1823 FoArea *child_area;
1824
1825 child_area = fo_area_first_child (area);
1826
1827 while (child_area)
1828 {
1829 fo_area_resolve_text_align (child_area);
1830 child_area = fo_area_next_sibling (child_area);
1831 }
1832 }
1833
1834 /**
1835 * fo_area_resolve_text_align:
1836 * @area: #FoArea for which to resolve text alignment.
1837 *
1838 * Resolves the text alignment value for @area and its descendants.
1839 **/
1840 void
1841 fo_area_resolve_text_align (FoArea *area)
1842 {
1843 if (area != NULL)
1844 {
1845 FO_AREA_GET_CLASS (area)->resolve_text_align (area);
1846 }
1847 }
1848
1849 /**
1850 * fo_area_size_request:
1851 * @child: Child area
1852 *
1853 * Checks that the parent area of @child has sufficient space for
1854 * @child. If not enough space, requests that the parent has
1855 * sufficient space allocated for it, then adjusts @child and its
1856 * siblings as necessary to fit into the resized parent area.
1857 *
1858 * You should call #fo_area_size_request() immediately after adding
1859 * an area to the area tree or making a change to the area's height.
1860 *
1861 * The child area's requested height is taken from the area's height
1862 * property value. Its requested width is taken from its width
1863 * property value.
1864 *
1865 * The height allocated to the area is set in the area's
1866 * available_height property value. Its width allocation is set in
1867 * its available_width property value.
1868 *
1869 * Immediately after calling this function, the child area should set
1870 * its height and width according to the available_height and
1871 * available_width property values. How the child area resolves any
1872 * difference between the available height and width and the height
1873 * and width that it needs is up to the child area to work out.
1874 *
1875 * The child area's x and y property values may also have been
1876 * adjusted, but a child area doesn't set its own x and y property
1877 * values anyway.
1878 *
1879 * The area that is returned may be a different area object than the
1880 * child area that is passed as the argument to this function. For
1881 * example, the parent area may not have been large enough to contain
1882 * the child area at its requested height, and the child area, the
1883 * parent area, and all ancestor areas up to an FoAreaPage may have
1884 * been split (possibly more than once) and the overflow placed on one
1885 * or more new pages.
1886 *
1887 * Return value: Pointer to the last area generated from @child after
1888 * any reallocation and resizing
1889 **/
1890 FoArea*
1891 fo_area_size_request (FoArea *child)
1892 {
1893 FoArea *parent = fo_area_parent (child);
1894
1895 if (parent == NULL)
1896 {
1897 g_error ("area_size_request:: parent is NULL");
1898 return NULL;
1899 }
1900 else if (!FO_IS_AREA (parent))
1901 {
1902 g_error ("area_size_request:: parent is not an area: %s",
1903 fo_object_debug_sprintf (parent));
1904 return NULL;
1905 }
1906 else
1907 {
1908 return FO_AREA_GET_CLASS (parent)->size_request (child);
1909 }
1910 }
1911
1912 /**
1913 * fo_area_accumulate_height:
1914 * @area: #FoArea whose height to add.
1915 * @data: Total to which to add height of @area.
1916 *
1917 * For use with #fo_area_children_foreach.
1918 **/
1919 void
1920 fo_area_accumulate_height (FoArea *area,
1921 gpointer data)
1922 {
1923 gdouble *total = (gdouble *) data;
1924 #if defined(LIBFO_DEBUG) && 0
1925 g_message ("add_height:: height: %f; area: %s; generated by: %s",
1926 fo_area_area_get_height (area),
1927 fo_object_debug_sprintf (area),
1928 fo_object_debug_sprintf (area->generated_by));
1929 #endif
1930 *total += fo_area_area_get_height (area);
1931
1932 /*if (fo_area_prev_sibling (area))*/
1933 *total += fo_area_area_get_space_before (area);
1934
1935 /*if (fo_area_next_sibling (area))*/
1936 *total += fo_area_area_get_space_after (area);
1937 }
1938
1939 /**
1940 * fo_area_size_adjust:
1941 * @area: #FoArea node to be placed within parent
1942 * @data: Not used
1943 *
1944 * Place @area within its parent and adjust the parent's next-x and
1945 * next-y properties accordingly.
1946 **/
1947 void
1948 fo_area_size_adjust (FoArea *area,
1949 gpointer data G_GNUC_UNUSED)
1950 {
1951 FoArea *parent = fo_area_parent (area);
1952
1953 fo_area_area_set_x (area,
1954 fo_area_get_next_x (parent) +
1955 fo_area_area_get_start_indent (area));
1956 fo_area_area_set_y (area,
1957 fo_area_get_next_y (parent) -
1958 fo_area_area_get_space_before (area));
1959 /* FIXME: 0 or border+padding? */
1960 fo_area_set_next_x (parent, 0);
1961 fo_area_set_next_y (parent,
1962 fo_area_get_next_y (parent) -
1963 fo_area_area_get_height (area) -
1964 fo_area_area_get_space_before (area) -
1965 fo_area_area_get_space_after (area));
1966 fo_area_set_available_height (area,
1967 fo_area_area_get_height (area));
1968 /* FIXME: Shouldn't child do its own accounting for indents? */
1969 fo_area_set_available_width (area,
1970 MAX (fo_area_get_child_available_ipdim (parent) -
1971 fo_area_area_get_start_indent (area) -
1972 fo_area_area_get_end_indent (area),
1973 0));
1974 }
1975
1976 /**
1977 * fo_area_set_or_split:
1978 * @area: #FoArea to be either placed within the parent area or split
1979 * into two areas
1980 * @data: Not used
1981 *
1982 *
1983 **/
1984 void
1985 fo_area_set_or_split (FoArea *area,
1986 gpointer data G_GNUC_UNUSED)
1987 {
1988 FoArea *parent = fo_area_parent (area);
1989 gdouble child_available_bpdim = fo_area_get_child_available_bpdim (parent);
1990
1991 if ((child_available_bpdim -
1992 (fo_area_get_next_y (parent) -
1993 fo_area_area_get_height (area))) >= 0)
1994 {
1995 fo_area_area_set_x (area,
1996 fo_area_get_next_x (parent) +
1997 fo_area_area_get_start_indent (area));
1998 fo_area_area_set_y (area,
1999 fo_area_get_next_y (parent));
2000 /* FIXME: 0 or border+padding? */
2001 fo_area_set_next_x (parent, 0);
2002 fo_area_set_next_y (parent,
2003 fo_area_get_next_y (parent) -
2004 fo_area_area_get_height (area));
2005 fo_area_set_available_height (area,
2006 fo_area_area_get_height (area));
2007 fo_area_set_available_width (area,
2008 fo_area_get_child_available_ipdim (parent));
2009 }
2010 else
2011 {
2012 #if defined(LIBFO_DEBUG) && 1
2013 g_message ("set_or_split:: splitting:: child: %s; generated by: %s",
2014 fo_object_debug_sprintf (area) ,
2015 fo_object_debug_sprintf (area->generated_by));
2016 #endif
2017 area = fo_area_split_before_height (area,
2018 child_available_bpdim -
2019 fo_area_area_get_height (parent));
2020 parent = fo_area_parent (area);
2021 child_available_bpdim = fo_area_get_child_available_bpdim (parent);
2022 }
2023 }
2024
2025 /**
2026 * _size_request:
2027 * @child: Child area
2028 *
2029 * Check that the parent area of @child has sufficient space for
2030 * @child. If not enough space, request that the parent has
2031 * sufficient space allocated for it, then adjust @child and its
2032 * siblings as necessary to fit into the resized parent area.
2033 *
2034 * Return value: Pointer to the last area generated from @child after
2035 * any reallocation and resizing
2036 **/
2037 static FoArea *
2038 _size_request (FoArea *child)
2039 {
2040 FoArea *parent;
2041 FoArea *child_original_next_part;
2042 FoArea *return_child;
2043 gdouble total_child_height = 0;
2044 gdouble child_available_ipdim;
2045 gdouble child_available_bpdim;
2046 gdouble child_height;
2047 gdouble child_space_before, child_space_after;
2048
2049 g_return_val_if_fail (child != NULL, NULL);
2050 g_return_val_if_fail (FO_IS_AREA_AREA (child), NULL);
2051 g_return_val_if_fail (!FO_AREA_IS_ROOT (child), NULL);
2052 g_return_val_if_fail (FO_IS_AREA_AREA (fo_area_parent (child)), NULL);
2053
2054 child_original_next_part = child->next_part;
2055
2056 child_height = fo_area_area_get_height (child);
2057 child_space_before = fo_area_area_get_space_before (child);
2058 child_space_after = fo_area_area_get_space_after (child);
2059
2060 parent = fo_area_parent (child);
2061 child_available_bpdim = fo_area_get_child_available_bpdim (parent);
2062
2063 #if defined(LIBFO_DEBUG) && 1
2064 g_message ("size_request_default (%p):: parent: %s; generated by: %s; available_height: %g",
2065 child,
2066 fo_object_debug_sprintf (parent),
2067 fo_object_debug_sprintf (parent->generated_by),
2068 child_available_bpdim);
2069 g_message ("size_request_default (%p):: child: %s; generated by: %s; height: %g; space_before: %g; space_after: %g",
2070 child,
2071 fo_object_debug_sprintf (child),
2072 fo_object_debug_sprintf (child->generated_by),
2073 child_height,
2074 child_space_before,
2075 child_space_after);
2076 #endif
2077
2078 fo_area_children_foreach (parent,
2079 G_TRAVERSE_ALL,
2080 &fo_area_accumulate_height,
2081 &total_child_height);
2082 #if defined(LIBFO_DEBUG) && 1
2083 g_message ("size_request_default (%p):: child total: %g",
2084 child,
2085 total_child_height);
2086 #endif
2087
2088 fo_area_area_set_height (parent,
2089 total_child_height +
2090 fo_area_area_get_border_before (parent) +
2091 fo_area_area_get_padding_before (parent) +
2092 fo_area_area_get_padding_after (parent) +
2093 fo_area_area_get_border_after (parent));
2094
2095 /* Don't bother doing a size_request if still fit within
2096 available height */
2097 if (child_available_bpdim < fo_area_area_get_height (parent))
2098 {
2099 parent = fo_area_size_request (parent);
2100 child_available_ipdim =
2101 MAX (fo_area_get_available_width (parent) -
2102 fo_area_area_get_border_start (parent) -
2103 fo_area_area_get_padding_start (parent) -
2104 fo_area_area_get_padding_end (parent) -
2105 fo_area_area_get_border_end (parent),
2106 0);
2107 fo_area_set_child_available_ipdim (parent, child_available_ipdim);
2108 child_available_bpdim =
2109 MAX (fo_area_get_available_height (parent) -
2110 fo_area_area_get_border_before (parent) -
2111 fo_area_area_get_padding_before (parent) -
2112 fo_area_area_get_padding_after (parent) -
2113 fo_area_area_get_border_after (parent),
2114 0);
2115 fo_area_set_child_available_bpdim (parent, child_available_bpdim);
2116 #if defined(LIBFO_DEBUG) && 1
2117 g_message ("size_request_default:: child: %s; new parent: %s; generated by: %s; available_height: %g; child_available_ipdim: %g; child_available_bpdim: %g",
2118 fo_object_debug_sprintf (child),
2119 fo_object_debug_sprintf (parent),
2120 fo_object_debug_sprintf (parent->generated_by),
2121 fo_area_get_available_height (parent),
2122 child_available_ipdim,
2123 child_available_bpdim);
2124 #endif
2125 }
2126
2127 total_child_height = 0;
2128 fo_area_children_foreach (parent,
2129 G_TRAVERSE_ALL,
2130 &fo_area_accumulate_height,
2131 &total_child_height);
2132 #if defined(LIBFO_DEBUG) && 1
2133 g_message ("size_request_default (%p):: new child total: %g",
2134 child,
2135 total_child_height);
2136 #endif
2137 fo_area_set_next_x (parent,
2138 fo_area_area_get_border_start (parent) +
2139 fo_area_area_get_padding_start (parent));
2140 fo_area_set_next_y (parent,
2141 - (fo_area_area_get_border_before (parent) +
2142 fo_area_area_get_padding_before (parent)));
2143
2144 if (total_child_height <= child_available_bpdim)
2145 {
2146 fo_area_children_foreach (parent,
2147 G_TRAVERSE_ALL,
2148 &fo_area_size_adjust,
2149 NULL);
2150
2151 #if defined(LIBFO_DEBUG) && 1
2152 g_message ("size_request_default (%p):: return:: parent->last: %s; generated by: %s",
2153 child,
2154 fo_object_debug_sprintf (fo_area_last_child (parent)),
2155 fo_object_debug_sprintf (fo_area_last_child (parent)->generated_by));
2156 #endif
2157 return_child = child;
2158
2159 while ((return_child->next_part != NULL) &&
2160 (return_child->next_part != child_original_next_part))
2161 {
2162 return_child = return_child->next_part;
2163 }
2164
2165 return return_child;
2166 /*
2167 return fo_area_last_child (parent);
2168 */
2169 }
2170 else
2171 {
2172 fo_area_children_foreach (parent,
2173 G_TRAVERSE_ALL,
2174 &fo_area_set_or_split,
2175 NULL);
2176 #if defined(LIBFO_DEBUG) && 1
2177 g_message ("size_request_default (%p):: total > available:: return:: parent->last: %s; generated by: %s",
2178 child,
2179 fo_object_debug_sprintf (fo_area_last_child (parent)),
2180 fo_object_debug_sprintf (fo_area_last_child (parent)->generated_by));
2181 #endif
2182 return_child = child;
2183
2184 while ((return_child->next_part != NULL) &&
2185 (return_child->next_part != child_original_next_part))
2186 {
2187 return_child = return_child->next_part;
2188 }
2189
2190 return return_child;
2191 /*
2192 return fo_area_last_child (parent);
2193 */
2194 }
2195 }
2196
2197 /**
2198 * fo_area_update_child_after_insert:
2199 * @parent:
2200 * @child:
2201 *
2202 *
2203 **/
2204 static void
2205 fo_area_update_child_after_insert (FoArea *parent,
2206 FoArea *child)
2207 {
2208 g_return_if_fail (FO_IS_AREA (parent));
2209 g_return_if_fail (FO_IS_AREA (child));
2210
2211 if (!FO_IS_AREA_PAGE (child))
2212 {
2213 child->page = parent->page;
2214 }
2215
2216 if (!FO_IS_AREA_REFERENCE (child))
2217 {
2218 child->reference = parent->reference;
2219 }
2220 }
2221
2222 /**
2223 * _node_insert:
2224 * @parent:
2225 * @position:
2226 * @area:
2227 *
2228 *
2229 *
2230 * Return value:
2231 **/
2232 static FoNode *
2233 _node_insert (FoNode *parent,
2234 gint position,
2235 FoNode *area)
2236 {
2237 return ((FoNode *) fo_area_insert (((FoArea *) parent),
2238 position,
2239 ((FoArea *) area)));
2240 }
2241
2242 /**
2243 * fo_area_insert:
2244 * @parent:
2245 * @position:
2246 * @area:
2247 *
2248 *
2249 *
2250 * Return value:
2251 **/
2252 FoArea*
2253 fo_area_insert (FoArea *parent,
2254 gint position,
2255 FoArea *area)
2256 {
2257 FoArea *new_area;
2258
2259 g_return_val_if_fail (FO_IS_AREA (parent), area);
2260 g_return_val_if_fail (FO_IS_AREA (area), area);
2261
2262 new_area =
2263 FO_AREA (FO_NODE_CLASS (parent_class)->insert (FO_NODE (parent),
2264 position,
2265 FO_NODE (area)));
2266
2267 fo_area_update_child_after_insert (parent, new_area);
2268
2269 return new_area;
2270 }
2271
2272 /**
2273 * _node_insert_before:
2274 * @parent:
2275 * @sibling:
2276 * @area:
2277 *
2278 *
2279 *
2280 * Return value:
2281 **/
2282 static FoNode *
2283 _node_insert_before (FoNode *parent,
2284 FoNode *sibling,
2285 FoNode *area)
2286 {
2287 return ((FoNode *) fo_area_insert_before (((FoArea *) parent),
2288 ((FoArea *) sibling),
2289 ((FoArea *) area)));
2290 }
2291
2292 /**
2293 * fo_area_insert_before:
2294 * @parent:
2295 * @sibling:
2296 * @area:
2297 *
2298 *
2299 *
2300 * Return value:
2301 **/
2302 FoArea*
2303 fo_area_insert_before (FoArea *parent,
2304 FoArea *sibling,
2305 FoArea *area)
2306 {
2307 FoArea *new_area;
2308
2309 g_return_val_if_fail (FO_IS_AREA (parent), area);
2310 g_return_val_if_fail (FO_IS_AREA (sibling), area);
2311 g_return_val_if_fail (FO_IS_AREA (area), area);
2312
2313 new_area =
2314 FO_AREA (FO_NODE_CLASS (parent_class)->insert_before (FO_NODE (parent),
2315 FO_NODE (sibling),
2316 FO_NODE (area)));
2317
2318 fo_area_update_child_after_insert (parent, new_area);
2319
2320 return new_area;
2321 }
2322
2323 /**
2324 * _node_insert_after:
2325 * @parent:
2326 * @sibling:
2327 * @area:
2328 *
2329 *
2330 *
2331 * Return value:
2332 **/
2333 static FoNode *
2334 _node_insert_after (FoNode *parent,
2335 FoNode *sibling,
2336 FoNode *area)
2337 {
2338 return ((FoNode *) fo_area_insert_after (((FoArea *) parent),
2339 ((FoArea *) sibling),
2340 ((FoArea *) area)));
2341 }
2342
2343 /**
2344 * fo_area_insert_after:
2345 * @parent:
2346 * @sibling:
2347 * @area:
2348 *
2349 *
2350 *
2351 * Return value:
2352 **/
2353 FoArea*
2354 fo_area_insert_after (FoArea *parent,
2355 FoArea *sibling,
2356 FoArea *area)
2357 {
2358 FoArea *new_area;
2359
2360 g_return_val_if_fail (FO_IS_AREA (parent), area);
2361 g_return_val_if_fail (FO_IS_AREA (sibling), area);
2362 g_return_val_if_fail (FO_IS_AREA (area), area);
2363
2364 new_area =
2365 FO_AREA (FO_NODE_CLASS (parent_class)->insert_after (FO_NODE (parent),
2366 FO_NODE (sibling),
2367 FO_NODE (area)));
2368
2369 fo_area_update_child_after_insert (parent, new_area);
2370
2371 return new_area;
2372 }
2373 /**
2374 * _node_prepend:
2375 * @parent: the #FoNode to place the new #FoNode under.
2376 * @area: the #FoNode to insert.
2377 *
2378 * Inserts a #FoNode as the first child of the given parent.
2379 *
2380 * Return value: the inserted #FoNode.
2381 **/
2382 static FoNode *
2383 _node_prepend (FoNode *parent,
2384 FoNode *area)
2385 {
2386 return ((FoNode *) fo_area_prepend (((FoArea *) parent),
2387 ((FoArea *) area)));
2388 }
2389
2390 /**
2391 * fo_area_prepend:
2392 * @parent: the #FoArea to place the new #FoArea under.
2393 * @area: the #FoArea to insert.
2394 *
2395 * Inserts a #FoArea as the first child of the given parent and
2396 * updates the inserted #FoArea.
2397 *
2398 * Return value: the inserted #FoArea.
2399 **/
2400 FoArea*
2401 fo_area_prepend (FoArea *parent,
2402 FoArea *area)
2403 {
2404 FoArea *new_area;
2405
2406 g_return_val_if_fail (FO_IS_AREA (parent), area);
2407 g_return_val_if_fail (FO_IS_AREA (area), area);
2408
2409 new_area =
2410 FO_AREA (FO_NODE_CLASS (parent_class)->prepend (FO_NODE (parent),
2411 FO_NODE (area)));
2412
2413 fo_area_update_child_after_insert (parent, new_area);
2414
2415 return new_area;
2416 }
2417
2418 /**
2419 * _node_append:
2420 * @parent: the #FoNode to place the new #FoNode under.
2421 * @area: the #FoNode to insert.
2422 *
2423 * Inserts a #FoNode as the last child of the given parent.
2424 *
2425 * Return value: the inserted #FoNode.
2426 **/
2427 static FoNode *
2428 _node_append (FoNode *parent,
2429 FoNode *area)
2430 {
2431 return ((FoNode *) fo_area_append (((FoArea *) parent),
2432 ((FoArea *) area)));
2433 }
2434
2435 /**
2436 * fo_area_append:
2437 * @parent: the #FoArea to place the new #FoArea under.
2438 * @area: the #FoArea to insert.
2439 *
2440 * Inserts a #FoArea as the last child of the given parent and updates
2441 * the inserted #FoArea.
2442 *
2443 * Return value: the inserted #FoArea.
2444 **/
2445 FoArea*
2446 fo_area_append (FoArea *parent,
2447 FoArea *area)
2448 {
2449 FoArea *new_area;
2450
2451 g_return_val_if_fail (FO_IS_AREA (parent), area);
2452 g_return_val_if_fail (FO_IS_AREA (area), area);
2453
2454 new_area =
2455 FO_AREA (FO_NODE_CLASS (parent_class)->append (FO_NODE (parent),
2456 FO_NODE (area)));
2457
2458 fo_area_update_child_after_insert (parent, new_area);
2459
2460 return new_area;
2461 }
2462
2463 /**
2464 * fo_area_n_areas:
2465 * @root: a #FoArea.
2466 * @flags: which types of children are to be counted, one of
2467 * %G_TRAVERSE_ALL, %G_TRAVERSE_LEAFS and
2468 * %G_TRAVERSE_NON_LEAFS.
2469 *
2470 * Gets the number of nodes in a tree.
2471 *
2472 * Return value: the number of nodes in the tree.
2473 **/
2474 guint
2475 fo_area_n_areas (FoArea *root,
2476 GTraverseFlags flags)
2477 {
2478 return fo_node_n_nodes (FO_NODE (root),
2479 flags);
2480 }
2481
2482 /**
2483 * fo_area_get_root:
2484 * @area:
2485 *
2486 *
2487 *
2488 * Return value:
2489 **/
2490 FoArea*
2491 fo_area_get_root (FoArea *area)
2492 {
2493 return FO_AREA (fo_node_get_root (FO_NODE (area)));
2494 }
2495
2496 /**
2497 * fo_area_is_ancestor:
2498 * @area:
2499 * @descendant:
2500 *
2501 *
2502 *
2503 * Return value:
2504 **/
2505 gboolean
2506 fo_area_is_ancestor (FoArea *area,
2507 FoArea *descendant)
2508 {
2509 return fo_node_is_ancestor (FO_NODE (area),
2510 FO_NODE (descendant));
2511 }
2512
2513 /**
2514 * fo_area_depth:
2515 * @area: a #FoArea.
2516 *
2517 * Gets the depth of a #FoArea.
2518 *
2519 * If @area is %NULL the depth is 0. The root node has a depth of 1. For
2520 * the children of the root node the depth is 2. And so on.
2521 *
2522 * Return value: the depth of the #FoArea.
2523 **/
2524 guint
2525 fo_area_depth (FoArea *area)
2526 {
2527 return fo_node_depth (((FoNode *) area));
2528 }
2529
2530 typedef struct _FoAreaFuncData
2531 {
2532 FoAreaForeachFunc func;
2533 gpointer area_func_data;
2534 } FoAreaFuncData;
2535
2536 #if 0
2537 static void
2538 fo_area_g_node_children_foreach_func (GNode *node,
2539 gpointer data)
2540 {
2541 const FoAreaFuncData *fo_area_func_data = (FoAreaFuncData *) data;
2542
2543 fo_area_func_data->func (node->data,
2544 fo_area_func_data->area_func_data);
2545 }
2546 #endif
2547
2548 /**
2549 * fo_area_children_foreach:
2550 * @area: a #FoArea.
2551 * @flags: which types of children are to be visited, one of
2552 * %G_TRAVERSE_ALL, %G_TRAVERSE_LEAFS and
2553 * %G_TRAVERSE_NON_LEAFS.
2554 * @func: the function to call for each visited node.
2555 * @data: user data to pass to the function.
2556 *
2557 * Calls a function for each of the children of a #FoArea. Note that
2558 * it doesn't descend beneath the child nodes.
2559 **/
2560 void
2561 fo_area_children_foreach (FoArea *area,
2562 GTraverseFlags flags,
2563 FoAreaForeachFunc func,
2564 gpointer data)
2565 {
2566 fo_node_children_foreach (((FoNode *) area),
2567 flags,
2568 (FoNodeForeachFunc) func,
2569 data);
2570 }
2571
2572 /**
2573 * fo_area_reverse_children:
2574 * @area: a #FoArea.
2575 *
2576 * Reverses the order of the children of a #FoArea. (It doesn't change
2577 * the order of the grandchildren.)
2578 **/
2579 void
2580 fo_area_reverse_children (FoArea *area)
2581 {
2582 fo_node_reverse_children (((FoNode *) area));
2583 }
2584
2585 /**
2586 * fo_area_n_children:
2587 * @area: a #FoArea.
2588 *
2589 * Gets the number of children of a #FoArea.
2590 *
2591 * Return value: the number of children of @area.
2592 **/
2593 guint
2594 fo_area_n_children (FoArea *area)
2595 {
2596 return fo_node_n_children (((FoNode *) area));
2597 }
2598
2599 /**
2600 * fo_area_nth_child:
2601 * @area: a #FoArea.
2602 * @n: the index of the desired child.
2603 *
2604 * Gets a child of a #FoArea, using the given index. The first child
2605 * is at index 0. If the index is too big, %NULL is returned.
2606 *
2607 * Return value: the child of @area at index @n.
2608 **/
2609 FoArea*
2610 fo_area_nth_child (FoArea *area,
2611 guint n)
2612 {
2613 return ((FoArea *) fo_node_nth_child (((FoNode *) area), n));
2614 }
2615
2616 /**
2617 * fo_area_last_child:
2618 * @area: a #FoArea (nust not be %NULL).
2619 *
2620 * Gets the last child of a #FoArea.
2621 *
2622 * Return value: the last child of @area, or %NULL if @area has no
2623 * children.
2624 **/
2625 FoArea*
2626 fo_area_last_child (FoArea *area)
2627 {
2628 return ((FoArea *) fo_node_last_child (((FoNode *) area)));
2629 }
2630
2631 /**
2632 * fo_area_child_position:
2633 * @area: a #FoArea.
2634 * @child: a child of @area.
2635 *
2636 * Gets the position of a #FoArea with respect to its siblings. @child
2637 * must be a child of @area. The first child is numbered 0, the second
2638 * 1, and so on.
2639 *
2640 * Return value: the position of @child with respect to its siblings.
2641 **/
2642 guint
2643 fo_area_child_position (FoArea *area,
2644 FoArea *child)
2645 {
2646 return fo_node_child_position (((FoNode *) area),
2647 ((FoNode *) child));
2648 }
2649
2650 /**
2651 * fo_area_first_sibling:
2652 * @area: a #FoArea.
2653 *
2654 * Gets the first sibling of a #FoArea. This could possibly be the
2655 * node itself.
2656 *
2657 * Return value: the first sibling of @area.
2658 **/
2659 FoArea*
2660 fo_area_first_sibling (FoArea *area)
2661 {
2662 return ((FoArea *) fo_node_first_sibling ((FoNode *) area));
2663 }
2664
2665 /**
2666 * fo_area_last_sibling:
2667 * @area: a #FoArea.
2668 *
2669 * Gets the last sibling of a #FoArea. This could possibly be the node
2670 * itself.
2671 *
2672 * Return value: the last sibling of @area.
2673 **/
2674 FoArea*
2675 fo_area_last_sibling (FoArea *area)
2676 {
2677 return ((FoArea *) fo_node_last_sibling (((FoNode *) area)));
2678 }
2679
2680 /**
2681 * fo_area_prev_sibling:
2682 * @area: a #FoArea.
2683 *
2684 * Gets the previous sibling of a #FoArea.
2685 *
2686 * Return value: the previous sibling of @area, or %NULL if @area is
2687 * %NULL.
2688 **/
2689 FoArea*
2690 fo_area_prev_sibling (FoArea *area)
2691 {
2692 return ((FoArea *) fo_node_prev_sibling (((FoNode *) area)));
2693 }
2694
2695 /**
2696 * fo_area_next_sibling:
2697 * @area: a #FoArea.
2698 *
2699 * Gets the next sibling of a #FoArea.
2700 *
2701 * Return value: the next sibling of @area, or %NULL if @area is %NULL.
2702 **/
2703 FoArea*
2704 fo_area_next_sibling (FoArea *area)
2705 {
2706 return ((FoArea *) fo_node_next_sibling (((FoNode *) area)));
2707 }
2708
2709 /**
2710 * fo_area_first_child:
2711 * @area: A #FoArea.
2712 *
2713 * Gets the first child of a #FoArea.
2714 *
2715 * Return value: the first child of @area, or %NULL if @area is %NULL or
2716 * has no children.
2717 **/
2718 FoArea*
2719 fo_area_first_child (FoArea *area)
2720 {
2721 return ((FoArea *) fo_node_first_child (((FoNode *) area)));
2722 }
2723
2724 /**
2725 * fo_area_parent:
2726 * @area: a #FoArea.
2727 *
2728 * Gets the parent of a #FoArea.
2729 *
2730 * Return value: the parent of @area, or %NULL if @area is the root of
2731 * the tree.
2732 **/
2733 FoArea*
2734 fo_area_parent (FoArea *area)
2735 {
2736 return ((FoArea *) fo_node_parent (((FoNode *) area)));
2737 }
2738
2739 /**
2740 * fo_area_unlink:
2741 * @area: the #FoArea to unlink, which becomes the root of a new tree.
2742 *
2743 * Unlinks an #FoArea from an #FoArea tree, resulting in two separate
2744 * trees.
2745 **/
2746 void
2747 fo_area_unlink (FoArea *area)
2748 {
2749 fo_node_unlink (((FoNode *) area));
2750 }
2751
2752 /**
2753 * fo_area_max_height:
2754 * @root: Root node of a #FoArea tree.
2755 *
2756 * Gets the maximum height of all branches beneath a #FoArea. This is
2757 * the maximum distance from the #FoArea to all leaf nodes.
2758 *
2759 * If @root is %NULL, 0 is returned. If @root has no children, 1 is
2760 * returned. If @root has children, 2 is returned. And so on.
2761 *
2762 * Return value: the maximum height of the tree beneath @root.
2763 **/
2764 guint
2765 fo_area_max_height (FoArea *root)
2766 {
2767 return fo_node_max_height (((FoNode *) root));
2768 }
2769
2770 typedef struct _FoAreaTraverseFuncData
2771 {
2772 FoAreaTraverseFunc func;
2773 gpointer area_func_data;
2774 } FoAreaTraverseFuncData;
2775
2776 /**
2777 * fo_area_traverse:
2778 * @root:
2779 * @order:
2780 * @flags:
2781 * @max_depth:
2782 * @func:
2783 * @data:
2784 *
2785 *
2786 **/
2787 void
2788 fo_area_traverse (FoArea *root,
2789 GTraverseType order,
2790 GTraverseFlags flags,
2791 gint max_depth,
2792 FoAreaTraverseFunc func,
2793 gpointer data)
2794 {
2795 fo_node_traverse (((FoNode *) root),
2796 order,
2797 flags,
2798 max_depth,
2799 (FoNodeTraverseFunc) func,
2800 data);
2801 }
2802
2803 /**
2804 * _node_unlink_with_next_siblings:
2805 * @area: First #FoNode to unlink.
2806 *
2807 * Unlinks @area and its following siblings.
2808 *
2809 * #FoArea implementation of fo_node_unlink_with_next_siblings().
2810 **/
2811 static void
2812 _node_unlink_with_next_siblings (FoNode *area)
2813 {
2814 fo_area_unlink_with_next_siblings (((FoArea *) area));
2815 }
2816
2817 /**
2818 * fo_area_unlink_with_next_siblings:
2819 * @area: First #FoArea to unlink.
2820 *
2821 * Unlinks @area and its following siblings.
2822 **/
2823 void
2824 fo_area_unlink_with_next_siblings (FoArea *area)
2825 {
2826 FO_NODE_CLASS (parent_class)->unlink_with_next_siblings (((FoNode *) area));
2827 }
2828
2829 /**
2830 * _node_insert_with_next_siblings:
2831 * @parent: #FoNode to be parent of @area and its siblings.
2832 * @position: Offset at which to insert @area and its siblings.
2833 * @area: #FoNode, possibly with following siblings.
2834 *
2835 * Implements fo_node_insert_with_next_siblings for #FoArea.
2836 *
2837 * Return value: @parent with @area and siblings inserted.
2838 **/
2839 static FoNode *
2840 _node_insert_with_next_siblings (FoNode *parent,
2841 gint position,
2842 FoNode *area)
2843 {
2844 return ((FoNode *) fo_area_insert_with_next_siblings (((FoArea *) parent),
2845 position,
2846 ((FoArea *) area)));
2847 }
2848
2849 /**
2850 * fo_area_insert_with_next_siblings:
2851 * @parent: #FoArea to be parent of @area and its siblings.
2852 * @position: Offset at which to insert @area and its siblings.
2853 * @area: #FoArea, possibly with following siblings.
2854 *
2855 * Implements fo_node_insert_with_next_siblings for #FoArea.
2856 *
2857 * Return value: @parent with @area and siblings inserted.
2858 **/
2859 FoArea *
2860 fo_area_insert_with_next_siblings (FoArea *parent,
2861 gint position,
2862 FoArea *area)
2863 {
2864 return FO_AREA (FO_NODE_CLASS (parent_class)->insert_with_next_siblings (FO_NODE (parent),
2865 position,
2866 FO_NODE (area)));
2867 }
2868
2869 /**
2870 * fo_area_release:
2871 * @fo_node: #FoNode for which to release subtree
2872 * @data: Context in which to resolve the properties.
2873 *
2874 * Releases the subtree rooted at @fo_node.
2875 *
2876 * Should be used with #fo_node_traverse() and %G_POST_ORDER order so
2877 * child nodes release their subtrees before @fo_node releases the
2878 * children.
2879 *
2880 * Return value: %TRUE if an error occurred, %FALSE otherwise.
2881 **/
2882 gboolean
2883 fo_area_release (FoNode *fo_node,
2884 gpointer data)
2885 {
2886 g_return_val_if_fail (FO_IS_AREA (fo_node), TRUE);
2887
2888 FoNodeTraverseFunc func = FO_AREA_GET_CLASS (fo_node)->release;
2889
2890 if (func != NULL)
2891 {
2892 return func (fo_node,
2893 data);
2894 }
2895 else
2896 {
2897 return FALSE;
2898 }
2899 }
2900
2901 static void
2902 _release_children (FoNode *node,
2903 gpointer data G_GNUC_UNUSED)
2904 {
2905 fo_node_unlink (node);
2906 }
2907
2908 /**
2909 * _release_default:
2910 * @fo_node: #FoFo
2911 * @data: Context within which to resolve property expressions
2912 *
2913 * Every #FoFo object was created from a result tree element that is
2914 * in the XSL FO namespace. The object's specified property values
2915 * are created from the result tree element's attributes.
2916 *
2917 * This function evaluates each of the property attributes of the
2918 * result tree element for @fo_node.
2919 *
2920 * Return value: %FALSE if completed successfully, %TRUE otherwise
2921 **/
2922 gboolean
2923 _release_default (FoNode *fo_node,
2924 gpointer data G_GNUC_UNUSED)
2925 {
2926 /*
2927 g_message ("before::");
2928 fo_object_debug_dump (FO_OBJECT (fo_node), 0);
2929 */
2930 fo_node_children_foreach (fo_node,
2931 G_TRAVERSE_ALL,
2932 _release_children,
2933 NULL);
2934 /*
2935 g_message ("after::");
2936 fo_object_debug_dump (FO_OBJECT (fo_node), 0);
2937 */
2938 return FALSE;
2939 }
2940