1 /* Fo
2 * fo-block-area.c: Block formatting object area creation
3 *
4 * Copyright (C) 2001 Sun Microsystems
5 * Copyright (C) 2007-2010 Menteith Consulting Ltd
6 *
7 * See COPYING for the status of this software.
8 */
9
10 #include <fo-inline-fo.h>
11 #include <area/fo-area-area.h>
12 #include <area/fo-area-layout.h>
13 #include <fo-text.h>
14 #include <fo-block-area.h>
15 #include <fo-block-private.h>
16 #include "property/fo-property-common-font.h"
17 #include "property/fo-property-text-property.h"
18 #include <property/fo-property-background-color.h>
19 #include <property/fo-property-dominant-baseline.h>
20 #include <property/fo-property-baseline-shift.h>
21 #include "property/fo-property-font-family.h"
22 #include "property/fo-property-font-size.h"
23 #include "property/fo-property-font-stretch.h"
24 #include <property/fo-property-space-after.h>
25 #include <property/fo-property-space-before.h>
26 #include <libfo/fo-doc.h>
27 #include <libfo/fo-doc-commands.h>
28 #include <libfo/fo-layout-private.h>
29
30 #if 0
31 static void
32 _debug_dump_item (gpointer data,
33 gpointer user_data)
34 {
35 const PangoItem *item = (const PangoItem *) data;
36 const PangoEngine *engine = (const PangoEngine *) item->analysis.shape_engine;
37 PangoFontDescription *font_desc = pango_font_describe (item->analysis.font);
38
39 g_log (G_LOG_DOMAIN,
40 G_LOG_LEVEL_DEBUG,
41 "dump_item:: offset: %d", item->offset);
42 g_log (G_LOG_DOMAIN,
43 G_LOG_LEVEL_DEBUG,
44 "dump_item:: length: %d", item->length);
45 g_log (G_LOG_DOMAIN,
46 G_LOG_LEVEL_DEBUG,
47 "dump_item:: num_chars: %d", item->num_chars);
48 g_log (G_LOG_DOMAIN,
49 G_LOG_LEVEL_DEBUG,
50 "dump_item:: shape_engine: %p", item->analysis.shape_engine);
51 g_log (G_LOG_DOMAIN,
52 G_LOG_LEVEL_DEBUG,
53 "dump_item:: shape_engine: %s", engine->id);
54 g_log (G_LOG_DOMAIN,
55 G_LOG_LEVEL_DEBUG,
56 "dump_item:: lang_engine: %p", item->analysis.lang_engine);
57 g_log (G_LOG_DOMAIN,
58 G_LOG_LEVEL_DEBUG,
59 "dump_item:: font: %p", item->analysis.font);
60 g_log (G_LOG_DOMAIN,
61 G_LOG_LEVEL_DEBUG,
62 "dump_item:: font: %s", pango_font_description_to_string (font_desc));
63 }
64
65 static void
66 _debug_dump_item_glist (GList *item_glist)
67 {
68 g_list_foreach (item_glist,
69 fo_block_debug_dump_item,
70 NULL);
71 }
72
73 static gint
74 _glist_find_attr_type (gpointer pango_attr, gpointer attr_klass)
75 {
76 /*
77 g_log (G_LOG_DOMAIN,
78 G_LOG_LEVEL_DEBUG,
79 "find_attr_type:: attr: %p; klass: %d", pango_attr, GPOINTER_TO_INT (attr_klass));
80 */
81 if (((PangoAttribute *) pango_attr)->klass->type == GPOINTER_TO_INT (attr_klass))
82 {
83 return 0;
84 }
85 else
86 {
87 return -1;
88 }
89 }
90 #endif
91
92 static void
fo_block_area_get_text_attr_list2(FoFo * parent_fo,FoDoc * fo_doc,GString * text,GList ** attr_glist,guint debug_level)93 fo_block_area_get_text_attr_list2 (FoFo *parent_fo,
94 FoDoc *fo_doc,
95 GString *text,
96 GList **attr_glist,
97 guint debug_level)
98 {
99 FoNode *fo_child_node;
100 const FoBlock *fo_block = (const FoBlock *) parent_fo;
101 gint start_index, end_index;
102
103 start_index = text->len;
104
105 fo_child_node = fo_node_first_child (FO_NODE (parent_fo));
106
107 while (fo_child_node)
108 {
109 fo_inline_fo_get_text_attr_list (FO_FO (fo_child_node),
110 fo_doc,
111 text,
112 attr_glist,
113 debug_level);
114 fo_child_node = fo_node_next_sibling (fo_child_node);
115 }
116
117 end_index = text->len;
118
119 if (start_index != end_index)
120 {
121 PangoAttribute *pango_attr;
122
123 *attr_glist =
124 g_list_concat (fo_property_common_font_get_pango_attrs (fo_block->font_family,
125 fo_block->font_size,
126 fo_block->font_stretch,
127 fo_block->font_style,
128 fo_block->font_variant,
129 fo_block->font_weight,
130 start_index,
131 end_index),
132 *attr_glist);
133 /*
134 pango_attr =
135 fo_property_text_property_new_attr (fo_block->line_height);
136 pango_attr->start_index = start_index;
137 pango_attr->end_index = end_index;
138 *attr_glist = g_list_prepend (*attr_glist, pango_attr);
139 */
140 pango_attr =
141 fo_property_text_property_new_attr (fo_block->color);
142 pango_attr->start_index = start_index;
143 pango_attr->end_index = end_index;
144 *attr_glist = g_list_prepend (*attr_glist, pango_attr);
145
146 if (FO_IS_COLOR (fo_property_get_value (fo_block->background_color)))
147 {
148 pango_attr =
149 fo_property_text_property_new_attr (fo_block->background_color);
150 pango_attr->start_index = start_index;
151 pango_attr->end_index = end_index;
152 *attr_glist = g_list_prepend (*attr_glist, pango_attr);
153 }
154 /*
155 pango_attr =
156 fo_property_text_property_new_attr (fo_block->keep_together_within_line);
157 pango_attr->start_index = start_index;
158 pango_attr->end_index = end_index;
159 *attr_glist = g_list_prepend (*attr_glist, pango_attr);
160
161 pango_attr =
162 fo_property_text_property_new_attr (fo_block->keep_with_next_within_line);
163 pango_attr->start_index = start_index;
164 pango_attr->end_index = end_index;
165 *attr_glist = g_list_prepend (*attr_glist, pango_attr);
166
167 pango_attr =
168 fo_property_text_property_new_attr (fo_block->keep_with_previous_within_line);
169 pango_attr->start_index = start_index;
170 pango_attr->end_index = end_index;
171 *attr_glist = g_list_prepend (*attr_glist, pango_attr);
172 */
173 }
174
175 #if defined(LIBFO_DEBUG) && 0
176 g_log (G_LOG_DOMAIN,
177 G_LOG_LEVEL_DEBUG,
178 "block_area_new2:: text: %s",
179 text->str);
180 if (*attr_glist)
181 {
182 PangoAttrList *attr_list = pango_attr_list_new ();
183 g_list_foreach (*attr_glist,
184 fo_block_area_pango_attr_list_add,
185 attr_list);
186 fo_block_debug_dump_attr_list (attr_list);
187 }
188 #endif
189 }
190
191 void
fo_block_area_new(FoFo * block,FoDoc * fo_doc,FoArea * parent_area,FoArea ** new_area,guint debug_level)192 fo_block_area_new (FoFo *block,
193 FoDoc *fo_doc,
194 FoArea *parent_area,
195 FoArea **new_area,
196 guint debug_level)
197 {
198 g_return_if_fail (block != NULL);
199 g_return_if_fail (FO_IS_BLOCK (block));
200 g_return_if_fail (FO_IS_DOC (fo_doc));
201
202 gfloat parent_child_available_ipdim =
203 fo_area_get_child_available_ipdim (parent_area);
204 gfloat x = fo_area_get_next_x (parent_area);
205 gfloat y = fo_area_get_next_y (parent_area);
206
207 gfloat border_start_width =
208 fo_length_get_value (fo_property_get_value (fo_block_get_border_start_width (block)));
209 gfloat border_end_width =
210 fo_length_get_value (fo_property_get_value (fo_block_get_border_end_width (block)));
211 gfloat border_before_width =
212 fo_length_get_value (fo_property_get_value (fo_block_get_border_before_width (block)));
213 gfloat border_after_width =
214 fo_length_get_value (fo_property_get_value (fo_block_get_border_after_width (block)));
215
216 gfloat padding_start =
217 fo_length_get_value (fo_property_get_value (fo_block_get_padding_start (block)));
218 gfloat padding_end =
219 fo_length_get_value (fo_property_get_value (fo_block_get_padding_end (block)));
220 gfloat padding_before =
221 fo_length_get_value (fo_property_get_value (fo_block_get_padding_before (block)));
222 gfloat padding_after =
223 fo_length_get_value (fo_property_get_value (fo_block_get_padding_after (block)));
224
225 FoDatatype *start_indent_datatype =
226 fo_property_get_value (fo_block_get_start_indent (block));
227 gfloat start_indent;
228 if (FO_IS_LENGTH (start_indent_datatype))
229 {
230 start_indent = fo_length_get_value (start_indent_datatype);
231 }
232 else
233 {
234 start_indent =
235 fo_percentage_get_value (start_indent_datatype) * 0.01 *
236 fo_area_area_get_width (parent_area);
237 #if defined(LIBFO_DEBUG) && 0
238 g_log (G_LOG_DOMAIN,
239 G_LOG_LEVEL_DEBUG,
240 "get_text_attr_list:: start-indent: %f, parent width: %f",
241 fo_percentage_get_value (start_indent_datatype),
242 fo_area_area_get_width (parent_area));
243 #endif
244 }
245 FoDatatype *end_indent_datatype =
246 fo_property_get_value (fo_block_get_end_indent (block));
247 gfloat end_indent;
248 if (FO_IS_LENGTH (end_indent_datatype))
249 {
250 end_indent = fo_length_get_value (end_indent_datatype);
251 }
252 else
253 {
254 end_indent =
255 fo_percentage_get_value (end_indent_datatype) * 0.01 *
256 fo_area_area_get_width (parent_area);
257 #if defined(LIBFO_DEBUG) && 0
258 g_log (G_LOG_DOMAIN,
259 G_LOG_LEVEL_DEBUG,
260 "get_text_attr_list:: end-indent: %f, parent width: %f",
261 fo_percentage_get_value (end_indent_datatype),
262 fo_area_area_get_width (parent_area));
263 #endif
264 }
265
266 gfloat layout_width =
267 parent_child_available_ipdim -
268 (border_start_width + border_end_width + padding_start + padding_end +
269 start_indent + end_indent);
270
271 FoFontDesc *font_desc =
272 fo_font_desc_copy (fo_doc_get_font_desc (fo_doc));
273
274 gchar *font_family =
275 fo_string_get_value (fo_property_get_value (fo_block_get_font_family (block)));
276 fo_font_desc_set_family (font_desc, font_family);
277 g_free (font_family);
278
279 fo_font_desc_set_size (font_desc,
280 fo_length_get_value (fo_property_get_value (fo_block_get_font_size (block))));
281 fo_font_desc_set_weight (font_desc,
282 fo_integer_get_value (fo_property_get_value (fo_block_get_font_weight (block))));
283 fo_font_desc_set_style (font_desc,
284 fo_enum_get_value (fo_property_get_value (fo_block_get_font_style (block))));
285 fo_font_desc_set_stretch (font_desc,
286 fo_enum_get_value (fo_property_get_value (fo_block_get_font_stretch (block))));
287 fo_font_desc_set_variant (font_desc,
288 fo_enum_get_value (fo_property_get_value (fo_block_get_font_variant (block))));
289
290 FoLayout *fo_layout = fo_doc_get_new_layout (fo_doc);
291 fo_layout_set_width (fo_layout,
292 layout_width);
293
294 fo_layout_set_line_stacking_strategy (fo_layout,
295 fo_enum_get_value (fo_property_get_value (fo_block_get_line_stacking_strategy (block))));
296 fo_layout_set_font_desc (fo_layout,
297 font_desc);
298
299 gfloat line_height =
300 fo_length_get_value (fo_property_get_value (fo_block_get_line_height (block)));
301 fo_layout_set_line_height (fo_layout,
302 line_height);
303
304 /* FIXME: should be FO-specific dir enum */
305 PangoDirection base_dir = fo_doc_get_base_dir (fo_doc);
306 fo_layout_set_alignment (fo_layout,
307 base_dir);
308
309 gfloat text_indent =
310 fo_length_get_value (fo_property_get_value (fo_block_get_text_indent (block)));
311 fo_layout_set_indent (fo_layout,
312 text_indent);
313 /*
314 FIXME: Pango does not justify.
315 fo_layout_set_justify (pango_layout, TRUE);
316 */
317 GString *text = g_string_new (NULL);
318 GList *attr_glist = NULL;
319 fo_block_area_get_text_attr_list2 (FO_FO (block),
320 fo_doc,
321 text,
322 &attr_glist,
323 debug_level);
324 fo_layout_set_text (fo_layout,
325 text);
326 fo_layout_set_attributes (fo_layout,
327 attr_glist);
328
329 if (debug_level & FO_DEBUG_PANGO)
330 {
331 g_log (G_LOG_DOMAIN,
332 G_LOG_LEVEL_DEBUG,
333 "get_text_attr_list:: block text: '%s'", (gchar *) text->str);
334 g_log (G_LOG_DOMAIN,
335 G_LOG_LEVEL_DEBUG,
336 "get_text_attr_list:: attr_glist: %p", attr_glist);
337 g_log (G_LOG_DOMAIN,
338 G_LOG_LEVEL_DEBUG,
339 "get_text_attr_list:: attr_glist length: %d", g_list_length (attr_glist));
340
341 fo_object_debug_dump (fo_layout, 0);
342 }
343
344 *new_area = g_object_ref_sink (fo_area_layout_new_with_layout (fo_layout));
345
346 FoRectangle logical;
347 fo_layout_get_extents (fo_layout,
348 &logical);
349
350 fo_area_area_set_height (*new_area,
351 logical.height / PANGO_SCALE +
352 border_before_width + padding_before +
353 border_after_width + padding_after);
354
355 fo_area_area_set_width (*new_area,
356 MAX (parent_child_available_ipdim -
357 start_indent -
358 end_indent,
359 0));
360 fo_area_area_set_x (*new_area, x + start_indent);
361 fo_area_area_set_y (*new_area, y);
362 fo_area_area_set_border_after (*new_area, border_after_width);
363 fo_area_area_set_border_before (*new_area, border_before_width);
364 fo_area_area_set_border_end (*new_area, border_end_width);
365 fo_area_area_set_border_start (*new_area, border_start_width);
366 fo_area_area_set_padding_before (*new_area, padding_before);
367 fo_area_area_set_padding_end (*new_area, padding_end);
368 fo_area_area_set_padding_after (*new_area, padding_after);
369 fo_area_area_set_padding_start (*new_area, padding_start);
370 fo_area_area_set_start_indent (*new_area, start_indent);
371 fo_area_area_set_end_indent (*new_area, end_indent);
372 gfloat space_before =
373 fo_length_get_value (fo_property_get_value (fo_block_get_space_before (block)));
374 fo_area_area_set_space_before (*new_area, space_before);
375 gfloat space_after =
376 fo_length_get_value (fo_property_get_value (fo_block_get_space_after (block)));
377 fo_area_area_set_space_after (*new_area, space_after);
378 fo_area_set_generated_by (*new_area,
379 block);
380 fo_fo_area_list_append (block,
381 *new_area);
382
383 g_object_unref (font_desc);
384 }
385
386 void
fo_block_area_new3(FoFo * block,FoDoc * fo_doc,FoArea * parent_area,FoArea ** new_area,guint debug_level)387 fo_block_area_new3 (FoFo *block,
388 FoDoc *fo_doc,
389 FoArea *parent_area,
390 FoArea **new_area,
391 guint debug_level)
392 {
393 #if defined(LIBFO_DEBUG) && 0
394 g_log (G_LOG_DOMAIN,
395 G_LOG_LEVEL_DEBUG,
396 "block_area_new3:: *** block parent before adding block:");
397 fo_object_debug_dump (parent_area, 0);
398 g_log (G_LOG_DOMAIN,
399 G_LOG_LEVEL_DEBUG,
400 "block_area_new3:: *** end block parent");
401 #endif
402
403 fo_block_area_new (block,
404 fo_doc,
405 parent_area,
406 new_area,
407 debug_level);
408 fo_area_add_child (parent_area, *new_area);
409 *new_area = fo_area_size_request (*new_area);
410 fo_area_resolve_text_align (*new_area);
411
412 #if defined(LIBFO_DEBUG) && 0
413 g_log (G_LOG_DOMAIN,
414 G_LOG_LEVEL_DEBUG,
415 "block_area_new3:: *new_area: %s; generated by: %s; parent: %s; generated by: %s",
416 fo_object_debug_sprintf (*new_area),
417 fo_object_debug_sprintf ((*new_area)->generated_by),
418 fo_object_debug_sprintf (fo_area_parent (*new_area)),
419 fo_object_debug_sprintf (fo_area_parent (*new_area->generated_by)));
420 #endif
421
422 #if defined(LIBFO_DEBUG) && 0
423 g_log (G_LOG_DOMAIN,
424 G_LOG_LEVEL_DEBUG,
425 "block_area_new3:: *** block parent after adding block:");
426 fo_object_debug_dump (parent_area, 0);
427 g_log (G_LOG_DOMAIN,
428 G_LOG_LEVEL_DEBUG,
429 "block_area_new3:: *** end block parent");
430 #endif
431 }
432
433 void
fo_block_area_new2(FoFo * fo_node,FoFoAreaNew2Context * context,GError ** error)434 fo_block_area_new2 (FoFo *fo_node,
435 FoFoAreaNew2Context *context,
436 GError **error)
437 {
438 g_return_if_fail (FO_IS_FO (fo_node));
439 g_return_if_fail (context != NULL);
440 g_return_if_fail (error == NULL || *error == NULL);
441
442 fo_block_area_new (fo_node,
443 context->fo_doc,
444 context->parent_area,
445 context->new_area,
446 context->debug_level);
447 #if defined(LIBFO_DEBUG) && 0
448 fo_object_debug_dump (*(context->new_area), 0);
449 #endif
450 fo_area_add_child (context->parent_area, *(context->new_area));
451 *(context->new_area) = fo_area_size_request (*(context->new_area));
452 fo_area_resolve_text_align (*(context->new_area));
453 }
454