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