1 /* Fo
2  * fo-area-table-continuation.c: Area object for 'table-continuation' formatting objects
3  *
4  * Copyright (C) 2001 Sun Microsystems
5  * Copyright (C) 2007-2009 Menteith Consulting Ltd
6  *
7  * See COPYING for the status of this software.
8  */
9 
10 #include "fo-utils.h"
11 #include "fo-area.h"
12 #include "fo-area-private.h"
13 #include "fo-area-reference.h"
14 #include "fo-area-reference-private.h"
15 #include "fo-area-table-continuation.h"
16 #include "fo-area-table-continuation-private.h"
17 #include "fo-area-table-header.h"
18 #include "fo/fo-block-fo.h"
19 #include "fo/fo-table.h"
20 #include "property/fo-property-block-progression-dimension.h"
21 #include "property/fo-property-inline-progression-dimension.h"
22 #include "property/fo-property-keep-with-next.h"
23 #include "property/fo-property-keep-with-previous.h"
24 #include "property/fo-property-keep-with-next-within-column.h"
25 #include "property/fo-property-keep-with-next-within-page.h"
26 #include "property/fo-property-keep-with-previous-within-column.h"
27 #include "property/fo-property-keep-with-previous-within-page.h"
28 
29 static void fo_area_table_continuation_class_init  (FoAreaTableContinuationClass *klass);
30 static void fo_area_table_continuation_finalize    (GObject           *object);
31 
32 static void fo_area_table_continuation_debug_dump_properties (FoArea *area,
33 							      gint depth);
34 static FoArea* fo_area_table_continuation_size_request (FoArea *child);
35 static FoArea* fo_area_table_continuation_split_before_height (FoArea *area,
36 						      gdouble max_height);
37 static gboolean fo_area_table_continuation_split_before_height_check (FoArea *area,
38 							     gdouble max_height);
39 static void fo_area_table_continuation_size_adjust (FoArea *area,
40 					    gpointer data);
41 
42 static void fo_area_table_continuation_set_or_split (FoArea *area,
43 					     gpointer data);
44 static void fo_area_table_continuation_update_after_clone (FoArea *clone,
45 							   FoArea *original);
46 
47 static gpointer parent_class;
48 
49 /**
50  * fo_area_table_continuation_get_type:
51  * @void:
52  *
53  * Register the FoAreaTableContinuation object type.
54  *
55  * Return value: GType value of the FoAreaTableContinuation object type.
56  **/
57 GType
fo_area_table_continuation_get_type(void)58 fo_area_table_continuation_get_type (void)
59 {
60   static GType object_type = 0;
61 
62   if (!object_type)
63     {
64       static const GTypeInfo object_info =
65       {
66         sizeof (FoAreaTableContinuationClass),
67         (GBaseInitFunc) NULL,
68         (GBaseFinalizeFunc) NULL,
69         (GClassInitFunc) fo_area_table_continuation_class_init,
70         NULL,           /* class_finalize */
71         NULL,           /* class_data */
72         sizeof (FoAreaTableContinuation),
73         0,              /* n_preallocs */
74         NULL,		/* instance_init */
75 	NULL		/* value_table */
76       };
77 
78       object_type = g_type_register_static (FO_TYPE_AREA_TABLE,
79                                             "FoAreaTableContinuation",
80                                             &object_info, 0);
81     }
82 
83   return object_type;
84 }
85 
86 static void
fo_area_table_continuation_class_init(FoAreaTableContinuationClass * klass)87 fo_area_table_continuation_class_init (FoAreaTableContinuationClass *klass)
88 {
89   GObjectClass *object_class = G_OBJECT_CLASS (klass);
90 
91   parent_class = g_type_class_peek_parent (klass);
92 
93   object_class->finalize = fo_area_table_continuation_finalize;
94 
95   FO_AREA_CLASS (klass)->debug_dump_properties = fo_area_table_continuation_debug_dump_properties;
96   FO_AREA_CLASS (klass)->size_request = fo_area_table_continuation_size_request;
97   FO_AREA_CLASS (klass)->split_before_height = fo_area_table_continuation_split_before_height;
98   FO_AREA_CLASS (klass)->split_before_height_check = fo_area_table_continuation_split_before_height_check;
99   FO_AREA_CLASS (klass)->update_after_clone =
100     fo_area_table_continuation_update_after_clone;
101 }
102 
103 static void
fo_area_table_continuation_finalize(GObject * object)104 fo_area_table_continuation_finalize (GObject *object)
105 {
106   FoAreaTableContinuation *fo_area_table_continuation;
107 
108   fo_area_table_continuation = FO_AREA_TABLE_CONTINUATION (object);
109 
110   G_OBJECT_CLASS (parent_class)->finalize (object);
111 }
112 
113 
114 /**
115  * fo_area_table_continuation_new:
116  *
117  * Creates a new #FoAreaTableContinuation initialized to default value.
118  *
119  * Return value: the new #FoAreaTableContinuation
120  **/
121 FoArea*
fo_area_table_continuation_new(void)122 fo_area_table_continuation_new (void)
123 {
124   return FO_AREA (g_object_new (fo_area_table_continuation_get_type (), NULL));
125 }
126 
127 
128 /**
129  * fo_area_table_continuation_debug_dump_properties:
130  * @area:  The #FoArea object
131  * @depth: Indent level to add to the output
132  *
133  * Logs the value of each significant property of @area then calls
134  * debug_dump_properties method of parent class.
135  **/
136 void
fo_area_table_continuation_debug_dump_properties(FoArea * area,gint depth)137 fo_area_table_continuation_debug_dump_properties (FoArea *area,
138 					  gint depth)
139 {
140   FoAreaTableContinuation *table_continuation;
141   gchar *indent = g_strnfill (depth * 2, ' ');
142   gchar *fo_sprintf;
143 
144   g_return_if_fail (area != NULL);
145   g_return_if_fail (FO_IS_AREA_TABLE_CONTINUATION (area));
146 
147   table_continuation = FO_AREA_TABLE_CONTINUATION (area);
148 
149   fo_sprintf = fo_object_debug_sprintf (table_continuation->table);
150   g_log (G_LOG_DOMAIN,
151 	 G_LOG_LEVEL_DEBUG,
152 	 "%stable:        %s",
153 	 indent,
154 	 fo_sprintf);
155   g_free (fo_sprintf);
156 
157   fo_sprintf = fo_object_debug_sprintf (table_continuation->table_header);
158   g_log (G_LOG_DOMAIN,
159 	 G_LOG_LEVEL_DEBUG,
160 	 "%stable-header: %s",
161 	 indent,
162 	 fo_sprintf);
163   g_free (fo_sprintf);
164 
165   g_free (indent);
166   FO_AREA_CLASS (parent_class)->debug_dump_properties (area, depth + 1);
167 }
168 
169 /**
170  * fo_area_table_continuation_size_adjust:
171  * @area: #FoArea node to be placed within parent
172  * @data: Not used
173  *
174  * Place @area within its parent and adjust the parent's next-x and
175  * next-y properties accordingly.
176  **/
177 void
fo_area_table_continuation_size_adjust(FoArea * area,gpointer data G_GNUC_UNUSED)178 fo_area_table_continuation_size_adjust (FoArea  *area,
179 					gpointer data G_GNUC_UNUSED)
180 {
181   FoArea *table_continuation;
182 
183   g_return_if_fail (FO_IS_AREA (area));
184   g_return_if_fail (FO_IS_AREA_TABLE_CONTINUATION (fo_area_parent (area)));
185 
186   table_continuation = fo_area_parent (area);
187 
188   fo_area_area_set_x (area,
189 		      fo_area_get_next_x (table_continuation) +
190 		      fo_area_area_get_start_indent (area));
191   fo_area_area_set_y (area,
192 		      fo_area_get_next_y (table_continuation) -
193 		      fo_area_area_get_space_before (area));
194   fo_area_set_next_x (table_continuation,
195 		      fo_area_area_get_border_before (table_continuation) +
196 		      fo_area_area_get_padding_before (table_continuation));
197   fo_area_set_next_y (table_continuation,
198 		      fo_area_get_next_y (table_continuation) -
199 		      fo_area_area_get_height (area));
200   fo_area_set_available_height (area,
201 				fo_area_area_get_height (area));
202   fo_area_set_available_width (area,
203 			       fo_area_get_child_available_ipdim (table_continuation));
204 }
205 
206 /**
207  * fo_area_table_continuation_set_or_split:
208  * @area: #FoArea to be either placed within the parent area or split
209  *        into two areas
210  * @data: Not used
211  *
212  *
213  **/
214 void
fo_area_table_continuation_set_or_split(FoArea * area,gpointer data G_GNUC_UNUSED)215 fo_area_table_continuation_set_or_split (FoArea  *area,
216 					 gpointer data G_GNUC_UNUSED)
217 {
218   FoArea *table_continuation;
219   gdouble table_continuation_child_available_bpdim;
220 
221   g_return_if_fail (FO_IS_AREA (area));
222   g_return_if_fail (FO_IS_AREA_TABLE_CONTINUATION (fo_area_parent (area)));
223 
224   table_continuation = fo_area_parent (area);
225   table_continuation_child_available_bpdim = fo_area_get_child_available_bpdim (table_continuation);
226 
227   if ((table_continuation_child_available_bpdim -
228        (fo_area_get_next_y (table_continuation) -
229 	fo_area_area_get_height (area))) >= 0)
230     {
231       fo_area_area_set_x (area,
232 			  fo_area_get_next_x (table_continuation) +
233 			  fo_area_area_get_start_indent (area));
234       fo_area_area_set_y (area,
235 			  fo_area_get_next_y (table_continuation));
236       fo_area_set_next_x (table_continuation,
237 			  fo_area_area_get_border_before (table_continuation) +
238 			  fo_area_area_get_padding_before (table_continuation));
239       fo_area_set_next_y (table_continuation,
240 			  fo_area_get_next_y (table_continuation) -
241 			  fo_area_area_get_height (area));
242       fo_area_set_available_height (area,
243 				    fo_area_area_get_height (area));
244       fo_area_set_available_width (area,
245 				   fo_area_get_child_available_ipdim (table_continuation));
246     }
247   else
248     {
249 #if defined(LIBFO_DEBUG) && 1
250       g_message ("table_continuation_set_or_split:: splitting:: child: %s; generated by: %s",
251 		 fo_object_debug_sprintf (area) ,
252 		 fo_object_debug_sprintf (area->generated_by));
253 #endif
254       area = fo_area_split_before_height (area,
255 					  table_continuation_child_available_bpdim -
256 					  fo_area_area_get_height (table_continuation));
257       table_continuation = fo_area_parent (area);
258       table_continuation_child_available_bpdim =
259 	fo_area_get_child_available_bpdim (table_continuation);
260     }
261 }
262 
263 /**
264  * fo_area_table_continuation_size_request:
265  * @child: Child area
266  *
267  * Check that the parent area of @child has sufficient space for
268  * @child.  If not enough space, request that the parent has
269  * sufficient space allocated for it, then adjust @child and its
270  * siblings as necessary to fit into the resized parent area.
271  *
272  * Return value: Pointer to the last area generated from @child after
273  * any reallocation and resizing
274  **/
275 FoArea*
fo_area_table_continuation_size_request(FoArea * child)276 fo_area_table_continuation_size_request (FoArea *child)
277 {
278   FoArea *table_continuation;
279   FoArea *return_child;
280   FoArea *child_original_next_part;
281   FoDatatype *fo_continuation_bpdim;
282   gdouble table_continuation_child_available_bpdim;
283   gdouble table_continuation_use_height = 0.0;
284   gdouble table_continuation_target_height = 0.0;
285   gdouble child_height;
286   gdouble total_child_height = 0.0;
287 
288   g_return_val_if_fail (child != NULL, NULL);
289   g_return_val_if_fail (FO_IS_AREA_AREA (child), NULL);
290   g_return_val_if_fail (!FO_AREA_IS_ROOT (child), NULL);
291   g_return_val_if_fail (fo_area_parent (child) != NULL, NULL);
292   g_return_val_if_fail (FO_IS_AREA_TABLE_CONTINUATION (fo_area_parent (child)), NULL);
293 
294   child_original_next_part = child->next_part;
295 
296   child_height = fo_area_area_get_height (child);
297 
298   table_continuation = fo_area_parent (child);
299   table_continuation_child_available_bpdim =
300     fo_area_get_child_available_bpdim (table_continuation);
301 
302   gdouble table_continuation_header_height = 0.0;
303   if ((FO_AREA_TABLE_CONTINUATION (table_continuation)->table != NULL) &&
304       (FO_AREA_TABLE_CONTINUATION (table_continuation)->table_header != NULL))
305     {
306       table_continuation_header_height =
307 	fo_area_area_get_height (FO_AREA_TABLE_CONTINUATION (table_continuation)->table_header);
308     }
309 
310 #if 0
311 	  g_message ("table_continuation_size_request:: header_height: %g",
312 		     table_continuation_header_height);
313 #endif
314 
315   fo_area_children_foreach (table_continuation,
316 			    G_TRAVERSE_ALL,
317 			    &fo_area_accumulate_height,
318 			    &total_child_height);
319 
320   table_continuation_target_height =
321     table_continuation_header_height +
322     total_child_height +
323     fo_area_area_get_border_before (table_continuation) +
324     fo_area_area_get_padding_before (table_continuation) +
325     fo_area_area_get_padding_after (table_continuation) +
326     fo_area_area_get_border_after (table_continuation);
327 
328   fo_continuation_bpdim =
329     fo_property_get_value (fo_table_get_block_progression_dimension (table_continuation->generated_by));
330 
331   if (FO_IS_LENGTH_RANGE (fo_continuation_bpdim))
332     {
333       FoDatatype *min_datatype = fo_length_range_get_minimum (fo_continuation_bpdim);
334       FoDatatype *opt_datatype = fo_length_range_get_optimum (fo_continuation_bpdim);
335       FoDatatype *max_datatype = fo_length_range_get_maximum (fo_continuation_bpdim);
336 
337       if (FO_IS_LENGTH (min_datatype) &&
338 	  table_continuation_target_height <= fo_length_get_value (min_datatype))
339 	{
340 	  table_continuation_use_height = fo_length_get_value (min_datatype);
341 
342 #if defined(LIBFO_DEBUG) && 0
343 	  g_message ("table_continuation_size_request:: target: %g; min: %g",
344 		     table_continuation_target_height,
345 		     fo_length_get_value (min_datatype));
346 #endif
347 	}
348       else if (FO_IS_LENGTH (opt_datatype) &&
349 	       table_continuation_target_height < fo_length_get_value (opt_datatype))
350 	{
351 	  table_continuation_use_height = fo_length_get_value (opt_datatype);
352 
353 #if defined(LIBFO_DEBUG) && 0
354 	  g_message ("table_continuation_size_request:: target: %g; opt: %g",
355 		     table_continuation_target_height,
356 		     fo_length_get_value (opt_datatype));
357 #endif
358 	}
359       else if (FO_IS_LENGTH (max_datatype) &&
360 	       fo_length_get_value (max_datatype) < table_continuation_target_height)
361 	{
362 	  table_continuation_use_height = fo_length_get_value (max_datatype);
363 
364 #if defined(LIBFO_DEBUG) && 0
365 	  g_message ("table_continuation_size_request:: target: %g; max: %g",
366 		     table_continuation_target_height,
367 		     fo_length_get_value (max_datatype));
368 #endif
369 	}
370       else
371 	{
372 	  table_continuation_use_height = table_continuation_target_height;
373 	}
374     }
375   else
376     {
377       g_assert_not_reached ();
378     }
379 
380   if (table_continuation_child_available_bpdim < table_continuation_use_height)
381     {
382       fo_area_area_set_height (table_continuation, table_continuation_use_height);
383       table_continuation = fo_area_size_request (table_continuation);
384       /*
385       table_continuation_child_available_ipdim =
386 	MAX (fo_area_get_available_width (table_continuation) -
387 	     fo_area_area_get_border_start (table_continuation) -
388 	     fo_area_area_get_padding_start (table_continuation) -
389 	     fo_area_area_get_padding_end (table_continuation) -
390 	     fo_area_area_get_border_end (table_continuation),
391 	     0);
392       fo_area_set_child_available_ipdim (table_continuation,
393 					 table_continuation_child_available_ipdim);
394       */
395       table_continuation_child_available_bpdim =
396 	MAX (fo_area_get_available_height (table_continuation) -
397 	     table_continuation_header_height +
398 	     fo_area_area_get_border_before (table_continuation) -
399 	     fo_area_area_get_padding_before (table_continuation) -
400 	     fo_area_area_get_padding_after (table_continuation) -
401 	     fo_area_area_get_border_after (table_continuation),
402 	     0);
403       fo_area_set_child_available_bpdim (table_continuation,
404 					 table_continuation_child_available_bpdim);
405     }
406 
407   total_child_height = 0;
408   fo_area_children_foreach (table_continuation,
409 			    G_TRAVERSE_ALL,
410 			    &fo_area_accumulate_height,
411 			    &total_child_height);
412 
413   table_continuation_target_height =
414     table_continuation_header_height +
415     total_child_height +
416     fo_area_area_get_border_before (table_continuation) +
417     fo_area_area_get_padding_before (table_continuation) +
418     fo_area_area_get_padding_after (table_continuation) +
419     fo_area_area_get_border_after (table_continuation);
420 
421   fo_area_set_next_x (table_continuation,
422 		      fo_area_area_get_border_start (table_continuation) +
423 		      fo_area_area_get_padding_start (table_continuation));
424   fo_area_set_next_y (table_continuation,
425 		      table_continuation_header_height +
426 		      - (fo_area_area_get_border_before (table_continuation) +
427 			 fo_area_area_get_padding_before (table_continuation)));
428 
429   if (table_continuation_target_height <= table_continuation_child_available_bpdim)
430     {
431       fo_area_children_foreach (table_continuation,
432 				G_TRAVERSE_ALL,
433 				&fo_area_table_continuation_size_adjust,
434 				NULL);
435 
436       return_child = child;
437 
438       while ((return_child->next_part != NULL) &&
439 	     (return_child->next_part != child_original_next_part))
440 	{
441 	  return_child = return_child->next_part;
442 	}
443 
444       return return_child;
445     }
446   else
447     {
448       fo_area_children_foreach (table_continuation,
449 				G_TRAVERSE_ALL,
450 				&fo_area_table_continuation_set_or_split,
451 				NULL);
452 #if defined(LIBFO_DEBUG) && 0
453       g_message ("table_continuation_size_request (%p):: total > available:: return:: table_continuation->last: %s; generated by: %s",
454 		 child,
455 		 fo_object_debug_sprintf (fo_area_last_child (table_continuation)),
456 		 fo_object_debug_sprintf (fo_area_last_child (table_continuation)->generated_by));
457 #endif
458       return_child = child;
459 
460       while ((return_child->next_part != NULL) &&
461 	     (return_child->next_part != child_original_next_part))
462 	{
463 	  return_child = return_child->next_part;
464 	}
465 
466       return return_child;
467       /*
468       return fo_area_last_child (table_continuation);
469       */
470     }
471 }
472 
473 /* return the new area containing what comes after the split */
474 /* leave @area as area remaining after split */
475 FoArea*
fo_area_table_continuation_split_before_height(FoArea * area,gdouble max_height)476 fo_area_table_continuation_split_before_height (FoArea *area,
477 					gdouble max_height)
478 {
479   FoArea *use_child_area;
480   gdouble minus_child_y = 0.0;
481   gdouble child_height = 0.0;
482 
483   g_return_val_if_fail (FO_IS_AREA_TABLE_CONTINUATION (area), NULL);
484   g_return_val_if_fail (fo_area_n_children (area) > 0, NULL);
485   g_return_val_if_fail (max_height > 0, NULL);
486 
487   /* if the current area is less than max height, then no new area */
488   if (fo_area_area_get_height (area) < max_height)
489     return NULL;
490 
491   use_child_area = fo_area_first_child (area);
492 
493   while (use_child_area)
494     {
495       minus_child_y = -fo_area_area_get_y (use_child_area);
496       child_height = fo_area_area_get_height (use_child_area);
497 
498       if (minus_child_y + child_height >= max_height)
499 	break;
500       else
501        use_child_area = fo_area_next_sibling (use_child_area);
502     }
503 
504 #if defined(LIBFO_DEBUG) && 1
505   g_message ("table_continuation_split_before_height:: splitting: area: %s; generated by: %s; y: %f; height: %f",
506 	     fo_object_debug_sprintf (use_child_area),
507 	     fo_object_debug_sprintf (fo_area_get_generated_by (use_child_area)),
508 	     fo_area_area_get_y (use_child_area),
509 	     fo_area_area_get_height (use_child_area));
510 #endif
511 
512   if (use_child_area == NULL)
513     return NULL;
514 
515   if (minus_child_y >= max_height)
516     {
517       /* max_height falls before use_child_area, i.e. in space between areas */
518 
519       if (use_child_area == fo_area_first_child (area))
520 	{
521 	  return NULL;
522 	}
523       else
524 	{
525 	  FoFo *child_fo =
526 	    fo_area_get_generated_by (use_child_area);
527 	  FoDatatype *child_kwpwp_datatype =
528 	    fo_keep_get_within_page (fo_property_get_value (fo_block_fo_get_keep_with_previous (child_fo)));
529 	  FoDatatype *child_kwpwc_datatype =
530 	    fo_keep_get_within_column (fo_property_get_value (fo_block_fo_get_keep_with_previous (child_fo)));
531 
532 	  FoFo *prev_child_fo =
533 	    fo_area_get_generated_by (fo_area_prev_sibling (use_child_area));
534 	  FoDatatype *prev_child_kwnwp_datatype =
535 	    fo_keep_get_within_page (fo_property_get_value (fo_block_fo_get_keep_with_next (prev_child_fo)));
536 	  FoDatatype *prev_child_kwnwc_datatype =
537 	    fo_keep_get_within_column (fo_property_get_value (fo_block_fo_get_keep_with_next (prev_child_fo)));
538 
539 	  /* FIXME: Need to handle integer keeps */
540 	  if ((FO_IS_ENUM (prev_child_kwnwp_datatype) &&
541 	       fo_enum_get_value (prev_child_kwnwp_datatype) == FO_ENUM_ENUM_AUTO) &&
542 	      (FO_IS_ENUM (prev_child_kwnwc_datatype) &&
543 	       fo_enum_get_value (prev_child_kwnwc_datatype) == FO_ENUM_ENUM_AUTO)  &&
544 	      (FO_IS_ENUM (child_kwpwp_datatype) &&
545 	       fo_enum_get_value (child_kwpwp_datatype) == FO_ENUM_ENUM_AUTO) &&
546 	      (FO_IS_ENUM (child_kwpwc_datatype) &&
547 	       fo_enum_get_value (child_kwpwc_datatype) == FO_ENUM_ENUM_AUTO))
548 	    {
549 	      /* If got to here, all relevant keeps are 'auto' */
550 	      FoArea *clone = fo_area_clone (area);
551 
552 	      fo_area_unlink_with_next_siblings (use_child_area);
553 	      fo_area_insert_with_next_siblings (clone, 0, use_child_area);
554 
555 	      return clone;
556 	    }
557 	  else
558 	    {
559 	      gdouble minus_prev_y =
560 		fo_area_area_get_y (fo_area_prev_sibling (use_child_area));
561 	      gdouble prev_height =
562 		fo_area_area_get_height (fo_area_prev_sibling (use_child_area));
563 	      /* If can't split between use_child_area and previous, maybe
564 		 can split at lower height */
565 	      return fo_area_table_continuation_split_before_height (area,
566 							     minus_prev_y +
567 							     prev_height);
568 	    }
569 	}
570     }
571   else
572     {
573       /* max_height falls within use_child_area */
574       gboolean child_can_split = fo_area_split_before_height_check (use_child_area,
575 								    max_height -
576 								    minus_child_y);
577 
578       if (child_can_split)
579 	{
580 	  FoArea *clone = fo_area_clone (area);
581 	  FoArea *split_child = fo_area_split_before_height (use_child_area,
582 							     max_height -
583 							     minus_child_y);
584 	  fo_area_unlink_with_next_siblings (split_child);
585 	  fo_area_insert_with_next_siblings (clone, 0, split_child);
586 
587 	  return clone;
588 	}
589       else
590 	{
591 	  /* If can't split use_child_area, maybe
592 	     can split at lower height */
593 	  return fo_area_table_continuation_split_before_height (area,
594 							 minus_child_y);
595 	}
596     }
597 }
598 
599 /* return the new area containing what comes after the split */
600 /* leave @area as area remaining after split */
601 gboolean
fo_area_table_continuation_split_before_height_check(FoArea * area,gdouble max_height)602 fo_area_table_continuation_split_before_height_check (FoArea *area,
603 					     gdouble max_height)
604 {
605   FoArea *use_child_area;
606   gdouble minus_child_y = 0.0;
607   gdouble child_height = 0.0;
608 
609   g_return_val_if_fail (FO_IS_AREA_TABLE_CONTINUATION (area), FALSE);
610   g_return_val_if_fail (fo_area_n_children (area) > 0, FALSE);
611   g_return_val_if_fail (max_height > 0, FALSE);
612 
613   /* if the current area is less than max height, then no new area */
614   if (fo_area_area_get_height (area) < max_height)
615     return FALSE;
616 
617   use_child_area = fo_area_first_child (area);
618 
619   while (use_child_area)
620     {
621       minus_child_y = -fo_area_area_get_y (use_child_area);
622       child_height = fo_area_area_get_height (use_child_area);
623 
624       if (minus_child_y + child_height >= max_height)
625 	break;
626       else
627        use_child_area = fo_area_next_sibling (use_child_area);
628     }
629 
630 #if defined(LIBFO_DEBUG) && 1
631   g_message ("table_continuation_split_before_height_check:: splitting: area: %s; generated by: %s; y: %f; height: %f",
632 	     fo_object_debug_sprintf (use_child_area),
633 	     fo_object_debug_sprintf (fo_area_get_generated_by (use_child_area)),
634 	     fo_area_area_get_y (use_child_area),
635 	     fo_area_area_get_height (use_child_area));
636 #endif
637 
638   if (use_child_area == NULL)
639     return FALSE;
640 
641   if (minus_child_y >= max_height)
642     {
643       /* max_height falls before use_child_area, i.e. in space between areas */
644 
645       if (use_child_area == fo_area_first_child (area))
646 	{
647 	  return FALSE;
648 	}
649       else
650 	{
651 	  FoFo *child_fo =
652 	    fo_area_get_generated_by (use_child_area);
653 	  FoDatatype *child_kwpwp_datatype =
654 	    fo_keep_get_within_page (fo_property_get_value (fo_block_fo_get_keep_with_previous (child_fo)));
655 	  FoDatatype *child_kwpwc_datatype =
656 	    fo_keep_get_within_column (fo_property_get_value (fo_block_fo_get_keep_with_previous (child_fo)));
657 
658 	  FoFo *prev_child_fo =
659 	    fo_area_get_generated_by (fo_area_prev_sibling (use_child_area));
660 	  FoDatatype *prev_child_kwnwp_datatype =
661 	    fo_keep_get_within_page (fo_property_get_value (fo_block_fo_get_keep_with_next (prev_child_fo)));
662 	  FoDatatype *prev_child_kwnwc_datatype =
663 	    fo_keep_get_within_column (fo_property_get_value (fo_block_fo_get_keep_with_next (prev_child_fo)));
664 
665 	  /* FIXME: Need to handle integer keeps */
666 	  if ((FO_IS_ENUM (prev_child_kwnwp_datatype) &&
667 	       fo_enum_get_value (prev_child_kwnwp_datatype) == FO_ENUM_ENUM_AUTO) &&
668 	      (FO_IS_ENUM (prev_child_kwnwc_datatype) &&
669 	       fo_enum_get_value (prev_child_kwnwc_datatype) == FO_ENUM_ENUM_AUTO)  &&
670 	      (FO_IS_ENUM (child_kwpwp_datatype) &&
671 	       fo_enum_get_value (child_kwpwp_datatype) == FO_ENUM_ENUM_AUTO) &&
672 	      (FO_IS_ENUM (child_kwpwc_datatype) &&
673 	       fo_enum_get_value (child_kwpwc_datatype) == FO_ENUM_ENUM_AUTO))
674 	    {
675 	      /* If got to here, all relevant keeps are 'auto' */
676 	      return TRUE;
677 	    }
678 	  else
679 	    {
680 	      gdouble minus_prev_y =
681 		fo_area_area_get_y (fo_area_prev_sibling (use_child_area));
682 	      gdouble prev_height =
683 		fo_area_area_get_height (fo_area_prev_sibling (use_child_area));
684 	      /* If can't split between use_child_area and previous, maybe
685 		 can split at lower height */
686 	      return fo_area_table_continuation_split_before_height_check (area,
687 								   minus_prev_y +
688 								   prev_height);
689 	    }
690 	}
691     }
692   else
693     {
694       /* max_height falls within use_child_area */
695       gboolean child_can_split = fo_area_split_before_height_check (use_child_area,
696 							      max_height -
697 							      minus_child_y);
698 
699       if (child_can_split)
700 	{
701 	  return TRUE;
702 	}
703       else
704 	{
705 	  /* If can't split use_child_area, maybe
706 	     can split at lower height */
707 	  return fo_area_table_continuation_split_before_height_check (area,
708 							       minus_child_y);
709 	}
710     }
711 }
712 
713 /**
714  * fo_area_table_continuation_update_after_clone:
715  * @clone:    New object cloned from @original
716  * @original: Original area object
717  *
718  * Update the FoAreaTableContinuation-specific instance variables of @clone to
719  * match those of @original
720  **/
721 void
fo_area_table_continuation_update_after_clone(FoArea * clone,FoArea * original)722 fo_area_table_continuation_update_after_clone (FoArea *clone,
723 					       FoArea *original)
724 {
725   FoAreaTableContinuation *table_continuation;
726 
727   g_return_if_fail (clone != NULL);
728   g_return_if_fail (FO_IS_AREA_TABLE_CONTINUATION (clone));
729   g_return_if_fail (original != NULL);
730   g_return_if_fail (FO_IS_AREA_TABLE_CONTINUATION (original) ||
731 		    FO_IS_AREA_TABLE (original));
732 
733   table_continuation = FO_AREA_TABLE_CONTINUATION (clone);
734 
735   FO_AREA_CLASS (parent_class)->update_after_clone (clone, original);
736 
737   if (FO_IS_AREA_TABLE (original))
738     {
739       FoArea *child = NULL;
740 
741       table_continuation->table = original;
742 
743       child = fo_area_first_child (original);
744 
745       while (child && G_TYPE_FROM_INSTANCE (child) != FO_TYPE_AREA_TABLE_HEADER)
746 	{
747 	  child = fo_area_next_sibling (child);
748 	}
749 
750       table_continuation->table_header = child;
751     }
752   else
753     {
754       table_continuation->table =
755 	FO_AREA_TABLE_CONTINUATION (original)->table;
756       table_continuation->table_header =
757 	FO_AREA_TABLE_CONTINUATION (original)->table_header;
758     }
759 
760 }
761