1 /* Fo
2  * area-to-pdf.c: Convert area tree into PDF
3  *
4  * Copyright (C) 2001-2005 Sun Microsystems
5  * Copyright (C) 2007-2009 Menteith Consulting Ltd
6  *
7  * See COPYING for the status of this software.
8  */
9 
10 
11 #include <string.h>
12 #include "area-to-pdf.h"
13 #include "area/fo-all-area.h"
14 #include "area/fo-area-table-continuation-private.h"
15 #include "property/fo-property-border.h"
16 #include "property/fo-property-border-bottom-style.h"
17 #include "property/fo-property-border-left-style.h"
18 #include "property/fo-property-border-right-style.h"
19 #include "property/fo-property-border-top-style.h"
20 #include "property/fo-property-color.h"
21 #include "property/fo-property-font-size.h"
22 #include "fo/fo-cbpbp-fo.h"
23 
24 
25 typedef struct
26 {
27   gdouble x1;	  /* X-coordinate of one corner. */
28   gdouble y1;	  /* Y-coordinate of one corner. */
29   gdouble x2;	  /* X-coordinate of the opposite corner. */
30   gdouble y2;	  /* Y-coordinate of the opposite corder. */
31   gdouble x1delta; /* Relative x-offset of interior corner nearest (x1,y1). */
32   gdouble y1delta; /* Relative y-offset of interior corner nearest (x1,y1). */
33   gdouble x2delta; /* Relative x-offset of interior corner nearest (x2,y2). */
34   gdouble y2delta; /* Relative y-offset of interior corner nearest (x2,y2). */
35 } FoPdfOneBorderCoords;
36 
37 /**
38  * fo_pdf_draw_background:
39  * @fo_doc: #FoDoc
40  * @x:      X-coordinate of top-left corner.
41  * @y:      Y-coordinate of top-left corner.
42  * @width:  Width of background area
43  * @height: Height of background area
44  * @background_color: Background color, or an #FoEnum if background is
45  *                    transparent.
46  *
47  * If @background_color is an #FoColor, draw a rectangle of the
48  * background color with top-left corner at (@x, @y) with width @width
49  * and height @height.
50  **/
51 static void
fo_pdf_draw_background(FoDoc * fo_doc,gdouble x,gdouble y,gdouble width,gdouble height,FoDatatype * background_color)52 fo_pdf_draw_background (FoDoc *fo_doc,
53 			gdouble x,
54 			gdouble y,
55 			gdouble width,
56 			gdouble height,
57 			FoDatatype *background_color)
58 {
59 
60 #if defined(LIBFO_DEBUG) && 0
61   g_message ("draw_background:: x: %f; y; %f; width: %f; height: %f",
62 	     x,
63 	     y,
64 	     width,
65 	     height);
66   fo_object_debug_dump (background_color, 0);
67 #endif
68 
69   if (FO_IS_COLOR (background_color))
70     {
71       fo_doc_set_fill_color (fo_doc,
72 			     background_color);
73 
74       fo_doc_rect_filled (fo_doc,
75 			  x,
76 			  y - height,
77 			  width,
78 			  height);
79     }
80 }
81 
82 /**
83  * fo_pdf_clip_to_coords:
84  * @fo_doc: #FoDoc.
85  * @coords: Coordinates of one border of an area.
86  *
87  * Clip the drawing area of @fo_doc to @coords
88  **/
89 static void
fo_pdf_clip_to_coords(FoDoc * fo_doc,FoPdfOneBorderCoords * coords)90 fo_pdf_clip_to_coords (FoDoc *fo_doc,
91 		       FoPdfOneBorderCoords *coords)
92 {
93   fo_doc_move_to (fo_doc,
94 		  coords->x1,
95 		  coords->y1);
96   fo_doc_line_to (fo_doc,
97 		  coords->x2,
98 		  coords->y2);
99   fo_doc_line_to (fo_doc,
100 		  coords->x2 + coords->x2delta,
101 		  coords->y2 + coords->y2delta);
102   fo_doc_line_to (fo_doc,
103 		  coords->x1 + coords->x1delta,
104 		  coords->y1 + coords->y1delta);
105   fo_doc_clip (fo_doc);
106 }
107 
108 /**
109  * fo_pdf_draw_border_two_tone_vertical:
110  * @fo_doc:      #FoDoc
111  * @inner_color: Color of the inner band
112  * @outer_color: Color of the outer band
113  * @coords:      Coordinates of one border of an area
114  *
115  * Draw a left or right two-tone border.
116  **/
117 static void
fo_pdf_draw_border_two_tone_vertical(FoDoc * fo_doc,FoDatatype * inner_color,FoDatatype * outer_color,FoPdfOneBorderCoords * coords)118 fo_pdf_draw_border_two_tone_vertical (FoDoc *fo_doc,
119 				      FoDatatype *inner_color,
120 				      FoDatatype *outer_color,
121 				      FoPdfOneBorderCoords *coords)
122 {
123   fo_doc_set_line_width (fo_doc,
124 			 ABS (coords->x1delta) / 2);
125 
126   fo_doc_set_stroke_color (fo_doc, outer_color);
127   fo_doc_move_to (fo_doc,
128 		  coords->x1 + coords->x1delta / 4.0,
129 		  coords->y1);
130   fo_doc_line_to (fo_doc,
131 		  coords->x2 + coords->x2delta / 4.0,
132 		  coords->y2);
133   fo_doc_stroke (fo_doc);
134 
135   fo_doc_set_stroke_color (fo_doc, inner_color);
136   fo_doc_move_to (fo_doc,
137 		  coords->x1 + 3.0 * coords->x1delta / 4.0,
138 		  coords->y1);
139   fo_doc_line_to (fo_doc,
140 		  coords->x2 + 3.0 * coords->x2delta / 4.0,
141 		  coords->y2);
142   fo_doc_stroke (fo_doc);
143 }
144 
145 /**
146  * fo_pdf_draw_border_two_tone_horizontal:
147  * @fo_doc:      #FoDoc
148  * @inner_color: Color of the inner band
149  * @outer_color: Color of the outer band
150  * @coords:      Coordinates of one border of an area
151  *
152  * Draw a top or bottom two-tone border.
153  **/
154 static void
fo_pdf_draw_border_two_tone_horizontal(FoDoc * fo_doc,FoDatatype * inner_color,FoDatatype * outer_color,FoPdfOneBorderCoords * coords)155 fo_pdf_draw_border_two_tone_horizontal (FoDoc *fo_doc,
156 					FoDatatype *inner_color,
157 					FoDatatype *outer_color,
158 					FoPdfOneBorderCoords *coords)
159 {
160   fo_doc_set_line_width (fo_doc,
161 			 ABS (coords->y1delta) / 2);
162 
163   fo_doc_set_stroke_color (fo_doc,
164 			   inner_color);
165   fo_doc_move_to (fo_doc,
166 		  coords->x1,
167 		  coords->y1 + 3.0 * coords->y1delta / 4.0);
168   fo_doc_line_to (fo_doc,
169 		  coords->x2,
170 		  coords->y2 + 3.0 * coords->y2delta / 4.0);
171   fo_doc_stroke (fo_doc);
172 
173   fo_doc_set_stroke_color (fo_doc,
174 			   outer_color);
175   fo_doc_move_to (fo_doc,
176 		  coords->x1,
177 		  coords->y1 + coords->y1delta / 4.0);
178   fo_doc_line_to (fo_doc,
179 		  coords->x2,
180 		  coords->y2 + coords->y2delta / 4.0);
181   fo_doc_stroke (fo_doc);
182 }
183 
184 /**
185  * fo_pdf_draw_border_solid:
186  * @fo_doc: #FoDoc
187  * @color:  Border color
188  * @coords: Coordinates of one border of an area
189  *
190  * Draw a solid border with color @color and coordinates @coords.
191  **/
192 static void
fo_pdf_draw_border_solid(FoDoc * fo_doc,FoDatatype * color,FoPdfOneBorderCoords * coords)193 fo_pdf_draw_border_solid (FoDoc *fo_doc,
194 			  FoDatatype *color,
195 			  FoPdfOneBorderCoords *coords)
196 {
197   fo_doc_set_fill_color (fo_doc,
198 			 color);
199 
200   fo_doc_move_to (fo_doc,
201 		  coords->x1,
202 		  coords->y1);
203   fo_doc_line_to (fo_doc,
204 		  coords->x2,
205 		  coords->y2);
206   fo_doc_line_to (fo_doc,
207 		  coords->x2 + coords->x2delta,
208 		  coords->y2 + coords->y2delta);
209   fo_doc_line_to (fo_doc,
210 		  coords->x1 + coords->x1delta,
211 		  coords->y1 + coords->y1delta);
212   fo_doc_fill (fo_doc);
213 }
214 
215 /**
216  * fo_pdf_draw_border_double:
217  * @fo_doc: #FoDoc
218  * @color:  Border color
219  * @coords: Coordinates of one border of an area
220  *
221  * Draw a double border with color @color and coordinates @coords.
222  **/
223 static void
fo_pdf_draw_border_double(FoDoc * fo_doc,FoDatatype * color,FoPdfOneBorderCoords * coords)224 fo_pdf_draw_border_double (FoDoc *fo_doc,
225 			   FoDatatype *color,
226 			   FoPdfOneBorderCoords *coords)
227 {
228   fo_doc_set_fill_color (fo_doc,
229 			 color);
230 
231   fo_doc_move_to (fo_doc,
232 		  coords->x1,
233 		  coords->y1);
234   fo_doc_line_to (fo_doc,
235 		  coords->x2,
236 		  coords->y2);
237   fo_doc_line_to (fo_doc,
238 		  coords->x2 + coords->x2delta / 3,
239 		  coords->y2 + coords->y2delta / 3);
240   fo_doc_line_to (fo_doc,
241 		  coords->x1 + coords->x1delta / 3,
242 		  coords->y1 + coords->y1delta / 3);
243   fo_doc_fill (fo_doc);
244 
245   fo_doc_move_to (fo_doc,
246 		  coords->x1 + 2 * coords->x1delta / 3,
247 		  coords->y1 + 2 * coords->y1delta / 3);
248   fo_doc_line_to (fo_doc,
249 		  coords->x2 + 2 * coords->x2delta / 3,
250 		  coords->y2 + 2 * coords->y2delta / 3);
251   fo_doc_line_to (fo_doc,
252 		  coords->x2 + coords->x2delta,
253 		  coords->y2 + coords->y2delta);
254   fo_doc_line_to (fo_doc,
255 		  coords->x1 + coords->x1delta,
256 		  coords->y1 + coords->y1delta);
257   fo_doc_fill (fo_doc);
258 }
259 
260 /**
261  * fo_pdf_draw_border_dotted:
262  * @fo_doc: #FoDoc
263  * @color:  Border color
264  * @coords: Coordinates of one border of an area
265  *
266  * Draw a dotted border with color @color and coordinates @coords.
267  **/
268 static void
fo_pdf_draw_border_dotted(FoDoc * fo_doc,FoDatatype * color,FoPdfOneBorderCoords * coords)269 fo_pdf_draw_border_dotted (FoDoc *fo_doc,
270 			   FoDatatype *color,
271 			   FoPdfOneBorderCoords *coords)
272 {
273   fo_doc_set_stroke_color (fo_doc,
274 			   color);
275 
276 /*  fo_doc_set_line_cap (fo_doc,
277     FO_DOC_LINE_CAP_ROUND);*/ /* round end caps */
278 
279   fo_doc_move_to (fo_doc,
280 		  coords->x1,
281 		  coords->y1);
282   fo_doc_line_to (fo_doc,
283 		  coords->x2,
284 		  coords->y2);
285   fo_doc_line_to (fo_doc,
286 		  coords->x2 + coords->x2delta,
287 		  coords->y2 + coords->y2delta);
288   fo_doc_line_to (fo_doc,
289 		  coords->x1 + coords->x1delta,
290 		  coords->y1 + coords->y1delta);
291   fo_doc_clip (fo_doc);
292 
293   if (coords->x1 == coords->x2)
294     { /* vertical */
295       fo_doc_set_dash (fo_doc,
296 		       ABS (coords->x1delta),
297 		       ABS (coords->x1delta));
298       fo_doc_set_line_width (fo_doc,
299 			     ABS (coords->x1delta));
300 
301       fo_doc_move_to (fo_doc,
302 		      coords->x1 + coords->x1delta / 2,
303 		      coords->y1);
304       fo_doc_line_to (fo_doc,
305 		      coords->x2 + coords->x2delta / 2,
306 		      coords->y2);
307     }
308   else
309     { /* horizontal */
310       fo_doc_set_dash (fo_doc,
311 		       ABS (coords->y1delta),
312 		       ABS (coords->y1delta));
313       fo_doc_set_line_width (fo_doc,
314 			     ABS (coords->y1delta));
315 
316       fo_doc_move_to (fo_doc,
317 		      coords->x1,
318 		      coords->y1 + coords->y1delta / 2);
319       fo_doc_line_to (fo_doc,
320 		      coords->x2,
321 		      coords->y2 + coords->y2delta / 2);
322     }
323 
324   fo_doc_stroke (fo_doc);
325 }
326 
327 /**
328  * fo_pdf_draw_border_dashed:
329  * @fo_doc: #FoDoc
330  * @color:  Border color
331  * @coords: Coordinates of one border of an area
332  *
333  * Draw a dashed border with color @color and coordinates @coords.
334  **/
335 static void
fo_pdf_draw_border_dashed(FoDoc * fo_doc,FoDatatype * color,FoPdfOneBorderCoords * coords)336 fo_pdf_draw_border_dashed (FoDoc *fo_doc,
337 			   FoDatatype *color,
338 			   FoPdfOneBorderCoords *coords)
339 {
340 /*  fo_doc_set_line_cap (fo_doc,
341     FO_DOC_LINE_CAP_BUTT);*/ /* butt end caps */
342 
343   fo_pdf_clip_to_coords (fo_doc, coords);
344 
345   fo_doc_set_stroke_color (fo_doc,
346 			   color);
347 
348   if (coords->x1 == coords->x2)
349     { /* vertical */
350       fo_doc_set_dash (fo_doc,
351 		       ABS (coords->x1delta) * 3,
352 		       ABS (coords->x1delta) * 3);
353       fo_doc_set_line_width (fo_doc,
354 			     ABS (coords->x1delta));
355 
356       fo_doc_move_to (fo_doc,
357 		      coords->x1 + coords->x1delta / 2,
358 		      coords->y1);
359       fo_doc_line_to (fo_doc,
360 		      coords->x2 + coords->x2delta / 2,
361 		      coords->y2);
362     }
363   else
364     { /* horizontal */
365       fo_doc_set_dash (fo_doc,
366 		       ABS (coords->y1delta) * 3,
367 		       ABS (coords->y1delta) * 3);
368       fo_doc_set_line_width (fo_doc,
369 			     ABS (coords->y1delta));
370 
371       fo_doc_move_to (fo_doc,
372 		      coords->x1,
373 		      coords->y1 + coords->y1delta / 2);
374       fo_doc_line_to (fo_doc,
375 		      coords->x2,
376 		      coords->y2 + coords->y2delta / 2);
377     }
378   fo_doc_stroke (fo_doc);
379 }
380 
381 /**
382  * fo_pdf_draw_border_groove:
383  * @fo_doc: #FoDoc
384  * @color:  Border color
385  * @coords: Coordinates of one border of an area
386  *
387  * Draw a grooved border with colors based on @color and coordinates @coords.
388  **/
389 static void
fo_pdf_draw_border_groove(FoDoc * fo_doc,FoDatatype * color,FoPdfOneBorderCoords * coords)390 fo_pdf_draw_border_groove (FoDoc *fo_doc,
391 			   FoDatatype *color,
392 			   FoPdfOneBorderCoords *coords)
393 {
394   fo_doc_set_dash (fo_doc, 0.0, 0.0);
395 
396   fo_pdf_clip_to_coords (fo_doc, coords);
397 
398   if (coords->x1 == coords->x2)
399     { /* vertical */
400       if (coords->x1delta >= 0)
401 	{ /* left */
402 	  fo_pdf_draw_border_two_tone_vertical (fo_doc,
403 						color,
404 						fo_color_get_color_one_quarter (color),
405 						coords);
406 	}
407       else
408 	{ /* right */
409 	  fo_pdf_draw_border_two_tone_vertical (fo_doc,
410 						fo_color_get_color_one_quarter (color),
411 						color,
412 						coords);
413 	}
414     }
415   else
416     { /* horizontal */
417       if (coords->y1delta >= 0)
418 	{ /* bottom */
419 	  fo_pdf_draw_border_two_tone_horizontal (fo_doc,
420 						  fo_color_get_color_one_quarter (color),
421 						  color,
422 						  coords);
423 	}
424       else
425 	{ /* top */
426 	  /* 3/4 color */
427 	  fo_pdf_draw_border_two_tone_horizontal (fo_doc,
428 						  color,
429 						  fo_color_get_color_one_quarter (color),
430 						  coords);
431 	}
432     }
433 }
434 
435 /**
436  * fo_pdf_draw_border_ridge:
437  * @fo_doc: #FoDoc
438  * @color:  Border color
439  * @coords: Coordinates of one border of an area
440  *
441  * Draw a ridged border with colors based on @color and coordinates @coords.
442  **/
443 static void
fo_pdf_draw_border_ridge(FoDoc * fo_doc,FoDatatype * color,FoPdfOneBorderCoords * coords)444 fo_pdf_draw_border_ridge (FoDoc *fo_doc,
445 			  FoDatatype *color,
446 			  FoPdfOneBorderCoords *coords)
447 {
448   fo_doc_set_dash (fo_doc, 0.0, 0.0);
449 
450   fo_pdf_clip_to_coords (fo_doc, coords);
451 
452   if (coords->x1 == coords->x2)
453     { /* vertical */
454       if (coords->x1delta >= 0)
455 	{ /* left */
456 	  fo_pdf_draw_border_two_tone_vertical (fo_doc,
457 					    fo_color_get_color_one_half (color),
458 					    fo_color_get_color_three_quarter (color),
459 					    coords);
460 	}
461       else
462 	{ /* right */
463 	  fo_pdf_draw_border_two_tone_vertical (fo_doc,
464 					     fo_color_get_color_three_quarter (color),
465 					     fo_color_get_color_one_half (color),
466 					     coords);
467 	}
468     }
469   else
470     { /* horizontal */
471       if (coords->y1delta >= 0)
472 	{ /* bottom */
473 	  fo_pdf_draw_border_two_tone_horizontal (fo_doc,
474 					      fo_color_get_color_one_half (color),
475 					      fo_color_get_color_three_quarter (color),
476 					      coords);
477 	}
478       else
479 	{ /* top */
480 	  /* 3/4 color */
481 	  fo_pdf_draw_border_two_tone_horizontal (fo_doc,
482 					   fo_color_get_color_three_quarter (color),
483 					   fo_color_get_color_one_half (color),
484 					   coords);
485 	}
486     }
487 }
488 
489 /**
490  * fo_pdf_draw_border_inset:
491  * @fo_doc: #FoDoc
492  * @color:  Border color
493  * @coords: Coordinates of one border of an area
494  *
495  * Draw an inset border with colors based on @color and coordinates @coords.
496  **/
497 static void
fo_pdf_draw_border_inset(FoDoc * fo_doc,FoDatatype * color,FoPdfOneBorderCoords * coords)498 fo_pdf_draw_border_inset (FoDoc *fo_doc,
499 			  FoDatatype *color,
500 			  FoPdfOneBorderCoords *coords)
501 {
502   fo_doc_set_dash (fo_doc, 0.0, 0.0);
503 
504   fo_pdf_clip_to_coords (fo_doc, coords);
505 
506   if (coords->x1 == coords->x2)
507     { /* vertical */
508       if (coords->x1delta >= 0)
509 	{ /* left */
510 	  fo_pdf_draw_border_two_tone_vertical (fo_doc,
511 					    fo_color_get_color_one_half (color),
512 					    fo_color_get_color_one_quarter (color),
513 					    coords);
514 	}
515       else
516 	{ /* right */
517 	  fo_pdf_draw_border_two_tone_vertical (fo_doc,
518 					     fo_color_get_color_three_quarter (color),
519 					     color,
520 					     coords);
521 	}
522     }
523   else
524     { /* horizontal */
525       if (coords->y1delta >= 0)
526 	{ /* bottom */
527 	  fo_pdf_draw_border_two_tone_horizontal (fo_doc,
528 					      fo_color_get_color_three_quarter (color),
529 					      color,
530 					      coords);
531 	}
532       else
533 	{ /* top */
534 	  /* 1/4 color */
535 	  fo_pdf_draw_border_two_tone_horizontal (fo_doc,
536 					      fo_color_get_color_one_half (color),
537 					      fo_color_get_color_one_quarter (color),
538 					      coords);
539 	}
540     }
541 }
542 
543 /**
544  * fo_pdf_draw_border_outset:
545  * @fo_doc: #FoDoc
546  * @color:  Border color
547  * @coords: Coordinates of one border of an area
548  *
549  * Draw an outset border with colors based on @color and coordinates @coords.
550  **/
551 static void
fo_pdf_draw_border_outset(FoDoc * fo_doc,FoDatatype * color,FoPdfOneBorderCoords * coords)552 fo_pdf_draw_border_outset (FoDoc *fo_doc,
553 			   FoDatatype *color,
554 			   FoPdfOneBorderCoords *coords)
555 {
556   fo_doc_set_dash (fo_doc, 0.0, 0.0);
557 
558   fo_pdf_clip_to_coords (fo_doc, coords);
559 
560   if (coords->x1 == coords->x2)
561     { /* vertical */
562       if (coords->x1delta >= 0)
563 	{ /* left */
564 	  fo_pdf_draw_border_two_tone_vertical (fo_doc,
565 					    color,
566 					    fo_color_get_color_three_quarter (color),
567 					    coords);
568 	}
569       else
570 	{ /* right */
571 	  fo_pdf_draw_border_two_tone_vertical (fo_doc,
572 					     fo_color_get_color_one_quarter (color),
573 					     fo_color_get_color_one_half (color),
574 					     coords);
575 	}
576     }
577   else
578     { /* horizontal */
579       if (coords->y1delta >= 0)
580 	{ /* bottom */
581 	  fo_pdf_draw_border_two_tone_horizontal (fo_doc,
582 					      fo_color_get_color_one_quarter (color),
583 					      fo_color_get_color_one_half (color),
584 					      coords);
585 	}
586       else
587 	{ /* top */
588 	  /* 3/4 color */
589 	  fo_pdf_draw_border_two_tone_horizontal (fo_doc,
590 						  color,
591 						  fo_color_get_color_three_quarter (color),
592 						  coords);
593 	}
594     }
595 }
596 
597 /**
598  * fo_pdf_draw_one_border:
599  * @fo_doc:           #FoDoc
600  * @border_style:     Border style
601  * @x1:               X-coordinate of one corner
602  * @y1:               Y-coordinate of one corner
603  * @x2:               X-coordinate of the opposite corner
604  * @y2:               Y-coordinate of the opposite corner
605  * @x1delta:          Relative x-offset of interior corner of border
606                         closest to (x1, y1)
607  * @y1delta:          Relative y-offset of interior corner of border
608                         closest to (x1, y1)
609  * @x2delta:          Relative x-offset of interior corner of border
610                         closest to (x2, y2)
611  * @y2delta:          Relative y-offset of interior corner of border
612                         closest to (x2, y2)
613  *
614  * Draw one border by outputting PDF statements to PDF document.
615  *
616  * Borders are mitred, i.e., the angle between the outer corner and
617  * the inner corner at the end of one border depends on both the width
618  * of the border and the width of the adjacent border that is at right
619  * angles to the current border.
620  **/
621 static void
fo_pdf_draw_one_border(FoDoc * fo_doc,FoDatatype * color,FoEnumEnum border_style,FoPdfOneBorderCoords * coords)622 fo_pdf_draw_one_border (FoDoc *fo_doc,
623 			FoDatatype *color,
624 			FoEnumEnum border_style,
625 			FoPdfOneBorderCoords *coords)
626 {
627   fo_doc_save (fo_doc);
628 
629 #if defined(LIBFO_DEBUG) && 1
630   g_message ("draw_one_border:: style: %d; x1: %f; y1; %f; x2: %f; y2: %f",
631 	     border_style, x1, y1, x2, y2);
632   g_message ("                  x1delta: %f; y1delta: %f; x2delta: %f; y2delta: %f",
633 	     x1delta, y1delta, x2delta, y2delta);
634 #endif
635 
636   switch (border_style) {
637   case FO_ENUM_ENUM_SOLID:
638     fo_pdf_draw_border_solid (fo_doc,
639 			      color,
640 			      coords);
641     break;
642   case FO_ENUM_ENUM_DOUBLE:
643     fo_pdf_draw_border_double (fo_doc,
644 			       color,
645 			       coords);
646     break;
647   case FO_ENUM_ENUM_DOTTED:
648     fo_pdf_draw_border_dotted (fo_doc,
649 			       color,
650 			       coords);
651     break;
652   case FO_ENUM_ENUM_DASHED:
653     fo_pdf_draw_border_dashed (fo_doc,
654 			       color,
655 			       coords);
656     break;
657   case FO_ENUM_ENUM_GROOVE:
658     fo_pdf_draw_border_groove (fo_doc,
659 			       color,
660 			       coords);
661     break;
662   case FO_ENUM_ENUM_RIDGE:
663     fo_pdf_draw_border_ridge (fo_doc,
664 			       color,
665 			       coords);
666     break;
667   case FO_ENUM_ENUM_INSET:
668     fo_pdf_draw_border_inset (fo_doc,
669 			      color,
670 			      coords);
671     break;
672   case FO_ENUM_ENUM_OUTSET:
673     fo_pdf_draw_border_outset (fo_doc,
674 			       color,
675 			       coords);
676     break;
677   default:
678     g_error ("Unexpected enumeration.");
679   }
680   fo_doc_restore (fo_doc);
681 }
682 
683 /**
684  * fo_pdf_draw_borders:
685  * @fo_doc:    #FoDoc document
686  * @area_node: #FoArea node
687  *
688  * Draw the borders appropriate to @area_node.
689  *
690  * FIXME: Does not work correctly for #FoAreaSpanningTableCell.
691  **/
692 static void
fo_pdf_draw_borders(FoDoc * fo_doc,FoArea * area_node,gdouble width,gdouble height)693 fo_pdf_draw_borders (FoDoc  *fo_doc,
694 		     FoArea *area_node,
695 		     gdouble width,
696 		     gdouble height)
697 {
698   GValue value = { 0, {{0}, {0}} };
699   FoFo *fo = fo_area_get_generated_by (area_node);
700   FoDatatype *color;
701   FoEnumEnum border_style;
702   gdouble x = fo_area_area_get_x (area_node);
703   gdouble y = fo_area_area_get_y (area_node);
704   gdouble border_before =
705     fo_area_area_get_border_before (area_node);
706   gdouble border_after =
707     fo_area_area_get_border_after (area_node);
708   gdouble border_start =
709     fo_area_area_get_border_start (area_node);
710   gdouble border_end =
711     fo_area_area_get_border_end (area_node);
712 
713   g_value_init (&value, G_TYPE_OBJECT);
714 
715   /* before == top */
716   if (border_before != 0.0)
717     {
718       border_style =
719 	fo_enum_get_value (fo_property_get_value (fo_cbpbp_fo_get_border_before_style (fo)));
720 
721       if ((border_style != FO_ENUM_ENUM_NONE) &&
722 	  (border_style != FO_ENUM_ENUM_HIDDEN))
723 	{
724 	  FoPdfOneBorderCoords coords = {x,
725 					 y,
726 					 x + width,
727 					 y,
728 					 border_start,
729 					 -border_before,
730 					 -border_end,
731 					 -border_before};
732 
733 	  color =
734 	    fo_property_get_value (fo_cbpbp_fo_get_border_before_color (fo));
735 
736 	  fo_pdf_draw_one_border (fo_doc,
737 				  color,
738 				  border_style,
739 				  &coords);
740 	}
741     }
742   /* start == left */
743   if (border_start != 0.0)
744     {
745       border_style =
746 	fo_enum_get_value (fo_property_get_value (fo_cbpbp_fo_get_border_start_style (fo)));
747 
748       if ((border_style != FO_ENUM_ENUM_NONE) &&
749 	  (border_style != FO_ENUM_ENUM_HIDDEN))
750 	{
751 	  FoPdfOneBorderCoords coords = {x,
752 					 y,
753 					 x,
754 					 y - height,
755 					 border_start,
756 					 -border_before,
757 					 border_start,
758 					 border_after};
759 
760 	  color =
761 	    fo_property_get_value (fo_cbpbp_fo_get_border_start_color (fo));
762 
763 	  fo_pdf_draw_one_border (fo_doc,
764 				  color,
765 				  border_style,
766 				  &coords);
767 	}
768     }
769   /* end == right */
770   if (border_end != 0.0)
771     {
772       border_style =
773 	fo_enum_get_value (fo_property_get_value (fo_cbpbp_fo_get_border_end_style (fo)));
774 
775       if ((border_style != FO_ENUM_ENUM_NONE) &&
776 	  (border_style != FO_ENUM_ENUM_HIDDEN))
777 	{
778 	  FoPdfOneBorderCoords coords = {x + width,
779 					 y,
780 					 x + width,
781 					 y - height,
782 					 -border_end,
783 					 -border_before,
784 					 -border_end,
785 					 border_after};
786 
787 	  color =
788 	    fo_property_get_value (fo_cbpbp_fo_get_border_end_color (fo));
789 
790 	  fo_pdf_draw_one_border (fo_doc,
791 				  color,
792 				  border_style,
793 				  &coords);
794 	}
795     }
796   /* after == bottom */
797   if (border_after != 0.0)
798     {
799       border_style =
800 	fo_enum_get_value (fo_property_get_value (fo_cbpbp_fo_get_border_after_style (fo)));
801 
802       if ((border_style != FO_ENUM_ENUM_NONE) &&
803 	  (border_style != FO_ENUM_ENUM_HIDDEN))
804 	{
805 	  FoPdfOneBorderCoords coords = {x,
806 					 y - height,
807 					 x + width,
808 					 y - height,
809 					 border_start,
810 					 border_after,
811 					 -border_end,
812 					 border_after};
813 
814 	  color =
815 	    fo_property_get_value (fo_cbpbp_fo_get_border_after_color (fo));
816 
817 	  fo_pdf_draw_one_border (fo_doc,
818 				  color,
819 				  border_style,
820 				  &coords);
821 	}
822     }
823 }
824 
825 /**
826  * fo_area_tree_to_pdf:
827  * @area_node: #FoArea node to be output to PDF file
828  * @data:      Pointer to #FoAreaToPDFData with additional data
829  *
830  * Add @area_node and its descendants to the PDF document.  The PDF
831  * document pointer and other required data is in @data.
832  *
833  * This conforms to FoAreaForeachFunc type so can use
834  * fo_area_children_foreach() on any children of @area_node.
835  **/
836 void
fo_area_tree_to_pdf(FoArea * area_node,gpointer data)837 fo_area_tree_to_pdf (FoArea  *area_node,
838 		     gpointer data)
839 {
840   FoAreaToPDFData *fo_area_to_pdf_data = (FoAreaToPDFData *) data;
841   FoDoc *fo_doc;
842   FoFo *fo;
843   FoProperty *prop_background_color;
844   FoDatatype *background_color;
845 
846   GValue value = { 0, {{0}, {0}} };
847 
848   g_value_init (&value, G_TYPE_OBJECT);
849 
850   g_return_if_fail (area_node != NULL);
851   g_return_if_fail (FO_IS_AREA (area_node));
852 
853   fo_doc = fo_area_to_pdf_data->fo_doc;
854 
855   fo = fo_area_get_generated_by (area_node);
856 
857   if (FO_IS_AREA_PAGE (area_node))
858     {
859       fo_doc_begin_page (fo_doc,
860 			 fo_area_page_get_page_width (area_node),
861 			 fo_area_page_get_page_height (area_node),
862 			 NULL);
863 
864       fo_area_children_foreach (area_node,
865 				G_TRAVERSE_ALL,
866 				&fo_area_tree_to_pdf,
867 				(gpointer) fo_area_to_pdf_data);
868 
869       fo_doc_end_page (fo_doc);
870     }
871   else if (FO_IS_AREA_LAYOUT (area_node))
872     {
873       FoPropertyColor *prop_color;
874       FoPropertyFontSize *prop_font_size;
875       FoDatatype *color;
876       FoDatatype *length;
877       gdouble x = fo_area_area_get_x (area_node);
878       gdouble y = fo_area_area_get_y (area_node);
879       gdouble width = fo_area_area_get_width (area_node);
880       gdouble height = fo_area_area_get_height (area_node);
881       gdouble border_before =
882 	fo_area_area_get_border_before (area_node);
883       gdouble border_start =
884 	fo_area_area_get_border_start (area_node);
885       gdouble padding_before =
886 	fo_area_area_get_padding_before (area_node);
887       gdouble padding_start =
888 	fo_area_area_get_padding_start (area_node);
889 
890       fo_doc_save (fo_doc);
891 
892       /* font-size */
893       g_object_get_property (G_OBJECT (fo),
894 			     "font-size",
895 			     &value);
896 
897       prop_font_size = g_value_get_object (&value);
898 
899       g_object_get_property (G_OBJECT (prop_font_size),
900 			     "value",
901 			     &value);
902 
903       length = g_value_get_object (&value);
904 
905       /* background-color */
906       g_object_get_property (G_OBJECT (fo),
907 			     "background-color",
908 			     &value);
909 
910       prop_background_color = g_value_get_object (&value);
911 
912       g_object_get_property (G_OBJECT (prop_background_color),
913 			     "value",
914 			     &value);
915 
916       background_color = g_value_get_object (&value);
917 
918       fo_pdf_draw_background (fo_doc,
919 			      x,
920 			      y,
921 			      width,
922 			      height,
923 			      background_color);
924 
925       /* color */
926       g_object_get_property (G_OBJECT (fo),
927 			     "color",
928 			     &value);
929 
930       prop_color = g_value_get_object (&value);
931 
932       g_object_get_property (G_OBJECT (prop_color),
933 			     "value",
934 			     &value);
935 
936       color = g_value_get_object (&value);
937 
938       fo_doc_set_fill_color (fo_doc,
939 			     color);
940 
941 #if defined(LIBFO_DEBUG) && 0
942       fo_object_debug_dump (area_node, 0);
943 #endif
944 
945       fo_doc_render_layout_lines (fo_doc,
946 				  area_node,
947 				  x + border_start + padding_start,
948 				  y - border_before - padding_before);
949 
950       /* borders */
951       fo_pdf_draw_borders (fo_doc, area_node, width, height);
952 
953       fo_doc_restore (fo_doc);
954     }
955   else if (FO_IS_AREA_NORMAL (area_node))
956     {
957       gdouble width = fo_area_area_get_width (area_node);
958       gdouble height = fo_area_area_get_height (area_node);
959 
960       fo_pdf_draw_borders (fo_doc, area_node, width, height);
961 
962       fo_doc_translate (fo_doc,
963 			fo_area_area_get_x (area_node),
964 			fo_area_area_get_y (area_node));
965 
966       fo_area_children_foreach (area_node,
967 				G_TRAVERSE_ALL,
968 				&fo_area_tree_to_pdf,
969 				fo_area_to_pdf_data);
970       fo_doc_translate (fo_doc,
971 			- fo_area_area_get_x (area_node),
972 			- fo_area_area_get_y (area_node));
973     }
974   else if (FO_IS_AREA_VIEWPORT_REFERENCE (area_node))
975     {
976       FoProperty *prop_overflow;
977       FoEnumEnum overflow;
978       gdouble x = fo_area_area_get_x (area_node);
979       gdouble y = fo_area_area_get_y (area_node);
980       /* FIXME: Why is this available width and height only? */
981       gdouble width = fo_area_get_available_width (area_node);
982       gdouble height = fo_area_get_available_height (area_node);
983 
984       /* background-color */
985       background_color = fo_property_get_value (fo_cbpbp_fo_get_background_color (fo));
986 
987       fo_pdf_draw_background (fo_doc,
988 			      x,
989 			      y,
990 			      width,
991 			      height,
992 			      background_color);
993 
994       /* borders */
995       fo_pdf_draw_borders (fo_doc, area_node, width, height);
996 
997       fo_doc_save (fo_doc);
998       fo_doc_translate (fo_doc,
999 			fo_area_area_get_x (area_node),
1000 			fo_area_area_get_y (area_node));
1001 
1002       /* overflow */
1003       g_object_get_property (G_OBJECT (fo_fo_get_area_fo (fo)),
1004 			     "overflow",
1005 			     &value);
1006       prop_overflow = g_value_get_object (&value);
1007       overflow =
1008 	fo_enum_get_value (fo_property_get_value (prop_overflow));
1009       if ((overflow == FO_ENUM_ENUM_HIDDEN) ||
1010 	  (overflow == FO_ENUM_ENUM_SCROLL))
1011 	{
1012 	  fo_doc_move_to (fo_doc,
1013 			  0,
1014 			  0);
1015 	  fo_doc_line_to (fo_doc,
1016 			  0,
1017 			  -height);
1018 	  fo_doc_line_to (fo_doc,
1019 			  width,
1020 			  -height);
1021 	  fo_doc_line_to (fo_doc,
1022 			  width,
1023 			  0);
1024 	  fo_doc_clip (fo_doc);
1025 	}
1026 
1027       fo_area_children_foreach (area_node,
1028 				G_TRAVERSE_ALL,
1029 				&fo_area_tree_to_pdf,
1030 				fo_area_to_pdf_data);
1031 
1032       fo_doc_restore (fo_doc);
1033     }
1034   else if (FO_IS_AREA_SPANNING_TABLE_CELL (area_node))
1035     {
1036       gdouble x = fo_area_area_get_x (area_node);
1037       gdouble y = fo_area_area_get_y (area_node);
1038       gdouble width = fo_area_area_get_width (area_node);
1039       gdouble height = fo_area_spanning_table_cell_get_real_available_height (area_node);
1040 
1041       fo_doc_save (fo_doc);
1042 
1043       /* background-color */
1044       g_object_get_property (G_OBJECT (fo),
1045 			     "background-color",
1046 			     &value);
1047 
1048       prop_background_color = g_value_get_object (&value);
1049 
1050       g_object_get_property (G_OBJECT (prop_background_color),
1051 			     "value",
1052 			     &value);
1053 
1054       background_color = g_value_get_object (&value);
1055 
1056       fo_pdf_draw_background (fo_doc,
1057 			      x,
1058 			      y,
1059 			      width,
1060 			      height,
1061 			      background_color);
1062 
1063       /* borders */
1064       fo_pdf_draw_borders (fo_doc, area_node, width, height);
1065 
1066       fo_doc_translate (fo_doc,
1067 			fo_area_area_get_x (area_node),
1068 			fo_area_area_get_y (area_node));
1069 
1070       fo_area_children_foreach (area_node,
1071 				G_TRAVERSE_ALL,
1072 				&fo_area_tree_to_pdf,
1073 				fo_area_to_pdf_data);
1074 
1075       fo_doc_restore (fo_doc);
1076     }
1077   else if (FO_IS_AREA_TABLE_CONTINUATION (area_node))
1078     {
1079       FoArea *table_header = FO_AREA_TABLE_CONTINUATION (area_node)->table_header;
1080       gdouble x = fo_area_area_get_x (area_node);
1081       gdouble y = fo_area_area_get_y (area_node);
1082       gdouble width = fo_area_area_get_width (area_node);
1083       gdouble height = fo_area_area_get_height (area_node);
1084 
1085       if (table_header != NULL)
1086 	{
1087 	  fo_doc_save (fo_doc);
1088 	  fo_doc_translate (fo_doc,
1089 			    fo_area_area_get_x (area_node),
1090 			    fo_area_area_get_y (area_node));
1091 
1092 	  fo_area_tree_to_pdf (table_header,
1093 			       fo_area_to_pdf_data);
1094 
1095 	  fo_doc_restore (fo_doc);
1096 	}
1097 
1098       fo_doc_save (fo_doc);
1099 
1100       /* background-color */
1101       g_object_get_property (G_OBJECT (fo),
1102 			     "background-color",
1103 			     &value);
1104 
1105       prop_background_color = g_value_get_object (&value);
1106 
1107       g_object_get_property (G_OBJECT (prop_background_color),
1108 			     "value",
1109 			     &value);
1110 
1111       background_color = g_value_get_object (&value);
1112 
1113       fo_pdf_draw_background (fo_doc,
1114 			      x,
1115 			      y -
1116 			      (table_header ? fo_area_area_get_height (table_header) : 0.0),
1117 			      width,
1118 			      height,
1119 			      background_color);
1120 
1121       /* borders */
1122       fo_pdf_draw_borders (fo_doc, area_node, width, height);
1123 
1124       fo_doc_translate (fo_doc,
1125 			fo_area_area_get_x (area_node),
1126 			fo_area_area_get_y (area_node) -
1127 			(table_header ? fo_area_area_get_height (table_header) : 0.0) -
1128 			(table_header ? fo_area_area_get_height (table_header) : 0.0));
1129 
1130       fo_area_children_foreach (area_node,
1131 				G_TRAVERSE_ALL,
1132 				&fo_area_tree_to_pdf,
1133 				fo_area_to_pdf_data);
1134 
1135       fo_doc_restore (fo_doc);
1136     }
1137   else if (FO_IS_AREA_REFERENCE (area_node))
1138     {
1139       gdouble x = fo_area_area_get_x (area_node);
1140       gdouble y = fo_area_area_get_y (area_node);
1141       gdouble width = fo_area_area_get_width (area_node);
1142       gdouble height = fo_area_area_get_height (area_node);
1143 
1144       fo_doc_save (fo_doc);
1145 
1146       /* background-color */
1147       g_object_get_property (G_OBJECT (fo),
1148 			     "background-color",
1149 			     &value);
1150 
1151       prop_background_color = g_value_get_object (&value);
1152 
1153       g_object_get_property (G_OBJECT (prop_background_color),
1154 			     "value",
1155 			     &value);
1156 
1157       background_color = g_value_get_object (&value);
1158 
1159       fo_pdf_draw_background (fo_doc,
1160 			      x,
1161 			      y,
1162 			      width,
1163 			      height,
1164 			      background_color);
1165 
1166       /* borders */
1167       fo_pdf_draw_borders (fo_doc, area_node, width, height);
1168 
1169       fo_doc_translate (fo_doc,
1170 			fo_area_area_get_x (area_node),
1171 			fo_area_area_get_y (area_node));
1172 
1173       fo_area_children_foreach (area_node,
1174 				G_TRAVERSE_ALL,
1175 				&fo_area_tree_to_pdf,
1176 				fo_area_to_pdf_data);
1177 
1178       fo_doc_restore (fo_doc);
1179     }
1180   else if (FO_IS_AREA_AREA (area_node))
1181     {
1182       gdouble width = fo_area_area_get_width (area_node);
1183       gdouble height = fo_area_area_get_height (area_node);
1184 
1185       /* borders */
1186       fo_pdf_draw_borders (fo_doc, area_node, width, height);
1187 
1188       fo_doc_translate (fo_doc,
1189 			fo_area_area_get_x (area_node),
1190 			fo_area_area_get_y (area_node));
1191 
1192       fo_area_children_foreach (area_node,
1193 				G_TRAVERSE_ALL,
1194 				&fo_area_tree_to_pdf,
1195 				fo_area_to_pdf_data);
1196 
1197       fo_doc_translate (fo_doc,
1198 			- fo_area_area_get_x (area_node),
1199 			- fo_area_area_get_y (area_node));
1200     }
1201   else
1202     {
1203       fo_area_children_foreach (area_node,
1204 				G_TRAVERSE_ALL,
1205 				&fo_area_tree_to_pdf,
1206 				fo_area_to_pdf_data);
1207     }
1208 }
1209 
1210