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