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