1 /* Fo
2 * fo-area-table-cell-proxy.c: Proxy area object for table-cell
3 * formatting objects that span rows
4 *
5 * Copyright (C) 2001 Sun Microsystems
6 * Copyright (C) 2007-2009 Menteith Consulting Ltd
7 * Copyright (C) 2011-2012 Mentea
8 *
9 * See COPYING for the status of this software.
10 */
11
12 #include "fo-utils.h"
13 #include "fo-area.h"
14 #include "fo-area-private.h"
15 #include "fo-area-area.h"
16 #include "fo-area-area-private.h"
17 #include "fo-area-table-cell-proxy.h"
18 #include "fo-area-spanning-table-cell.h"
19 #include "fo/fo-table-cell.h"
20 #include "property/fo-property-block-progression-dimension.h"
21
22 struct _FoAreaTableCellProxy
23 {
24 FoAreaArea parent_instance;
25
26 FoArea *table_cell;
27 gint row_number;
28 gdouble min_height;
29 };
30
31 struct _FoAreaTableCellProxyClass
32 {
33 FoAreaAreaClass parent_class;
34 };
35
36 static void fo_area_table_cell_proxy_class_init (FoAreaTableCellProxyClass *klass);
37 static void fo_area_table_cell_proxy_finalize (GObject *object);
38
39 static void fo_area_table_cell_proxy_debug_dump_properties (FoArea *area,
40 gint depth);
41 static FoArea* fo_area_table_cell_proxy_size_request (FoArea *child);
42 static FoArea* fo_area_table_cell_proxy_split_before_height (FoArea *area,
43 gdouble max_height);
44 static gboolean fo_area_table_cell_proxy_split_before_height_check (FoArea *area,
45 gdouble max_height);
46
47 static gpointer parent_class;
48
49 /**
50 * fo_area_table_cell_proxy_get_type:
51 * @void:
52 *
53 * Register the FoTableCellProxy object type.
54 *
55 * Return value: GType value of the FoTableCellProxy object type.
56 **/
57 GType
fo_area_table_cell_proxy_get_type(void)58 fo_area_table_cell_proxy_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 (FoAreaTableCellProxyClass),
67 (GBaseInitFunc) NULL,
68 (GBaseFinalizeFunc) NULL,
69 (GClassInitFunc) fo_area_table_cell_proxy_class_init,
70 NULL, /* class_finalize */
71 NULL, /* class_data */
72 sizeof (FoAreaTableCellProxy),
73 0, /* n_preallocs */
74 NULL, /* instance_init */
75 NULL /* value_table */
76 };
77
78 object_type = g_type_register_static (FO_TYPE_AREA_AREA,
79 "FoAreaTableCellProxy",
80 &object_info, 0);
81 }
82
83 return object_type;
84 }
85
86 /**
87 * fo_area_table_cell_proxy_class_init:
88 * @klass: FoTableCellProxyClass object to initialise
89 *
90 * Implements GClassInitFunc for FoTableCellProxyClass
91 **/
92 void
fo_area_table_cell_proxy_class_init(FoAreaTableCellProxyClass * klass)93 fo_area_table_cell_proxy_class_init (FoAreaTableCellProxyClass *klass)
94 {
95 GObjectClass *object_class = G_OBJECT_CLASS (klass);
96 FoAreaClass *fo_area_class = FO_AREA_CLASS (klass);
97
98 parent_class = g_type_class_peek_parent (klass);
99
100 object_class->finalize = fo_area_table_cell_proxy_finalize;
101
102 fo_area_class->debug_dump_properties = fo_area_table_cell_proxy_debug_dump_properties;
103 fo_area_class->size_request = fo_area_table_cell_proxy_size_request;
104 fo_area_class->split_before_height = fo_area_table_cell_proxy_split_before_height;
105 fo_area_class->split_before_height_check = fo_area_table_cell_proxy_split_before_height_check;
106 }
107
108 /**
109 * fo_area_table_cell_proxy_finalize:
110 * @object: FoTableCellProxy object to finalize
111 *
112 * Implements GObjectFinalizeFunc for FoTableCellProxy
113 **/
114 void
fo_area_table_cell_proxy_finalize(GObject * object)115 fo_area_table_cell_proxy_finalize (GObject *object)
116 {
117 FoAreaTableCellProxy *fo_area_table_cell_proxy;
118
119 fo_area_table_cell_proxy = FO_AREA_TABLE_CELL_PROXY (object);
120
121 G_OBJECT_CLASS (parent_class)->finalize (object);
122 }
123
124
125 /**
126 * fo_area_table_cell_proxy_new:
127 *
128 * Creates a new #FoAreaTableCellProxy initialized to default value.
129 *
130 * Return value: the new #FoAreaTableCellProxy
131 **/
132 FoArea*
fo_area_table_cell_proxy_new(void)133 fo_area_table_cell_proxy_new (void)
134 {
135 return FO_AREA (g_object_new (fo_area_table_cell_proxy_get_type (), NULL));
136 }
137
138 /**
139 * fo_area_table_cell_proxy_set_table_cell:
140 * @fo_area: The #FoAreaTableCellProxy object
141 * @new_table_cell: The new "row-number" property value
142 *
143 * Sets the #line-last property of @area_area to @new_table_cell
144 **/
145 void
fo_area_table_cell_proxy_set_table_cell(FoArea * fo_area,FoArea * new_table_cell)146 fo_area_table_cell_proxy_set_table_cell (FoArea *fo_area,
147 FoArea *new_table_cell)
148 {
149 g_return_if_fail (fo_area != NULL);
150 g_return_if_fail (FO_IS_AREA_TABLE_CELL_PROXY (fo_area));
151 g_return_if_fail (FO_IS_AREA_SPANNING_TABLE_CELL (new_table_cell));
152
153 FO_AREA_TABLE_CELL_PROXY (fo_area)->table_cell = new_table_cell;
154 /* g_object_notify (G_OBJECT (fo_area), "table_cell");*/
155 }
156
157 /**
158 * fo_area_table_cell_proxy_get_table_cell:
159 * @fo_area: The #FoAreaTableCellProxy object
160 *
161 * Gets the 'row-number' property of @area_table_cell_proxy
162 *
163 * Return value: The "row-number" property value
164 **/
165 FoArea*
fo_area_table_cell_proxy_get_table_cell(FoArea * fo_area)166 fo_area_table_cell_proxy_get_table_cell (FoArea *fo_area)
167 {
168 g_return_val_if_fail (fo_area != NULL, 0);
169 g_return_val_if_fail (FO_IS_AREA_TABLE_CELL_PROXY (fo_area), 0);
170
171 return FO_AREA_TABLE_CELL_PROXY (fo_area)->table_cell;
172 }
173
174 /**
175 * fo_area_table_cell_proxy_set_row_number:
176 * @fo_area: The #FoAreaTableCellProxy object
177 * @new_row_number: The new "row-number" property value
178 *
179 * Sets the "row-number" property of @fo_area to @new_row_number
180 **/
181 void
fo_area_table_cell_proxy_set_row_number(FoArea * fo_area,gint new_row_number)182 fo_area_table_cell_proxy_set_row_number (FoArea *fo_area,
183 gint new_row_number)
184 {
185 g_return_if_fail (fo_area != NULL);
186 g_return_if_fail (FO_IS_AREA_TABLE_CELL_PROXY (fo_area));
187
188 FO_AREA_TABLE_CELL_PROXY (fo_area)->row_number = new_row_number;
189 /* g_object_notify (G_OBJECT (fo_area), "row-number");*/
190 }
191
192 /**
193 * fo_area_table_cell_proxy_get_row_number:
194 * @fo_area: The #FoAreaTableCellProxy object
195 *
196 * Gets the 'row-number' property of @area_table_cell_proxy
197 *
198 * Return value: The "row-number" property value
199 **/
200 gint
fo_area_table_cell_proxy_get_row_number(FoArea * fo_area)201 fo_area_table_cell_proxy_get_row_number (FoArea *fo_area)
202 {
203 g_return_val_if_fail (fo_area != NULL, 0);
204 g_return_val_if_fail (FO_IS_AREA_TABLE_CELL_PROXY (fo_area), 0);
205
206 return FO_AREA_TABLE_CELL_PROXY (fo_area)->row_number;
207 }
208
209 /**
210 * fo_area_table_cell_proxy_set_min_height:
211 * @fo_area: The #FoAreaTableCellProxy object
212 * @new_min_height: The new "min-height" property value
213 *
214 * Sets the "min-height" property of @fo_area to @new_min_height
215 **/
216 void
fo_area_table_cell_proxy_set_min_height(FoArea * fo_area,gdouble new_min_height)217 fo_area_table_cell_proxy_set_min_height (FoArea *fo_area,
218 gdouble new_min_height)
219 {
220 g_return_if_fail (fo_area != NULL);
221 g_return_if_fail (FO_IS_AREA_TABLE_CELL_PROXY (fo_area));
222
223 FO_AREA_TABLE_CELL_PROXY (fo_area)->min_height = new_min_height;
224 /* g_object_notify (G_OBJECT (fo_area), "min-height");*/
225 }
226
227 /**
228 * fo_area_table_cell_proxy_get_min_height:
229 * @fo_area: The #FoAreaTableCellProxy object
230 *
231 * Gets the 'min-height' property of @fo_area
232 *
233 * Return value: The "min-height" property value
234 **/
235 gdouble
fo_area_table_cell_proxy_get_min_height(FoArea * fo_area)236 fo_area_table_cell_proxy_get_min_height (FoArea *fo_area)
237 {
238 g_return_val_if_fail (fo_area != NULL, 0);
239 g_return_val_if_fail (FO_IS_AREA_TABLE_CELL_PROXY (fo_area), 0);
240
241 return FO_AREA_TABLE_CELL_PROXY (fo_area)->min_height;
242 }
243
244 /**
245 * fo_area_table_cell_proxy_debug_dump_properties:
246 * @area: The #FoArea object
247 * @depth: Indent level to add to the output
248 *
249 * Logs the value of each significant property of @area then calls
250 * debug_dump_properties method of parent class.
251 **/
252 void
fo_area_table_cell_proxy_debug_dump_properties(FoArea * area,gint depth)253 fo_area_table_cell_proxy_debug_dump_properties (FoArea *area, gint depth)
254 {
255 FoAreaTableCellProxy *table_cell_proxy;
256 gchar *indent = g_strnfill (depth * 2, ' ');
257 gchar *string;
258
259 g_return_if_fail (area != NULL);
260 g_return_if_fail (FO_IS_AREA_TABLE_CELL_PROXY (area));
261
262 table_cell_proxy = FO_AREA_TABLE_CELL_PROXY (area);
263
264 string = fo_object_debug_sprintf (table_cell_proxy->table_cell);
265 g_log (G_LOG_DOMAIN,
266 G_LOG_LEVEL_DEBUG,
267 "%stable-cell area: %s",
268 indent,
269 string);
270 g_free (string);
271
272 g_log (G_LOG_DOMAIN,
273 G_LOG_LEVEL_DEBUG,
274 "%srow-number: %d",
275 indent,
276 table_cell_proxy->row_number);
277
278 g_free (indent);
279 FO_AREA_CLASS (parent_class)->debug_dump_properties (area, depth + 1);
280 }
281
282 /**
283 * fo_area_table_cell_proxy_size_request:
284 * @child: Child area
285 *
286 * Check that the parent area of @child has sufficient space for
287 * @child. If not enough space, request that the parent has
288 * sufficient space allocated for it, then adjust @child and its
289 * siblings as necessary to fit into the resized parent area.
290 *
291 * Return value: Pointer to the last area generated from @child after
292 * any reallocation and resizing
293 **/
294 FoArea*
fo_area_table_cell_proxy_size_request(FoArea * child)295 fo_area_table_cell_proxy_size_request (FoArea *child)
296 {
297 FoArea *use_child_area;
298 FoArea *parent;
299 FoDatatype *fo_row_bpdim;
300 gdouble max_child_height = 0;
301 gdouble parent_child_available_bpdim;
302 gdouble parent_use_height = 0;
303 gdouble child_height;
304
305 g_return_val_if_fail (child != NULL, NULL);
306 g_return_val_if_fail (FO_IS_AREA_AREA (child), NULL);
307 g_return_val_if_fail (!FO_AREA_IS_ROOT (child), NULL);
308 g_return_val_if_fail (fo_area_parent (child) != NULL, NULL);
309 g_return_val_if_fail (FO_IS_AREA_TABLE_CELL_PROXY (fo_area_parent (child)), NULL);
310
311 child_height = fo_area_area_get_height (child);
312
313 parent = fo_area_parent (child);
314 parent_child_available_bpdim = fo_area_get_child_available_bpdim (parent);
315
316 if (child_height <= parent_child_available_bpdim)
317 {
318 fo_area_set_available_height (child, parent_child_available_bpdim);
319 return child;
320 }
321
322 use_child_area = fo_area_first_child (parent);
323
324 while (use_child_area)
325 {
326 max_child_height =
327 MAX (max_child_height,
328 fo_area_area_get_height (use_child_area));
329 use_child_area = fo_area_next_sibling (use_child_area);
330 }
331
332 fo_row_bpdim =
333 fo_property_get_value (fo_table_cell_get_block_progression_dimension (parent->generated_by));
334
335 if (FO_IS_LENGTH_RANGE (fo_row_bpdim))
336 {
337 FoDatatype *min_datatype = fo_length_range_get_minimum (fo_row_bpdim);
338 FoDatatype *opt_datatype = fo_length_range_get_optimum (fo_row_bpdim);
339 FoDatatype *max_datatype = fo_length_range_get_maximum (fo_row_bpdim);
340
341 if (FO_IS_LENGTH (min_datatype) &&
342 max_child_height <= fo_length_get_value (min_datatype))
343 {
344 parent_use_height = fo_length_get_value (min_datatype);
345
346 #if defined(LIBFO_DEBUG) && 0
347 g_message ("table_cell_proxy_size_request:: child: %g; min: %g",
348 max_child_height,
349 fo_length_get_value (min_datatype));
350 #endif
351 }
352 else if (FO_IS_LENGTH (opt_datatype) &&
353 fo_length_get_value (opt_datatype) < max_child_height)
354 {
355 parent_use_height = fo_length_get_value (opt_datatype);
356
357 #if defined(LIBFO_DEBUG) && 0
358 g_message ("table_cell_proxy_size_request:: child: %g; opt: %g",
359 max_child_height,
360 fo_length_get_value (opt_datatype));
361 #endif
362 }
363 else if (FO_IS_LENGTH (max_datatype) &&
364 fo_length_get_value (max_datatype) < max_child_height)
365 {
366 parent_use_height = fo_length_get_value (max_datatype);
367
368 #if defined(LIBFO_DEBUG) && 0
369 g_message ("table_cell_proxy_size_request:: child: %g; max: %g",
370 max_child_height,
371 fo_length_get_value (max_datatype));
372 #endif
373 }
374 else
375 {
376 parent_use_height = max_child_height;
377 }
378 }
379 else
380 {
381 g_assert_not_reached ();
382 }
383
384 if (parent_child_available_bpdim < parent_use_height)
385 {
386 fo_area_area_set_height (parent, parent_use_height);
387 parent = fo_area_size_request (parent);
388 parent_child_available_bpdim = fo_area_get_child_available_bpdim (parent);
389 }
390
391 use_child_area = fo_area_first_child (parent);
392 max_child_height = 0;
393
394 while (use_child_area)
395 {
396 max_child_height =
397 MAX (max_child_height,
398 fo_area_area_get_height (use_child_area));
399 use_child_area = fo_area_next_sibling (use_child_area);
400 }
401
402 if (max_child_height <= parent_child_available_bpdim)
403 {
404 use_child_area = fo_area_first_child (parent);
405
406 while (use_child_area)
407 {
408 fo_area_set_available_height (use_child_area,
409 parent_child_available_bpdim);
410 use_child_area = fo_area_next_sibling (use_child_area);
411 }
412
413 /* FIXME: Should this be last area in FO's glist of areas?
414 Currently is *not* the last area of child unless child is
415 the last child of parent (which is only true when child
416 appended to parent). */
417 return fo_area_last_child (parent);
418 }
419 else
420 {
421 use_child_area = fo_area_first_child (parent);
422
423 while (use_child_area)
424 {
425 if (fo_area_area_get_height (use_child_area) <=
426 parent_child_available_bpdim)
427 {
428 fo_area_set_available_height (use_child_area,
429 parent_child_available_bpdim);
430
431 use_child_area = fo_area_next_sibling (use_child_area);
432 }
433 else
434 {
435 use_child_area =
436 fo_area_split_before_height (use_child_area,
437 parent_child_available_bpdim);
438 parent = fo_area_parent (use_child_area);
439 parent_child_available_bpdim = fo_area_get_child_available_bpdim (parent);
440
441 /* Don't change use_child_area since need to test
442 again against parent_child_available_bpdim. */
443 }
444 }
445 return fo_area_last_child (parent);
446 }
447 }
448
449 /* return the new area containing what comes after the split */
450 /* leave @area as area remaining after split */
451 FoArea*
fo_area_table_cell_proxy_split_before_height(FoArea * area,gdouble max_height)452 fo_area_table_cell_proxy_split_before_height (FoArea *area,
453 gdouble max_height)
454 {
455 FoArea *use_child_area;
456 gboolean can_split = TRUE;
457
458 g_return_val_if_fail (FO_IS_AREA_TABLE_CELL_PROXY (area), NULL);
459 g_return_val_if_fail (fo_area_n_children (area) > 0, NULL);
460 g_return_val_if_fail (max_height > 0, NULL);
461
462 use_child_area = fo_area_first_child (area);
463
464 while (use_child_area && can_split)
465 {
466 gdouble child_height = fo_area_area_get_height (use_child_area);
467
468 can_split &= ((child_height <= max_height) ||
469 fo_area_split_before_height_check (use_child_area,
470 max_height));
471
472 use_child_area = fo_area_next_sibling (use_child_area);
473 }
474
475 if (can_split)
476 {
477 FoArea *split_child;
478 FoArea *clone = fo_area_clone (area);
479 gdouble max_remaining_child_height = 0;
480 gdouble max_split_child_height = 0;
481
482 area->is_last = FALSE;
483
484 clone->is_first = FALSE;
485 ((FoAreaArea *)clone)->border_before = 0;
486
487 use_child_area = fo_area_first_child (area);
488
489 while (use_child_area)
490 {
491 split_child = fo_area_split_before_height (use_child_area,
492 max_height);
493
494 fo_area_unlink (split_child);
495 fo_area_append (clone, split_child);
496
497 max_remaining_child_height =
498 MAX (max_remaining_child_height,
499 fo_area_area_get_height (use_child_area));
500 max_split_child_height =
501 MAX (max_split_child_height,
502 fo_area_area_get_height (split_child));
503
504 use_child_area = fo_area_next_sibling (use_child_area);
505 }
506
507 fo_area_area_set_height (area, max_remaining_child_height);
508 fo_area_area_set_height (clone, max_split_child_height);
509
510 /*
511 fo_area_size_request (area);
512 fo_area_size_request (clone);
513 */
514
515 return clone;
516 }
517 else
518 {
519 return NULL;
520 }
521 }
522 /* return the new area containing what comes after the split */
523 /* leave @area as area remaining after split */
524 gboolean
fo_area_table_cell_proxy_split_before_height_check(FoArea * area,gdouble max_height)525 fo_area_table_cell_proxy_split_before_height_check (FoArea *area,
526 gdouble max_height)
527 {
528 FoArea *use_child_area;
529 gboolean can_split = TRUE;
530
531 g_return_val_if_fail (FO_IS_AREA_TABLE_CELL_PROXY (area), FALSE);
532 g_return_val_if_fail (fo_area_n_children (area) > 0, FALSE);
533 g_return_val_if_fail (max_height > 0, FALSE);
534
535 use_child_area = fo_area_first_child (area);
536
537 while (use_child_area && can_split)
538 {
539 gdouble child_height = fo_area_area_get_height (use_child_area);
540
541 can_split &= ((child_height <= max_height) ||
542 fo_area_split_before_height_check (use_child_area,
543 max_height));
544
545 use_child_area = fo_area_next_sibling (use_child_area);
546 }
547
548 return can_split;
549 }
550